commons-fileupload bypass

开头:

​ 之前有一些师傅对Commons-fileupload这个apache文件上传组件有过一些研究,我之前也看到很多文章,今天来自己做一下研究看看相关的原理;

正文:

​ 首先构建一个项目用于方便复现;相关搭建过程就不过多赘述了,我的环境搭建是采用springboot+fileupload;在此之前要先在配置文件中关闭掉原本springboot的文件上传解析,否则parseRequest函数处理返回为空;搭建完成之后导入相应的依赖;编写一个controller进行调用就可;问题的发生点是在对filename的处理上;

放出我的controller:

bbfx0g.png

追踪一下parseRequest函数:

bb8xCq.png

看到内部处理流程:

bbGm26.png

发现对上传的表单进行了相关的处理和解析;

bbGYGt.png

进入下面FileItemIteratorImpl下看看处理细节:

bbJky8.png

具体的判断为contentType开头要为multipart/;中间下面这段是对输入流进行相关的处理;拿到相关的编码规则等等;接着看一个敏感函数;

可以很清晰的看到是对一些流里的数据做了相应的处理,按照分号和逗号进行相应的分割;

1
2
3
4
------WebKitFormBoundaryovjb4UffMAlZ2ToM
Content-Disposition: form-data; name="file"; filename="1.jsp"
233
------WebKitFormBoundaryovjb4UffMAlZ2ToM--

这里都不是重点,之前有师傅爆出采用在filename左右加上空格的方法,会导致相应的waf不匹配从而造成饶过;那么相关的问题点肯定是发生在filename的地方,这里直接追溯到相关的敏感函数中去看一下:

bbYl4A.png

入口点在此;向下追溯看看相关的敏感解析点,调试过java的师傅肯定都知道敏感的parse或多或少都要看一下;这个解析点就是在此函数中;

bbYdEQ.png

可以看到里面是对

1
Content-Disposition: form-data; name="file"; filename="1.jsp"

进行相关的解析;

bbUuHU.png

利用分号进行分割完之后再次按照等号进行相关的分割,拿到paramName和paramValue;

在解析的过程之中,会调用parseToken进行解析,跟进看一下:

bbN16P.png

按照相关的逻辑进行解析,最后调用getToken函数进行处理并且return;这个函数里可以细致看一下流程;

bbNB60.png

看到这里相信很多人都已经明白了,对空白字符字符做相应的处理;这里自然会处理空格,tab键,换行符等的空白字符,处理原理就是将相关的指针进行移动,从而实现去除空白字符;所以利用这个特性,可以对于一些waf进行一些简单的饶过,在filename的地方前后添加空格或者%0a之类的空白字符,就可饶过匹配,饶过之后进行解析会将其去除,所以这是一个挺好的饶waf的点;

bbNQSI.png

除了这种方法饶过waf之外还有一些更骚的操作,可以继续向下分析一波;

这里有一个敏感的点decodeText,追溯进去看一发:

发现是对filename的paramValue进行处理;

bbtYGR.png

不过这里有相关的要求,我们没办法进入相关流程,动态调试一下,往后看看解析;看到进入相关的decodeWord,这个函数就很敏感;追进去看一下;

bbaPr6.png

可以看到开始了标志符的处理,这里我们动态调试:

bbyDPK.png

发现如此构造可以在substring中街区到相关的字符;进入后续的处理;可以看到后续就进入了相应的加解密流程,但是需要匹配到相应的标识符才可进行解析;

bbyfat.png

回溯一下标识符的匹配传入,发现是在上方利用substring进行截取;继续动态修改;

bb6LlD.png

可以看到相关的效果,调试到此发现匹配到B之后,会将我们传入的asdf进行base64的解码,这里便是一个很好的利用点,可以利用此解码机制饶过相应的waf;

bbc9tP.png

可以很清晰的看到被解码成了乱码,解码成乱码肯定会触发后面的错误;

bbgtKg.png

这里可以看到传入正常的base64加密的filename,在这里就会被进行相关的解析;就会被正确的写入;但是事实是最后还是发生了报错,很显然是在javaCharset这里发生了问题;

bbgUbj.png

之类charset为空;追溯一下:

bbgrGV.png

发现是需要在map进行相关的寻找从而设置相应的编码格式;

这里eval一下看看如何满足条件:

bbgzJP.png

找到相关的插入点即可;在此修改文件名进行调试;结果如下:

bb2JF1.png

可以看到这次已经正确的解析到了charset;继续往下跟入:

bb2wOe.png

发现在之前报错的javaCharset函数中已经可以正常的get到相关的编码规则;最后就会被成功的写入:

bb2LlT.png

所以最后我们上传=?utf8?B?czFtcGxlLmpzcA==?=;经过waf判断没有什么问题,最后经过commons-fileuplaod组件解析之后会成为s1mple.jsp;最后即可传入;

bbRL4I.png

bbW88x.png

bbf6YR.png

其实分析到这里,已经没有什么悬念了,直接可以上传文件,这里base64的相对比较好理解,还有一种编码方式我这里顺带提一下吧;那种编码方式加密原理是将任何8-bit字节值可编码为3个字符:⼀个等号”=”后跟随两个⼗六进制数字(0–9或A–F)表⽰该字节的数值。例如,ASCII码换页符(⼗进制值为12)可以表⽰为”=0C”, 等号”=”(⼗进制值为61)必须表⽰为”=3D”,gb2312下“中”表⽰为=D6=D0;其实都只是加密方式的不一样,最后产生的攻击效果都是一样的;23333

总结

commons-fileupload的饶过waf的方式主要是基于其自身的特性,在filename前后加上空白字符,导致无法合理匹配filename导致饶过waf是因为内部采用了isWhitespace方法进行对filename的判断,判断为空白字符则去除,所以对于上传上去是没有什么影响的;另外一种方法则是利用了commons-fileupload的内部上传处理机制,对filename进行相关的加密;从而饶过相关的waf;其实也不是很难理解23333;