Apache Struts2存在远程代码执行漏洞,攻击者可以将恶意代码通过http报文头部的Content-Type字段传递给存在漏洞的服务器,从而导致了任意代码执行漏洞

漏洞分析

S2-045漏洞的poc如下。该poc是漏洞发现者——安恒的 Nike Zheng编写的

lMWPSS.png

在分析过poc之后发现,payload是从content-type字段中传入的

我们使用了对应版本struts2官方案例app struts2-showcase来搭建漏洞环境

首先看一下案例中struts2-showcase中的web.xml

lMRlVI.png

可以看出struts2-showcase使用StrutsPrepareFilter作为过滤器

因此我们在StrutsPrepareFilter中doFilter方法中下断,执行poc并发送本次漏洞的利用请求

lMRuKH.png

上图可见,程序执行到StrutsPrepareFilter中doFilter方法,doFilter方法中,程序将执行prepare.wrapRequest以进行request处理分支

跟入prepare.wrapRequest

lMRtxg.png

在prepare.wrapRequest中,调用dispatcher.wrapRequest对request进行处理

跟入dispatcher.wrapRequest

lMRmxe.png

见上图红框处的if分支。当content-type为”multipart/form-data”时进入该if分支,在该if分支中将调用MultiPartRequestWrapper生成一个名为request的实例

继续跟入MultiPartRequestWrapper类,进入其构造方法MultiPartRequestWrapper,见下图

lMRJG8.png

可见request请求被传入上图84行中parse方法中

继续跟入parse方法

lMRZ8O.png

在parse方法中,当”Content-Type”格式错误时,会出现异常,进入catch分支,程序最终会执行到105行处buildErrorMessage方法处

跟入buildErrorMessage方法

lMRGPf.png

buildErrorMessage方法中的localizedTextUtil.findText会执行ognl表达式,从而导致命令执行。注意上图123断点处,程序将e.getMessage()传入localizedTextUtil.findText,而e.getMessage()正是我们构造的payload

继续跟入findText

lMRarj.png

可见findText中的defaultMessage参数即为我们构造的payload,也就是上一步传入的e.getMessage()

接着,findText会将defaultMessage传入getDefaulMessage方法中,见下图

lMR1at.png

继续跟入GetDefaultMessageReturnArg方法

lMRKrd.png

可见payload又被传递到TextParseUtil.translateVariables中

lMRdqs.png

继续跟入TextParseUtil.translateVariables

lMRyGT.png

继续跟入parser.evaluate

lMRBaq.png

lMRUMQ.png

最终在parser.evaluate里执行ognl语句。

写在最后

回顾之前的S2-001漏洞,不得不说,S2-045的执行点与S2-001漏洞的执行点极其相似

我们看一下S2-045最终的执行点:

位于Com\opensymphony\xwork2\util\OgnlTextParser.java

lMRYRS.png

再看一下S2-001最终的执行点:

位于\com\opensymphony\xwork2\util\TextParseUtil.java

lMR0Zn.png

代码结构几乎完全一样