客户端检测是发生在输入被实际发送至服务器之前进行的验证。这类检测大多是通过javascript检测上传文件的后缀是否合法。通常在上传页面中含有专门检测文件上传的javascript代码,最常见的是使用黑白名单校验。
判断方法:打开调试面板(F12),选择Network功能,分别上传普通图片和脚本文件,对这两个文件上传时Network的变化进行对比,若Network中数据没有变化,则说明是JS前端检测;如果有变化则说明JS前端没有进行验证,而是把文件传输到后台,后台进行验证,所以才会有网络请求。
上传正常图片(Network有变化):
网络中有数据流量产生
上传脚本文件(Network无变化):
提示不允许上传且没有数据流量产生,说明前端有JS检测。
检测请求头content-type字段;
文件扩展名检测;
文件内容检测;
服务器、中间件检测;
火狐浏览器
进入高级首选项(about:config),将javascript的值改为false
成功上传php文件
使用蚁剑进行连接
谷歌浏览器禁用javascript
F12
勾选上
上传图片文件,抓包,将后缀修改为php,上传。
content-type一般是指网页中存在的content-type(内容类型)。用于定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件。用户在上传文件时,服务器会获取该文件的content-type,再与事先设置好的进行对比,如果不一致,则不允许上传。
绕过方式:将content-type值改为image/*(image/jpeg、image/png、image/gif)
源码:
上传php文件,抓包,修改content-type为图片类型。
常见的MIME类型:
超文本标记语言文本 .html text/htmlxml文档 .xml text/xml普通文本 .txt text/plainRTF文本 .rtf application/rtfPDF文档 .pdf application/pdfMicrosoft Word文件 .word application/mswordPNG图像 .png image/pngGIF图形 .gif image/gifJPEG图形 .jpeg,.jpg image/jpegau声音文件 .au audio/basicMIDI音乐文件 mid,.midi audio/midi,audio/x-midiRealAudio音乐文件 .ra, .ram audio/x-pn-realaudioMPEG文件 .mpg,.mpeg video/mpegAVI文件 .avi video/x-msvideoGZIP文件 .gz application/x-gzipTAR文件 .tar application/x-tar任意的二进制数据 application/octet-stream
源码:黑名单写入了几乎所有可能是脚本文件的后缀,且过滤了.htaccess。
可上传混合大小写后缀的文件:Asp、ASpx、PHP、JSP;
源码:黑名单过滤,将黑名单中后缀名替换为空,且只替换一次。
修改后缀为:phphpp、aaspsp、jsjspp等;
jsp、jspx、jspf
asp、asa、cer、aspx
exe、exee
php、php3、php4、phtml、phps、pht,前提是Apache的配置文件要有如下配置:
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
如果“文件名+::$DATA”,系统会把“::$DATA”之后的数据当成文件流处理,不会检测后缀名,且会保持“::$DATA”之前的文件名,所以可以利用Windows的特性,在上传文件的后缀名加“::$DATA”进行绕过。
前提条件:mod_rewrite模块开启、AllowOverride All
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置.通过htaccess文件,可以实现:网页301重定向、自定义404页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
先上传.htaccess文件,文件内容如下(将所有文件当作php解析):
SetHandler application/x-httpd-php
再上传图片马
访问
源码:
检测方式为:先去除文件名末尾的点,再通过strrchr()寻找“.”以确认文件名的后缀,但最终保存文件的时候没有进行重命名,而是使用原始的文件名,导致可以利用“1.php. .”这种方式进行绕过。
源码:白名单检测,但$img_path是直接拼接,所以可利用%00截断绕过。
php00截断的使用条件:
php<5.3.4、magic_quotes_gpc为off状态;
有时数据包中必须含有上传文件后的目录才可使用该方法。
原理(%00与0x00):
表单中的enctype就是encodetype,指编码类型。
enctype有三个属性:
application/x-www-form-urlencoded:在发送前编码所有字符;
multipart/form-data:不对字符编码,或在使用包含文件上传控件的表单时,必须使用该值。指定传输数据为二进制类型。
text/plain:空格转换为“+”号,但不对特殊字符编码。纯文本的传输,
默认情况下,enctype的值是application/x-www-form-urlencoded,不能用于文件上传,只有使用了multipart/form-data,才能完整的传递文件数据。
而application/x-www-form-urlencoded不是不能上传文件,是只能上传文本格式的文件,multipart/form-data是将文件以二进制的形式上传,这样可以实现多种类型的文件上传。
在URL中%00被URLdecode后为空字符,所以当URL中出现%00是会认为读取已结束。
GET请求中,提交数据时浏览器会自动对数据进行URLdecode,所以GET请求可直接使用%00。
而POST请求中,上传的表单有个enctype的属性,若属性值为"multipart/form-data",则不会自动对表单进行URLdecode。而path大多数都是存放在表单中的,因此需要在数据包中进行urldecode操作,使%00变成字符串结束符号。就需要使用0x00,将hex值改为00才能进行截断。
0X00是字符串的结束标识符,攻击者可以利用手动添加字符串标识符的方式将后面的内容进行截断,而后面的内容又可以帮助我们绕过检测。
比如数据包中存在path为uploads/,那么攻击者可以通过修改path的值来构造payload为:uploads/1.php%00。程序检测的是文件的后缀名,如果后缀合法就会拼接路径和文件名,攻击者修改path后的拼接结果为:upload/1.php%00/2021091823123.jpg(可绕过后缀的检测),移动文件时%00产生截断作用,文件就会保存为upload/1.php,达到getshell的目的。
%00,是因为path也可以存放在URL或者cookie中,在提交数据的时候浏览器会对数据做一次urldecode操作,在服务端,会对数据进行一次urldecode操作,因此,如果path在非“enctype=multipart/form-data”的表单中或在URL、cookie中时,可以直接写%00,不再需要urldecode操作,服务器自己会对%00进行url解码。
实例:
通过正则匹配判断文件幻数(文件头)内容是否符合要求,一般为白名单检测,常见的文件头(文件头标志位)如下:
.JPEG .JPE .JPG :“JPGGraphicFile”(FFD8FFFE00)
.gif:”GIF89A”(474946383961)
.zip:”ZipCompressed”(504B0304)
.doc .xls .xlt .ppt .apr:“MSCompoundDocumentv1orLotusApproachAPRfile”(D0CF11E0A1B11AE1)
一般是在木马文件头部插入对应的文件头内容,比如GIF89A等,伪装成图片马。
图片马制作方法:
(1)直接在木马文件的头部添加GIF89A等字母;
(2)直接在图片文件中添加payload(易造成图片损坏);
(3)使用cmd命令,copy tupian.jpg /b + muma.php /a muma.jpg
(4)使用edjpgcom等工具制作;
getimagesize()函数会读取目标文件的16进制,验证目标文件16进制的头几个字符串是否符合图片的要求,通过此函数判断文件类型。故可以使用图片马进行绕过。
源码:
制作图片马:
再配合文件包含漏洞进行解析执行。
exif_imagetype()函数是用来读取文件的第一个字节并检查其签名,即通过文件头判断文件类型。所以与getimagesize()函数检测一样,可使用图片马进行绕过。
什么是条件竞争?
条件竞争是服务端的漏洞,由于后端程序操作逻辑不合理导致。由于服务端在处理不同用户的请求时是并发进行的,因此,如果并发处理不当或相关操作逻辑顺序设计的不合理时,会导致此类问题的发生。条件竞争一般发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中。
检测原理:
网站允许任意文件上传,再检查文件内容是否包含webshell,如果有就删除该文件;
网站允许任意文件上传,但如果不是指定的类型,会使用unlink删除文件。
绕过方法:
利用文件上传成功至文件被删除之间的时间差,上传一个可执行脚本文件,再使用多线程并发的方式访问上传的文件,总会有一次在时间差内访问到上传的php文件,一旦成功访问到了上传的文件,就能执行payload,因为php之类的代码只要访问就能执行。
源码:
上传逻辑:
通过move_uploaded_file($temp_file, $upload_file)移动上传的文件;
上传完毕后通过in_array($file_ext,$ext_arr)检查文件名后缀是否在白名单中;
若后缀合法,则对文件进行重命名(rename),上传完成;
若后缀非法,则删除文件。
绕过:
上传一个写一句话木马的文件test.php
<?php
$file=fopen("shell.php","w");
$string='<?php @eval($_POST["shell"]); ?>';
fwrite($file,$string);
fcolse();
?>
截取两个数据包,一个为上传test.php的请求包,另一个为访问shell.php的请求包。
将上传文件的请求包进行无参数爆破,让他不停的进行上传请求。
另一个访问shell.php的请求包也进行无参数爆破,不断地进行访问请求。
或者可以通过py脚本代替不停访问的操作。
import requests
for i in range(1000000):
url="文件地址"
if requests.get(url).status_code == 200 :
print('yes')
成功写入
WampServer2.0 All Version (WampServer2.0i / Apache 2.2.11) [Success]WampServer2.1 All Version (WampServer2.1e-x32 / Apache 2.2.17) [Success]Wamp5 All Version (Wamp5_1.7.4 / Apache 2.2.6) [Success]AppServ 2.4 All Version (AppServ - 2.4.9 / Apache 2.0.59) [Success]AppServ 2.5 All Version (AppServ - 2.5.10 / Apache 2.2.8) [Success]AppServ 2.6 All Version (AppServ - 2.6.0 / Apache 2.2.8) [Success]
IIS6.0
IIS6.0 在解析文件时存在以下两个解析漏洞 .
①当建立 .asa 、.asp 格式的文件夹时 , 其目录下的任意文件都将被 IIS 当作 asp 文件 来解析 .
② 在 IIS6.0 下 , 分 号 后面 的 扩 展 名 不 会 被 解 析 , 也 就 是 说 当 文 件 为 *.asp;.jpg
时,IIS6.0 同样会以 ASP脚本来执行 .
影响版本 :0.5,0.6,0.7<=0.7.65 0.8<=0.8.37
Nginx 在图片中嵌入 PHP代码 , 然后通过访问 xxx.jpg%00.php 可以执行其中的代码 .
注意
任意文件名/任意文件名.php这个漏洞是因为php-cgi
在 PHP的配置文件中有一个关键的选项 : cgi.fi: x_pathinfo. 这个选项在某些版本是
默认开启的 , 在开启时访问 url, 比如 :http://www.xxx.com/x.txt/x.php,x.php 是不存在的 文件 , 所以 php 将会向前递归解析 , 于是就造成了解析漏洞 . 由于这种漏洞常见于 IIS7.0 、 IIS7.5 、 Nginx 等 Web服务器 , 所以经常会被误认为是这些 Web服务器的解析漏洞 .
近期在做渗透测试的过程中,遇到一个文件上传,发现jsp脚本内容或者是jsp后缀名称的上传均会被waf拦截。正好有授权,实践下分块传输bypass waf的方法。
引用维基百科描述
分块传输编码(Chunked transfer encoding)是超文本传输协议(HTTP)中的一种数据传输机制,允许HTTP由网页服务器发送给客户端应用( 通常是网页浏览器)的数据可以分成多个部分。分块传输编码只在HTTP协议1.1版本(HTTP/1.1)中提供。(使用HTTP 1.0协议,服务器会主动放弃chunked编码。)
《HTTP权威指南》
[RFC7230]中查看到有关分块传输的定义规范。
4.1. Chunked Transfer Coding The chunked transfer coding wraps the payload body in order to transfer it as a series of chunks, each with its own size indicator, followed by an OPTIONAL trailer containing header fields. Chunked enables content streams of unknown size to be transferred as a sequence of length-delimited buffers, which enables the sender to retain connection persistence and the recipient to know when it has received the entire message. chunked-body = *chunk last-chunk trailer-part CRLF chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF chunk-size = 1*HEXDIG last-chunk = 1*("0") [ chunk-ext ] CRLF chunk-data = 1*OCTET ; a sequence of chunk-size octets The chunk-size field is a string of hex digits indicating the size of the chunk-data in octets. The chunked transfer coding is complete when a chunk with a chunk-size of zero is received, possibly followed by a trailer, and finally terminated by an empty line. A recipient MUST be able to parse and decode the chunked transfer coding. 4.1.1. Chunk Extensions The chunked encoding allows each chunk to include zero or more chunk extensions, immediately following the chunk-size, for the sake of supplying per-chunk metadata (such as a signature or hash), mid-message control information, or randomization of message body size. chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) chunk-ext-name = token chunk-ext-val = token / quoted-string The chunked encoding is specific to each connection and is likely to be removed or recoded by each recipient (including intermediaries) before any higher-level application would have a chance to inspect the extensions. Hence, use of chunk extensions is generally limited
通过阅读规范发现分块传输可以在长度标识处加上分号“;”作为注释,如
9;kkkkk 1234567=1 4;ooo=222 2345 0 (两个换行)
以上均为引用,以下为实践内容
burpsuite插件
https://github.com/c0ny1/chunked-coding-converter 解释下为什么有时候需要添加注释:因为几乎所有可以识别Transfer-Encoding数据包的WAF,都没有处理分块数据包中长度标识处的注释,导致在分块数据包中加入注释的话,WAF就识别不出这个数据包了。
Transfer-Encoding :在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码
回过头来看案例,正常情况下,上传一个jsp文件,会被waf拦截,返回为空,如下图所示
使用分块编码,对目标系统进行文件上传,如下图
不过还是被该系统的waf检测到了威胁,返回为空,上传失败。至于为什么,可能是因为该分块bypass方法已经有很长的一段时间了吧,所以很多waf都已经有了应对方法。
通过测试,发现WAF一般是如下应对分块传输的。
发现数据包是分块传输,启动分块传输线程进行接收 分块传输线程不断接收客户端传来的分块,直到接收到0rnrn 将所有分块合并,并检测合并之后的内容。
不过开发这个burpsuite插件工具的大佬也有了新的应对方法(膜拜):添加延时,消耗waf性能,让waf放弃等待所有分块发送完成。
借用下大佬的图
使用延时方法再次对目标系统发起上传
查看上传的结果,如下图,已经成功绕过waf,并上传成功
只有HTTP/1.1支持分块传输
POST包都支持分块,不局限仅仅于反序列化和上传包
Transfer-Encoding: chunked大小写不敏感
此处因为碰巧遇到了这么切合的场景,索性就拿来写个实践过程,此插件还有很多有趣的用法,比如sqlmap+burpsuite实现对post数据包分块bypass waf进行SQL注入
sqlmap -r 1.txt --batch --thread 10 --proxy=http://127.0.0.1:8080 --dbs
前提条件:寻找上传点,查看上传点是否可用。
利用:
首先判断是程序员自己写的上传点,还是编辑器的上传功能;
如果是编辑器上传功能,利用已纰漏的漏洞进行实验;
如果是程序员自己写的上传点,先上传正常的图片查看上传点是否可用,判断是白名单还是黑名单检测,再按照相对应的绕过方式依次实验。
判断服务器是什么类型,使用的是什么类型的web服务器,版本号多少。看是否可以利用解析漏洞。
检查文件上传路径,设置上传目录执行权限,拒绝脚本执行的可能性(避免%00截断、IIS6.0文件夹解析漏洞、目录遍历);
文件扩展名检测,避免服务器以非图片的文件格式解析文件,通常使用黑白名单进行检测;
文件MIME验证;
文件内容检测,避免图片中插入webshell;
图片二次渲染(基本上完全避免了文件上传漏洞);
文件重命名,如随机字符串或时间戳等方式,并且加上此前生成的文件扩展名,防止攻击者得到webshell的路径;
隐藏上传路径;
定义一个.htaccess文件,只允许访问指定扩展名的文件;
以上几点,可以防御绝大多数上传漏洞,但是需要跟服务器容器结合起来。如果解析漏洞依然存在,那么没有绝对的安全。
https://www.freebuf.com/news/193659.htmlhttps://www.anquanke.com/post/id/169738
https://gv7.me/articles/2021/java-deserialized-data-bypasses-waf-through-sleep-chunked/
https://www.secpulse.com/archives/95987.html
https://www.it610.com/article/1295203871039234048.htm
http://www.admintony.com/%E5%85%B3%E4%BA%8E%E4%B8%8A%E4%BC%A0%E4%B8%AD%E7%9A%8400%E6%88%AA%E6%96%AD%E5%88%86%E6%9E%90.html
https://www.it610.com/article/1295203871039234048.htm
E
N
D
关
于
我
们
Tide安全团队正式成立于2019年1月,是新潮信息旗下以互联网攻防技术研究为目标的安全团队,团队致力于分享高质量原创文章、开源安全工具、交流安全技术,研究方向覆盖网络攻防、系统安全、Web安全、移动终端、安全开发、物联网/工控安全/AI安全等多个领域。
团队作为“省级等保关键技术实验室”先后与哈工大、齐鲁银行、聊城大学、交通学院等多个高校名企建立联合技术实验室。团队公众号自创建以来,共发布原创文章370余篇,自研平台达到26个,目有15个平台已开源。此外积极参加各类线上、线下CTF比赛并取得了优异的成绩。如有对安全行业感兴趣的小伙伴可以踊跃加入或关注我们。
本文作者:TideSec
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/171650.html