solr 配置多个entity_详细分析Solr的CVE20190193以及velocity模板注入新洞

本文详细分析了Solr配置多个entity的情况,重点讨论了CVE-2019-0193漏洞。首先介绍了环境搭建,然后通过源码分析,揭示了SolrRequestFilter如何处理请求,特别关注了ScriptTransformer如何导致远程代码执行(RCE)。文中提到了利用漏洞的两个关键请求,第一个请求覆盖配置,第二个请求利用 VelocityResponceWriter 进行模板注入。作者指出,当paramsResourceLoaderEnabled为true时,可以实现模板注入,否则会因找不到模板而导致失败。文章最后发出招新广告,欢迎对相关领域感兴趣的人加入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境搭建

java "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9000" -Dsolr.solr.home="../example/example-DIH/solr/" -jar start.jar --module=http

然后idea加远程调试9000端口,dist、server/lib文件夹加到library里。dist是solr的主要jar

首先是CVE-2019-0193

首先看exp

POST /solr/tika/dataimport HTTP/1.1

Host: 10.27.52.42:8983

Content-Length: 416

Content-type: application/x-www-form-urlencoded

Connection: close

command=full-import&dataConfig=

<dataConfig>

<dataSource type="URLDataSource"/>

<script>CDATA[ java.lang.Runtime.getRuntime().exec("open -a Calculator");

]]>script>

<document>

<entity name="a"

url="https://stackoverflow.com/feeds/tag/solr"

processor="XPathEntityProcessor"

forEach="/feed"

transformer="script:" />

document>

dataConfig>

solr的admin后台文件是server/solr-webapp, 所以首先还是得看web.xml,看大概的一些filter、url-pattern路由才能知道后台怎么过去的。140227ba0357a8c2fb44bfa0eeff633d.png

请求都走了SolrRequestFilter这个过滤器,对应着org.apache.solr.servlet.SolrDispatchFilter,进去看一下看了doFilter方法,主要就是通过getHttpSolrCall返回一个HttpSolrCall对象,然后调用call方法到了servlet类中,然后handler.handleRequest(req, rsp);进到了handleRequest中对请求响应进行处理。

在handleRequest中,this.handleRequestBody(req, rsp);调用了抽象方法来对请求处理,看一下哪些类实现了这个抽象方法。

有点多,这些都是可以通过路由直接请求到的类。这里不仔细看了。

exp是请求/solr/tika/dataimport,所以直接进入exp中的dataimport类。4772120b48db3419d1290bcdad068317.png

一开始通过loadDataConfig,其中调用了readFromXml方法,从xml数据中读取信息并解析,根据解析出的document,script,function,dataSource等标签构建出DIHConfiguration对象并返回。然后根据传的参数,没debug,进了这里。2a6b9f52de47bb10b817f01ed2519ffd.png里边只是在新线程中进了runCmd中,还是进了runCmd。根据我们传的full-import,进了这里。在doFullImport中,首先会创建一个DocBuilder对象,DocBuilder的主要功能是从给定配置中创建Solr文档,同时会记录一些状态信息。随后通过execute()方法会通过遍历Entity的所有元素来解析config结构,最终得到是一个EntityProcessorWrapper对象。

下面是通过docBuilder.execute()进入doFullDump然后进入buildDocument方法。可以看到,execute中传入的生成的builder对象的config属性是之前根据我们传入的payload生成的DIHConfiguration对象。buildDocument()方法会为发送的配置数据的每一个processor做解析,当发送的entity中含有Transformers转换器时,会进行相应的转换操作。问题出在ScriptTransformer。script转换器能够对把其他java支持的语言转成java函数执行。而内容我们可控,这就很尴尬了。引用A-Team大佬的描述:

脚本转换器允许使用Java支持的语言(比如Javascript, JRuby, Jython, Groovy, or BeanShell)编写任意转换函数,其中Javascript语言已默认集成在Java中了,使用其他语言的话需要自己整合。每个转换函数都 必须接收一个row变量(与Java中的Map类型对应,所以是支持get、put、remove等操作的),函数的功能是修改已知field的值,或者添加新的fields。处理完之后,将row对象作为返回值返回。这个脚本会以最高级别插入到DIH配置文件中,每个row会调用一次。

