文件上传相关
初始参考思路
PASS1
直接上传快速弹框,且点击上传抓包无数据,属于前端校验
方式一:修改原始后缀,先绕过前端,再修改后缀和Content-Type
方式二:抓包修改响应包,前端禁用JS即可
PASS2
直接上传响应类型不正确,应该是后端校验
修改后缀为.jpg失败,修改Conten-Type成功(MIME检测)
常见MIME
PASS3
直接上传显示如下,表示存在基于后缀的黑名单
修改后缀为一些特殊后缀用于绕过,并且能够服务器解析php文件:php3、php5、php7、phtml、pht
注意:题目docker环境中默认没有开启对phtml等后缀的解析,可编辑/etc/mime.types 去掉部分行的注释即可
PASS4
直接上传提示如下
上传非法后缀可以,表示存在黑名单,但是未过滤.htaccess
上传.htaccess重写解析规则绕过
表明将jpg后缀当作php来解析,再上传一个php文件抓包修改后缀即可成功解析
注意:题目docker环境中.htaccess并不会重写生效,需要做如下配置
- sudo a2enmod 随后输入rewrite表示让apache加载重写模块
- 修改/etc/apache2/apache2.conf 文件下如下部分
- 重启docker环境
PASS5
还是和PASS4一样黑名单(加入了.htaccess),但是未转小写,可通过大写绕过
PASS6
黑名单,加入.htaccess,转小写,但是未去空格
上传php文件,文件名后加空格绕过
PASS7
黑名单,转小写,去空格,未去'.'
上传php文件,文件名后加.绕过
注意:PASS6 和 PASS7都是利用了windows系统的文件名特性,在文件名后加[空格]、[.]会被自动去除,例如shell.php[空格] 或 shell.php[.]保存至windows后即为shell.php。但是在linux docker环境下空格绕过失败、加点绕过成功(多后缀解析漏洞)。
多后缀解析漏洞
AddHandler application/x-httpd-php .php
//只要含.php的都会被当作php文件被解析
或者
<FilesMatch ".+\.ph(ar|p|tml)">
SetHandler application/x-httpd-php
</FilesMatch>
上面两个配置都可以实现解析文件名中包含.php后缀的文件,apache对文件后缀名的识别是从后向前进行匹配的,以单个.作为分隔符。当遇到不认识的后缀时继续往前,直到识别,若都不识别就不做处理。
PASS8
黑名单,未去除'::$DATA’字符串
在文件名后添加::$DATA绕过
windows文件流特性
NTFS交换数据流(alternate data streams,简称ADS),是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流,就是说除了主文件流之外还可以有许多非主文件流寄宿在主文件流中。创建一个数据交换流文件的方法:“宿主文件:准备与宿主文件关联的数据流文件”
比如:shell.php::$DATA 上传至windows实际上访问的就是shell.php本身流数据 。如果shell.php还有别的数据流,比如:shell.php:shell1.php ,那么请求shell.php:shell1.php::$DATA,实际上访问的是shell.php流数据中的shell1.php流数据
也就是说在后端判断时可绕过后缀名检测,落地后即为shell.php,可以正常解析。
PASS9
黑名单,去除点,首尾去空
类似PASS6,在文件名后添加. .(点 空格 点)绕过
后端去除点、去空后为shell.php. 可正常解析
PASS10
黑名单,上传.php文件去除了php
后缀
双写绕过
PASS11
上传任意后缀失败,白名单
GET请求中的save_path可控,使用%00截断绕过白名单
作者提供的linux docker下失败,原因为PHP版本=5.5.38
注意:
00截断利用条件
PHP版本<5.3.4、magic_quotes_gpc=off(magic_quotes_gpc开关作用时间是请求开始时,表示在SQL语句执行前对字符串内容是否进行转义)
00截断原理
0x00是字符串的结束标识符;真正发挥作用是在处于路径中并和文件名进行拼接,从而发生截断,成功绕过白名单限制;路径一般可以在URL、Cookie、表单中,对于URL和Cookie而言,浏览器端和服务器端都会进行一次urldecode,这样就会将%00解码转换为字符串结束符,对于表单而言,如果有属性enctype=“multipart/form-data”(表示不会对表单数据进行编码),服务端接收到表单数据中的%00并不会urldecode,自然无法转换成结束符,这时候需要手动转为十六进制确保其为结束符
form表单enctype属性
application/x-www-form-urlencoded:在发送前编码所有字符(默认)
multipart/form-data:不对字符编码,或在使用包含文件上传控件的表单时,必须使用该值
text/plain:空格转换为 “+” 加号,但不对特殊字符编码
综上
确保是路径中使用、在URL or Cookie中直接%00即可、在表单中(enctype=“multipart/form-data”)需要手动转
PASS12
上传任意后缀失败,白名单
POST请求中的sava_path可控,不能再使用%00了,因为POST中不会像URL中那样可以解码。在Burp的hex中在路径后添加0x00实现截断
同11失败了
PASS13
从文件头中读取图片的相关特征确保上传的为图片类文件
用图下代码判断文件头
function getReailFileType($filename){
$file = fopen($filename, "rb");
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack("C2chars", $bin); //按照指定格式解二进制数据
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
$fileType = '';
switch($typeCode){
case 255216:
$fileType = 'jpg';
break;
case 13780:
$fileType = 'png';
break;
case 7173:
$fileType = 'gif';
break;
default:
$fileType = 'unknown';
}
return $fileType;
}
GIF绕过,文件头中添加GIF89a
JPG绕过,使用命令生成图片马,再上传即可
PNG类似
**注意:**仅仅只是上传了图片马,需要配合文件包含漏洞才能解析为PHP
PASS14
使用如下代码判断是否为真实图片
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
getimagesize
<?php
list($width, $height, $type, $attr) = getimagesize("test.png");
echo "宽度为:" . $width;
echo "高度为:" . $height;
echo "类型为:" . $type;
echo "属性:" . $attr;
?>
同样可使用PASS13中的图片马绕过
PASS15
使用php_exif模块检测文件类型,同PASS13上传图片马即可
PASS16
进行了二次渲染,具体绕过思路就是比较上传后且渲染过的正常图片和原始图片的区别,在相同的部分插入webshell代码
参考如下:
https://xz.aliyun.com/t/2657#toc-12
PASS17
白名单,条件竞争。代码逻辑:先上传上来,再判断是否为白名单类型或者其他判断等,如果非法就立刻删除,如果合法就重命名,即先落地再判断处理
绕过方法
初始上传一个shell1.php,内容为生成一个webshell,当shell1.php上传成功后,利用时间差客户端立刻访问该php确保能够生成webshell(可以配合burp不断发送上传包,同时浏览器不断访问shell1.php即可)
PASS18
白名单+条件竞争。代码逻辑:上传上来,做后缀、大小等各种判断后,再重命名
绕过方法
上传一个白名单多后缀PHP文件,配合Apache解析漏洞, 不断重放会成功上传而没有被重命名
PASS19
上传后保存的文件名完全可控,源码中未处理大小写
可以大小写绕过,可以利用00截断(CVE-2015-2348 https://www.cnblogs.com/cyjaysun/p/4390930.html),可以利用move_uploaded_file忽视"/."
PASS20
审计
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//检查MIME
$allow_type = array('image/jpeg','image/png','image/gif');
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//检查文件名
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
if (!is_array($file)) {
$file = explode('.', strtolower($file)); //save_name参数如果不是数组,就用"."拆分为数组
}
$ext = end($file);
$allow_suffix = array('jpg','png','gif');
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}else{
$file_name = reset($file) . '.' . $file[count($file) - 1]; //reset表示将数组指针移到首位
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$msg = "文件上传成功!";
$is_upload = true;
} else {
$msg = "文件上传失败!";
}
}
}
}else{
$msg = "请选择要上传的文件!";
}
审计可知,先判断MIME类型,其再获取save_name,不为数组直接以".“拆分为数组,随后取数组最后位置元素为扩展名,但是重命名文件名时使用了$file[count($file) - 1],因此绕过方法即为让save_name[0] = test.php 、save_name[2] = jpg ,则count($file)值为2,$file[count($file) - 1]即为$file[1],为空,最后拼接文件名为"test.php.",利用多后缀解析即可。
也可以利用move_uploaded_file忽视”/.“绕过,落地后文件名即为shell.php
整理
可解析后缀
asp/aspx语言:asp、aspx、asa、asax、ascx、ashx、asmx、cer php语言:php、php5、php4、php3、php2、phtml、pht jsp语言:jsp、jspa、jspx、jsw、jsv、jspf、jhtml
中间件漏洞
IIS
IIS 6.0 文件解析 xx.asp;.jpg IIS 6.0 目录解析 xx.asp/1.jpg IIS 7.5 畸形解析 xxx.jpg/x.php Apache
%0a (CVE-2017-15715) 多后缀解析 test.php.xxx nginx
访问链接加 /xxx.php,即 test.jpg/xxx.php 畸形解析漏洞 test.jpg%00xxx.php CVE-2013-4547 test.jpg(非编码空格)\0x.php
tomcat(需要配合Windows特性)
xxx.jsp/ xxx.jsp%20 xxx.jsp::$DATA
系统特性
Windows 下 ADS 流特性,导致上传文件 xxx.php::$DATA = xxx.php Windows 下文件名结尾加入.、空格、<、>、»>、0x81-0xff等字符,最终生成的文件均被会被Windows 忽略
防御
- 文件上传目录设置为不可执行(文件上传后做独立存储,做静态文件处理):web容器无法解析该目录下的文件
- 通过白名单判断文件类型(图片可以做压缩和resize处理,破坏其中的可能包含的html或php代码)
- 使用随机随改写文件名和文件路径(攻击者不知道路径和改写后的文件名就无法直接访问该文件)