CVE-2024-45216 Authentication bypass in Apache Solr
Apache Solr là một nền tảng tìm kiếm mã nguồn mở dựa trên Apache Lucene, cung cấp các công cụ mạnh mẽ để xây dựng các ứng dụng tìm kiếm và phân tích dữ liệu. Được thiết kế để xử lý khối lượng dữ liệu lớn với tốc độ cao, Solr được sử dụng rộng rãi trong các hệ thống tìm kiếm, quản lý nội dung, phân tích và các ứng dụng yêu cầu xử lý ngôn ngữ tự nhiên.
Tổng quan
Các phiên bản Solr từ 5.3.0 tới 8.11.4 hoặc 9.7.0 trở xuống sử dụng PKIAuthenticationPlugin (được kích hoạt mặc định khi bật xác thực) có lỗ hổng cho phép bỏ qua xác thực bằng cách thêm một đoạn giả mạo vào cuối đường dẫn URL của bất kỳ API nào trong Solr.
Setup
Solr cấu hình xác thực thông qua file security.json.
{
"authentication": {
"class": "solr.BasicAuthPlugin",
"credentials": {
"solr": "IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c="
},
"blockUnknown": false,
"": {
"v": 0
}
},
"authorization": {
"class": "solr.RuleBasedAuthorizationPlugin",
"permissions": [
{
"name": "security-edit",
"role": "admin"
}
],
"user-role": {
"solr": "admin"
}
}
}
Bật plugin BasicAuthPlugin và RuleBasedAuthoricationPlugin cho authen và author.
Tạo một user với username là “solr” và password là “SolrRocks“.
Tạo một role “admin” có quyền “security-edit” và gán cho user “solr”.
Vì lỗ hổng này nằm ở plugin PKIAuthentication (chỉ khả dụng ở chế độ SolrCloud) nên mình sẽ dựng bằng docker-compose.yaml cho tiện và cấu hình auth bằng file security.json ở trên.
version: '3.7'
services:
solr1:
image: solr:9.6.0
container_name: solr1e
ports:
- "8983:8983"
- "5006:5006"
environment:
- ZK_HOST=zoo1:2181,zoo2:2181,zoo3:2181
- SOLR_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5006
volumes:
- [your-local-path]security.json:/var/solr/data/security.json
networks:
- solr
depends_on:
- zoo1
- zoo2
- zoo3
solr2:
image: solr:9.6.0
container_name: solr2
ports:
- "8982:8983"
environment:
- ZK_HOST=zoo1:2181,zoo2:2181,zoo3:2181
networks:
- solr
depends_on:
- zoo1
- zoo2
- zoo3
solr3:
image: solr:9.6.0
container_name: solr3
ports:
- "8981:8983"
environment:
- ZK_HOST=zoo1:2181,zoo2:2181,zoo3:2181
networks:
- solr
depends_on:
- zoo1
- zoo2
- zoo3
zoo1:
image: zookeeper:3.8
container_name: zoo1
restart: always
hostname: zoo1
ports:
- 2181:2181
- 7001:7000
environment:
ZOO_MY_ID: 1
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok
ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true"
networks:
- solr
zoo2:
image: zookeeper:3.8
container_name: zoo2
restart: always
hostname: zoo2
ports:
- 2182:2181
- 7002:7000
environment:
ZOO_MY_ID: 2
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok
ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true"
networks:
- solr
zoo3:
image: zookeeper:3.8
container_name: zoo3
restart: always
hostname: zoo3
ports:
- 2183:2181
- 7003:7000
environment:
ZOO_MY_ID: 3
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181
ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok
ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true"
networks:
- solr
networks:
solr:
Chạy lệnh dưới trên solr để add security.json vào Zookeeper
solr zk cp /var/solr/data/security.json zk:/security.json -z zoo1:2181,zoo2:2181,zoo3:2181
Sau đó đăng nhập vào Solr bằng tài khoản ở trên. Bật option “Block anonymous request”
Phân tích
Ở đây mình sử dụng version lỗi là 9.6.0 diff với bản 9.7.0.
Trong mô tả của NVD thì lỗ hổng nằm ở class PKIAuthenticationPlugin nên mình sẽ diff hai file này trước.
Nói qua một chút về PKIAuthenticationPlugin
Tại method doAuthenticate ta thấy được tại bản vá đã bị xóa đi đoạn kiểm tra uri từ request.
method này kiểm tra uri request nhận được có kết thúc bằng /admin/info/key không, nếu bằng thì sẽ forward request tới filter chain tiếp theo rồi cuối cùng return true, bỏ qua hoàn toàn các đoạn xác thực tiếp theo bên dưới.
Đặt debug ở dòng 145 của file PKIAuthenticationPlugin để xem chi tiết hơn code flow đoạn này.
Send request như trên lúc này ta thấy không trigger được breakpoint thì nguyên nhân của điều này là tại method SolrDispatchFilter.authenticateRequest() có kiểm tra requestPath tức đoạn uri sau /solr nếu bằng /admin/info/key sẽ return ngay khiến flow không tới được PKIAuthenticationPlugin.doAuthenticate().
Đây cũng chính là unauth endpoint để trả về public key của một node mà mình đã nói ở trên.
Send lại một request khác
lúc này đã vào được method doAuthenticate() và bypass được đoạn check public key header ở dưới.
Như vậy ta có thể vượt qua method doAuthenticate() này mà không cần có một header SolrAuth hợp lệ bằng cách tạo một request có uri kết thúc bằng /admin/info/key. Có vẻ đây chính là “fake ending” được nhắc tới trong mô tả của NVD.
Giờ ta đã biết được cách có thể bypass được đoạn xác thực request rồi nhưng làm sao để ta có thể truy cập vào một api bất kỳ nào khác ngoài cái /admin/info/key. Trong mô tả lỗi nói rằng trước khi thực hiện API routing thì đoạn “fake ending” sẽ bị loại bỏ. Chắc chắn đằng sau có một hàm có thể dùng để xóa đi đoạn “fake ending” này. Tiếp tục F7+F8
Sau khi qua bước check authen ở trên thì tại line 262, SolrDispatchFilter tiếp tục gọi tới method HttpSolrCall.call() và HttpSolrCall.init().
có thể thấy rõ rằng biến path tức request path của ta được xóa đi từ kí tự “:” đầu tiên. Sau khi kiểm tra lại file diff thì ở bản vá cũng đã không còn đoạn substring này.
Send lại request dưới (có “:”)
đoạn sau “:” đã bị xóa
Có vẻ như đây chính là mảnh ghép cuối của lỗ hổng này. Bây giờ ta có thể access vào bất kì API nào trên solr mà không cần phải xác thực.
Subscribe to my newsletter
Read articles from gumgum directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by