df3c23f8d8ae486104d8dbd47d41b42e.png跟buildDocument(), 下面通过epw.nextRow();进入到了applyTransformer,这里就是问题触发点。

b6c49c2c1e3bb256d0e9d3a9db07f000.png

首先是loadTransformers,进入加载转换器。下边startwith判断,如果转换器以script开头,则把ScriptTransformer加到transformers里。

加载转换器后,通过transformers.iterator();遍历所有转换器。跟进t.transformRow,然后就很清晰了。通过initEngine初始化转换引擎,进去看一下,通过eval完成了js函数定义。出来后通过invokeFunction完成了rcef3f0477b38fb40086ad2a7d2f44a5ad4.png最后说一下,payload中document这部分

6a0afce3013146ba79c633b99f3f08b3.png

这里就是buildDocument中,需要对传入的实体进行解析,根据我们传入的datasource类型加载对应的datasource。这里主要的作用还是构建我们的script转换器,并且让exp不报错。如果传一个不存在的datasource会报错无法执行exp。solr一共有6中datasource,这里用URLDatasource主要是很方便。网上除了看到URLDataSource外还看到了JdbsDataSource的payload,可以直接ldap+jndi

看下新的这个洞

两次请求,第一个是覆盖了config然后才能velocity模板注入。这里确实牛逼,膜

9e926fdc558da4d81999d350a696280b.png

首先第一个包,他是config进来的。和之前一样,看下configHandler的handleRequestBod

5e0986c8992d36197b59219c4bc6b480.png进到command.handlePOST里,继续跟handleCommands, 里边SolrResourceLoader.persistConfLocally,进去看一下5145dd355d07596d46f462ae87200812.png

可以看到,直接把我们要覆盖的配置写入configoverlay.json中。这里第一次请求需要做的事情就完成了。

下面看第二次请求。第二次理论上应该是把configoverlay.json中的配置读出来,然后写到VelocityResponceWriter的配置中,但我跟了几遍代码,都没有找到读文件配置的部分。。配置是true和false的区别就在初始化velocity对象时,对象的配置值不同。。这里应该是内存中的值,当文件中的值更改后,会进入init方法中重置该值(大概)。c78870811d4b3e3750119d402231e74f.png继续往下跟,进入到在createInitInstance中,通过解析请求参数中的class,使createInstance方法创建一个VelocityResponceWriter对象,然后调用他的init方法。c16f52ea1d8dccd5094bdbc0f4b0d446.png跟进能看到prle和srle就是传入的要覆盖的属性。他们被覆盖到了VelocityResponceWriter对象的this.paramsResourceLoaderEnabled和this.solrResourceLoaderEnabled属性。a448d58757eae0d5c3fa39bc25b94a6f.png当到了createEngine的时候可以看到,paramsResourceLoaderEnabled是true时将params加到了loader里。接下来通过engine.getTemplate(templateName + ".vm");就能够从url中获得传过去的exp。a1867738e921c4a4926a2e0d6f30da1d.png

然后返回继续到template.merge进入velocity中,然后继续跟一下会发现在render中通过ASTprocess解析注入的模板完成RCE34b0b6553a1fae144d2329af970f3f3c.png而当是false时,engine.getTemplate会报错找不到该vm,原因就是paramsResourceLoaderEnabled为false时,velocity并不会从url中获得velocity的模板字符串,从而无法进行模板注入。39a356959cb8746e0fcdba9e63c1511a.png可以继续跟一下Solr的各个handler,感觉可能还会有其他直接render的地方能直接ssti。 6dc2c0c33a09b313682a51bf81ee032e.png

招新小广告

ChaMd5 ctf组 长期招新

尤其是crypto+reverse+pwn+合约的大佬

欢迎联系admin@chamd5.org

985a9eab6b4dae7744dcd37d28e9bad8.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值