tomcat的上传代码特性
前言:之前别人分享的一个知识点,这边简单记录下关于上传代码特性,在上传绕过waf会比较有用,比如war部署包的时候
参考文章:https://www.ch1ng.com/blog/264.html
参考文章:https://y4tacker.github.io/2022/06/19/year/2022/6/探寻Tomcat文件上传流量层面绕waf新姿势/
下面测试的tomcat是8.5.50
org.apache.catalina.core.ApplicationPart#getSubmittedFileName自动消除反斜杠
当通过war包部署的时候,pathinfo为upload的时候则触发getSubmittedFileName函数

这边可以观察tomcat的javax.servlet.http.Part#getSubmittedFileName函数
堆栈调用过程:
upload:246, HTMLManagerServlet (org.apache.catalina.manager)
doPost:207, HTMLManagerServlet (org.apache.catalina.manager)
service:660, HttpServlet (javax.servlet.http)
service:741, HttpServlet (javax.servlet.http)

getSubmittedFileName 首先会将Content-Disposition字段的数据进行;来进行分割

如果filename字段中存在双引号,则进行org.apache.tomcat.util.http.parser.HttpParser#unquote处理,遇到双引号会进行跳过处理,比如下面的\s\h\e\l\l.\w\a\r最终获取到的是shell.war

trim方法的发现
堆栈调用过程:
getSubmittedFileName:155, ApplicationPart (org.apache.catalina.core)
upload:246, HTMLManagerServlet (org.apache.catalina.manager)
doPost:207, HTMLManagerServlet (org.apache.catalina.manager)
service:660, HttpServlet (javax.servlet.http)
这里发现trim方法在处理空格的时候,除了直接处理空格,还有低于\x20的都与空格比较equal都为true
public class TestMain {
public static void main(String[] args) {
String t1 = "test\u001c".trim();
String t2 = "test ".trim();
System.out.println(t1.equals(t2));
}
}

而上传war包中的时候处理文件名的时候也用到了,如下图所示

在绕过waf中可能也是有用的,测试如下所示

在处理的时候进行了trim的处理

最后拿到的结果还是shell.war

org.apache.tomcat.util.http.parser.HttpParser#unquote
堆栈调用过程:
getSubmittedFileName:155, ApplicationPart (org.apache.catalina.core)
upload:246, HTMLManagerServlet (org.apache.catalina.manager)
doPost:207, HTMLManagerServlet (org.apache.catalina.manager)
service:660, HttpServlet (javax.servlet.http)
当文件名存在反斜杠的时候情况下会进入到unquote函数

在HttpParser.unquote(fileName.trim());中,当如果开头是引号,那么总长度则减去1,那么这里可以进行利用
比如filename="shell.wa\rT的形式,最终获取到的还是shell.war,如下图所示

org.apache.catalina.connector.Request#getPart支持多表单上传
堆栈调用过程:
upload:246, HTMLManagerServlet (org.apache.catalina.manager)
doPost:207, HTMLManagerServlet (org.apache.catalina.manager)
service:660, HttpServlet (javax.servlet.http)
org.apache.catalina.connector.Request#getPart 在获取上传表单的时候,该方法是默认支持多文件上传的,所以也可以考虑多文件表单绕过waf的测试

多文件表单上传如下所示

org.apache.tomcat.util.http.fileupload.ParameterParser#parse文件名支持编码解析
该方法在getSubmittedFileName中进行调用,如下图所示

跟进去它会对Content-Disposition字段的值进行=或者;进行分割,然后获取KV形式,对Value会调用MimeUtility.decodeText对其进行解析
Content-Disposition: form-data; name="deployWar"; filename="shell.war"

在MimeUtility.decodeText中解析的时候value支持encoded-word = "=?" charset "?" encoding "?" encoded-text "?="这种形式进行定义

比如我们这边通过=?US-ASCII?Q?Keith_Moore?=123456这段数据作为测试,含义就是以"Keith_Moore"通过QUOTEDPRINTABLE_ENCODING解码,通过US-ASCII解码字符串展示
-
"=?" charset "?"的代表charset为US-ASCII
-
"?" encoding "?"的代表encoding为Q,tomcat中支持两种解码方式,Q是QUOTEDPRINTABLE_ENCODING,B是Base64

- "?" encoded-text "?="的代表encoded-text为Keith_Moore
而这边的话同样也可以进行混淆利用,这里用到的是utf-16be,%00t%00e%00s%00t%00.%00w%00a%00r

然后放到bp中进行测试即可,这里不能直接用url编码的数据,空字节的话需要自己在hex中进行修改

测试结果如下

正常文件上传中的利用
上面说的都是在tomcat manager部署war包的时候所调用的,而原生的上传文件的操作用到的类是ServletFileUpload,而该类中并没有用到getSubmittedFileName等相关的操作,所以反斜杠的操作无法使用,大概过程如下所示

但是这边的话通过引用的方式寻找getSubmittedFileName调用处,可以发现request.getParts();方法中同样调用了getSubmittedFileName方法,所以如果在代码中使用了该方法的话同样是可以进行利用的,所以这边可以注意下
org.apache.catalina.connector.Request#parseParts
org.apache.catalina.connector.RequestFacade#getParts

但是encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" 这种形式的利用在正常文件ServletFileUpload上传中都可以用到,如下所示
下面测试的tomcat是9.0.45,发现同样是可以的

tomcat在9.0.45的变动
前面tomcat8.5.50中分析encoded-word = "=?" charset "?" encoding "?" encoded-text "?="这种形式的时候,只提供了MimeUtility.decodeText函数进行解析,而这里9.0.45版本中还另外添加了一个函数RFC2231Utility.decodeText来进行分析,如下所示
如果满足RFC2231Utility.hasEncodedValue则调用该RFC2231Utility.decodeText函数

如果满足KV形式中的Key满足结尾是一个'*'符号的话则使用RFC2231Utility.decodeText解析

而在RFC2231Utility.decodeText中解析的过程是如下,最终拿到的文件名同样也是test.jsp


新的随意发现的东东
在代码中可以发现很多比较有意思的,如果解析顺序的问题,如果存在多个Content-Disposition字段的话,优先解析第一个,那么如果waf是选取末尾的话则就被绕过了
还有很多 大家自己可以慢慢观察
org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl#getHeader



浙公网安备 33010602011771号