Apache Struts2存在远程代码执行漏洞,攻击者可以将恶意代码通过http报文头部的Content-Type字段传递给存在漏洞的服务器,从而导致了任意代码执行漏洞
漏洞分析
S2-045漏洞的poc如下。该poc是漏洞发现者——安恒的 Nike Zheng编写的
在分析过poc之后发现,payload是从content-type字段中传入的
我们使用了对应版本struts2官方案例app struts2-showcase来搭建漏洞环境
首先看一下案例中struts2-showcase中的web.xml
可以看出struts2-showcase使用StrutsPrepareFilter作为过滤器
因此我们在StrutsPrepareFilter中doFilter方法中下断,执行poc并发送本次漏洞的利用请求
上图可见,程序执行到StrutsPrepareFilter中doFilter方法,doFilter方法中,程序将执行prepare.wrapRequest以进行request处理分支
跟入prepare.wrapRequest
在prepare.wrapRequest中,调用dispatcher.wrapRequest对request进行处理
跟入dispatcher.wrapRequest
见上图红框处的if分支。当content-type为”multipart/form-data”时进入该if分支,在该if分支中将调用MultiPartRequestWrapper生成一个名为request的实例
继续跟入MultiPartRequestWrapper类,进入其构造方法MultiPartRequestWrapper,见下图
可见request请求被传入上图84行中parse方法中
继续跟入parse方法
在parse方法中,当”Content-Type”格式错误时,会出现异常,进入catch分支,程序最终会执行到105行处buildErrorMessage方法处
跟入buildErrorMessage方法
buildErrorMessage方法中的localizedTextUtil.findText会执行ognl表达式,从而导致命令执行。注意上图123断点处,程序将e.getMessage()传入localizedTextUtil.findText,而e.getMessage()正是我们构造的payload
继续跟入findText
可见findText中的defaultMessage参数即为我们构造的payload,也就是上一步传入的e.getMessage()
接着,findText会将defaultMessage传入getDefaulMessage方法中,见下图
继续跟入GetDefaultMessageReturnArg方法
可见payload又被传递到TextParseUtil.translateVariables中
继续跟入TextParseUtil.translateVariables
继续跟入parser.evaluate
最终在parser.evaluate里执行ognl语句。
写在最后
回顾之前的S2-001漏洞,不得不说,S2-045的执行点与S2-001漏洞的执行点极其相似
我们看一下S2-045最终的执行点:
位于Com\opensymphony\xwork2\util\OgnlTextParser.java
再看一下S2-001最终的执行点:
位于\com\opensymphony\xwork2\util\TextParseUtil.java
代码结构几乎完全一样