CVE-2019-0193 Apache Solr远程命令执行漏洞分析

2019-08-13 约 109 字 预计阅读 1 分钟

声明:本文 【CVE-2019-0193 Apache Solr远程命令执行漏洞分析】 由作者 tornado 于 2019-08-13 07:31:00 首发 先知社区 曾经 浏览数 33 次

感谢 tornado 的辛苦付出!

概述

近日,Apache Solr官方发布Apache Solr存在一个远程代码执行漏洞(CVE-2019-0193),攻击者可利用dataConfig参数构造恶意请求,导致执行任意代码,下面简单分析一下这个漏洞。

官方通告:https://issues.apache.org/jira/browse/SOLR-13669

前置概念

Dataimport

Solr支持从Dataimport导入自定义数据,dataconfig需要满足一定语法,参考

其中ScriptTransformer可以编写自定义脚本,支持常见的脚本语言如Javascript、JRuby、Jython、Groovy和BeanShell

ScriptTransformer容许用脚本语言如Javascript、JRuby、Jython、Groovy和BeanShell转换,函数应当以行(类型为Map\<String,Object\>)为参数,可以修改字段。脚本应当写在数据仓库配置文件顶级的script元素内,而转换器属性值为script:函数名。

使用示例:

<dataconfig>
  <script><![CDATA[
    function f2c(row) {
      var tempf, tempc;
      tempf = row.get('temp_f');
      if (tempf != null) {
        tempc = (tempf - 32.0)*5.0/9.0;
        row.put('temp_c', temp_c);
      }
      return row;
    }
    ]]>
  </script>
  <document>

    <entity name="e1" pk="id" transformer="script:f2c" query="select * from X">
    </entity>
  </document>
</dataConfig>

Nashorn引擎

在Solr中解析js脚本使用的是Nashorn引擎,可以通过Java.typeAPI在JavaScript中引用,就像Java的import一样,例如:

var MyJavaClass = Java.type('my.package.MyJavaClass');
var result = MyJavaClass.sayHello("Nashorn");
print(result);

漏洞分析

Solr在处理dataimport请求时,首先进入dataimport/DataImportHandler的handleRequestBody方法,当前请求的command为full-import,因此通过maybeReloadConfiguration重新加载配置

在maybeReloadConfiguration中通过params.getDataConfig()判断了post的数据(dataConfig)是否为空,如果不是则通过loadDataConfig来加载

随后在loadDataConfig中通过readFromXml方法解析提交的配置数据中的各个标签,比如document,script,function,dataSource等,传入的script自定义脚本即在此处被存入script变量,递归解析完所有标签构建出DIHConfiguration对象并返回。
获取到配置信息后通过this.importer.runCmd()方法处理导入过程

this.importer.runCmd(requestParams, sw);

在doFullImport中,首先会创建一个DocBuilder对象,DocBuilder的主要功能是从给定配置中创建Solr文档,同时会记录一些状态信息。随后通过execute()方法会通过遍历Entity的所有元素来解析config结构,最终得到是一个EntityProcessorWrapper对象。EntityProcessorWrapper是一个比较关键的类,继承自EntityProcessor,在整个解析过程中起到重要的作用,可以参考https://lucene.apache.org/solr/8_1_1/solr-dataimporthandler/org/apache/solr/handler/dataimport/EntityProcessorWrapper.html
在解析完config数据后solr会把最后更新时间记录到配置文件中,这个时间是为了下次进行增量更新的时候用的。接着通过this.dataImporter.getStatus()判断当前数据导入是“全部导入”还是“增量导入”,两个操作对应的方法分别为doDelta()和doFullDump(),此处的操作是full-import,因此调用doFullDump()

在doFullDump()中调用的是DocBuilder.buildDocument()方法,这个方法会为发送的配置数据的每一个processor做解析,当发送的entity中含有Transformers时,会进行相应的转换操作,例如转换成日期格式(DateFormatTransformer)、根据正则表达式转换(RegexTransformer)等,这次出现问题的是ScriptTransformer,可以根据用户自定义的脚本进行数据转换。由于脚本内容完全是用户控制的,当指定的script含有恶意代码时就会被执行,下面看一下Solr中如何执行javascript代码:
在读取EntityProcessorWrapper的每一个元素时,是通过epw.nextRow()调用的,它返回的是一个Map对象,进入EntityProcessorWrapper.nextRow方法

通过applyTransformer()执行转换,调用的是相应Transformer的transformRow方法

ScriptTransformer允许多种脚本语言调用,如Javascript、JRuby、Jython、Groovy和BeanShell等,transformRow()方法则会根据指定的语言来初始化对应的解析引擎,例如此处初始化的是scriptEngine,用来解析JavaScript脚本

Solr中默认的js引擎是Nashorn,Nashorn是在Java 8中用于取代Rhino(Java 6,Java 7)的JavaScript引擎,在js中可以通过Java.type引用Java类,就像Java的import一样,此处就可以通过这个语法导入任意Java类。 随后通过反射调用自定义的函数并执行,例如通过java.lang.Runtime执行系统命令

整个漏洞就是因为可以通过<script>标签指定ScriptTransformer,而在这个标签内可以导入任意的java类,Solr也并没有对标签内容做限制,导致可以执行任意代码。

调用栈情况

补充

值得注意的是,官方给出的临时修复方案并不能缓解漏洞,当把相应当index core的配置文件置为空时,dataimport的时候只是获取不到默认的配置,但是依然能够通过这个接口发送PoC,漏洞也依然能够触发,解决办法是把相应配置文件中的dataimport requestHandler全部注释并重启Solr服务器,才能彻底关闭这个接口缓解漏洞。

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now