之前有一些师傅对Commons-fileupload这个apache文件上传组件有过一些研究,我之前也看到很多文章,今天来自己做一下研究看看相关的原理;
首先构建一个项目用于方便复现;相关搭建过程就不过多赘述了,我的环境搭建是采用springboot+fileupload;在此之前要先在配置文件中关闭掉原本springboot的文件上传解析,否则parseRequest函数处理返回为空;搭建完成之后导入相应的依赖;编写一个controller进行调用就可;问题的发生点是在对filename的处理上;
放出我的controller:
追踪一下parseRequest函数:
看到内部处理流程:
发现对上传的表单进行了相关的处理和解析;
进入下面FileItemIteratorImpl下看看处理细节:
具体的判断为contentType开头要为multipart/;中间下面这段是对输入流进行相关的处理;拿到相关的编码规则等等;接着看一个敏感函数;
可以很清晰的看到是对一些流里的数据做了相应的处理,按照分号和逗号进行相应的分割;
1 | ------WebKitFormBoundaryovjb4UffMAlZ2ToM |
这里都不是重点,之前有师傅爆出采用在filename左右加上空格的方法,会导致相应的waf不匹配从而造成饶过;那么相关的问题点肯定是发生在filename的地方,这里直接追溯到相关的敏感函数中去看一下:
入口点在此;向下追溯看看相关的敏感解析点,调试过java的师傅肯定都知道敏感的parse或多或少都要看一下;这个解析点就是在此函数中;
可以看到里面是对
1 | Content-Disposition: form-data; name="file"; filename="1.jsp" |
进行相关的解析;
利用分号进行分割完之后再次按照等号进行相关的分割,拿到paramName和paramValue;
在解析的过程之中,会调用parseToken进行解析,跟进看一下:
按照相关的逻辑进行解析,最后调用getToken函数进行处理并且return;这个函数里可以细致看一下流程;
看到这里相信很多人都已经明白了,对空白字符字符做相应的处理;这里自然会处理空格,tab键,换行符等的空白字符,处理原理就是将相关的指针进行移动,从而实现去除空白字符;所以利用这个特性,可以对于一些waf进行一些简单的饶过,在filename的地方前后添加空格或者%0a之类的空白字符,就可饶过匹配,饶过之后进行解析会将其去除,所以这是一个挺好的饶waf的点;
除了这种方法饶过waf之外还有一些更骚的操作,可以继续向下分析一波;
这里有一个敏感的点decodeText,追溯进去看一发:
发现是对filename的paramValue进行处理;
不过这里有相关的要求,我们没办法进入相关流程,动态调试一下,往后看看解析;看到进入相关的decodeWord,这个函数就很敏感;追进去看一下;
可以看到开始了标志符的处理,这里我们动态调试:
发现如此构造可以在substring中街区到相关的字符;进入后续的处理;可以看到后续就进入了相应的加解密流程,但是需要匹配到相应的标识符才可进行解析;
回溯一下标识符的匹配传入,发现是在上方利用substring进行截取;继续动态修改;
可以看到相关的效果,调试到此发现匹配到B之后,会将我们传入的asdf进行base64的解码,这里便是一个很好的利用点,可以利用此解码机制饶过相应的waf;
可以很清晰的看到被解码成了乱码,解码成乱码肯定会触发后面的错误;
这里可以看到传入正常的base64加密的filename,在这里就会被进行相关的解析;就会被正确的写入;但是事实是最后还是发生了报错,很显然是在javaCharset这里发生了问题;
之类charset为空;追溯一下:
发现是需要在map进行相关的寻找从而设置相应的编码格式;
这里eval一下看看如何满足条件:
找到相关的插入点即可;在此修改文件名进行调试;结果如下:
可以看到这次已经正确的解析到了charset;继续往下跟入:
发现在之前报错的javaCharset函数中已经可以正常的get到相关的编码规则;最后就会被成功的写入:
所以最后我们上传=?utf8?B?czFtcGxlLmpzcA==?=
;经过waf判断没有什么问题,最后经过commons-fileuplaod组件解析之后会成为s1mple.jsp;最后即可传入;
其实分析到这里,已经没有什么悬念了,直接可以上传文件,这里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;