环境搭建
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路由才能知道后台怎么过去的。
请求都走了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类。
一开始通过loadDataConfig,其中调用了readFromXml方法,从xml数据中读取信息并解析,根据解析出的document,script,function,dataSource等标签构建出DIHConfiguration对象并返回。然后根据传的参数,没debug,进了这里。
下面是通过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<String,Object>类型对应,所以是支持get、put、remove等操作的),函数的功能是修改已知field的值,或者添加新的fields。处理完之后,将row对象作为返回值返回。这个脚本会以最高级别插入到DIH配置文件中,每个row会调用一次。
首先是loadTransformers,进入加载转换器。下边startwith判断,如果转换器以script开头,则把ScriptTransformer加到transformers里。
加载转换器后,通过transformers.iterator();遍历所有转换器。跟进t.transformRow,然后就很清晰了。通过initEngine初始化转换引擎,进去看一下,通过eval完成了js函数定义。出来后通过invokeFunction完成了rce
这里就是buildDocument中,需要对传入的实体进行解析,根据我们传入的datasource类型加载对应的datasource。这里主要的作用还是构建我们的script转换器,并且让exp不报错。如果传一个不存在的datasource会报错无法执行exp。solr一共有6中datasource,这里用URLDatasource主要是很方便。网上除了看到URLDataSource外还看到了JdbsDataSource的payload,可以直接ldap+jndi
看下新的这个洞
两次请求,第一个是覆盖了config然后才能velocity模板注入。这里确实牛逼,膜
首先第一个包,他是config进来的。和之前一样,看下configHandler的handleRequestBod
可以看到,直接把我们要覆盖的配置写入configoverlay.json中。这里第一次请求需要做的事情就完成了。
下面看第二次请求。
第二次理论上应该是把configoverlay.json中的配置读出来,然后写到VelocityResponceWriter的配置中,但我跟了几遍代码,都没有找到读文件配置的部分。。配置是true和false的区别就在初始化velocity对象时,对象的配置值不同。。这里应该是内存中的值,当文件中的值更改后,会进入init方法中重置该值(大概)。
然后返回继续到template.merge进入velocity中,然后继续跟一下会发现在render中通过ASTprocess解析注入的模板完成RCE
招新小广告
ChaMd5 ctf组 长期招新
尤其是crypto+reverse+pwn+合约的大佬
欢迎联系admin@chamd5.org