Lucifaer's Blog.

S2-046(CVE-2017-5638)分析

Word count: 976 / Reading time: 4 min
2018/12/17 Share

S2-046,是045的另外两个触发流程,分析起来还是很有趣的。

0x00 漏洞描述

Problem
It is possible to perform a RCE attack with a malicious Content-Disposition value or with improper Content-Length header. If the Content-Disposition / Content-Length value is not valid an exception is thrown which is then used to display an error message to a user. This is a different vector for the same vulnerability described in S2-045 (CVE-2017-5638).

可以看到046是和045一样的触发点,只不过是利用方式不同,当构造一个Content-Disposition或一个错误的Content-Length时就有可能造成RCE,而造成ognl表达式执行的点还是在Jakarta Multipart解析器中。

总体来说046和045如出一辙,重复的FileUploadInterceptor文件上传拦截器就可以不用分析了,直接瞅瞅触发流程就好。

0x01 整体触发流程

1
2
3
4
5
6
MultiPartRequestWrapper$MultiPartRequestWrapper:86 # 处理requests请求
JakartaMultiPartRequest$parse:67 # 处理上传请求,捕捉上传异常
JakartaMultiPartRequest$processUpload:96 # 解析请求
JakartaMultiPartRequest$processFileField:105 # 处理上传表单
DiskFileItem$getName:259 # 获取并检查上传文件名
Steams$checkFileName:189 # 上传文件名中存在空白字符,抛出异常

0x02 漏洞分析

既然我们已经知道046的触发点和045的触发点是相同的,也就是说我们不需要重复去看FileUploadInterceptor执行ognl的过程了,我们只需要关注FileUpload这一部分的处理过程就好。

通过045我们知道ognl是通过报错信息传递的,而在046中,ongl也是通过这样的方法传递的。文件上传的过程中主要流程是在org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequestparse方法中进行处理的,我们再来看看除了045的Content-Type外,哪里还能利用。

注意红框框的这两部分,一部分是处理上传请求参数并创建新的upload item,而另一部分是在经过表单校验后,如果为上传表单时会执行的方法。而前一个是045的利用电,后一个是046的一个利用方式,接下来分别说一下046的两个利用流。

2.1 JakartaMultiPartRequest上传filename中存在空字符

可以看到首先会判断文件上传表单中是否没有给定文件名(即没有选择上传文件),跟进看一下getName()方法是如何校验文件名的:

在继承关系中我们看到getName()org.apache.commons.fileupload.disk中有具体的实现:

继续跟进checkFileName():

可以看到首先判断文件名是否存在,之后判断文件名中是否存在空字符,而在java中:

这样是可以通过检测的,所以也就是说我们可以通过构造一个包含ognl表达式的fileName进入if判断中,并且抛出一个InvalidFileNameException的异常,同时经过处理后的fileName拼接进报错信息中。

回到最开始的parse()方法中:

可以看到这里的异常处理直接把报错信息传入buildErrorMessage()中,剩下的流程就和045中是一样的,会直接执行报错信息中的ognl表达式。

2.2 JakartaStreamMultiPartRequest上传长度过长

这一个利用流程的通用性比之上面的来说,就差很多,首先JakartaStreamMultiPartRequest的处理流默认是不开启的,为了测试漏洞的话,可以在struts.xml中主动配置:

1
<constant name="struts.multipart.parser" value="jakarta-stream" />

JakartaStreamMultiPartRequest的对Content-Length的异常处理和JakartaMultiPartRequest不同:

判断Content-Length是否符合标准的地方是:

如果超出了maxSize则会进入addFileSkippedError()

可以看到会直接把fileName拼接进错误信息中,然后传到buildErrorMessage()中,执行错误信息中的ognl表达式。

所以总体来说两种利用方式的关键是构造含有ognl表达式的fileName

0x03 构造POC

和045的poc没什么区别,可以参考poc,最终的效果为:

0x04 Reference

CATALOG
  1. 1. 0x00 漏洞描述
  2. 2. 0x01 整体触发流程
  3. 3. 0x02 漏洞分析
    1. 3.1. 2.1 JakartaMultiPartRequest上传filename中存在空字符
    2. 3.2. 2.2 JakartaStreamMultiPartRequest上传长度过长
  4. 4. 0x03 构造POC
  5. 5. 0x04 Reference