参考文章 https://xz.aliyun.com/t/2657
https://xz.aliyun.com/t/4029#toc-16
0x00前言
之前再suctf比赛中的一题中遇到了 exif_imagetype() 这个的问题 后面发现 这个文件上传靶场有提到 这个靶场之前只做了一部分 后半部分 看了一下write up便草草了事 .... 其实这样他根本不过脑啊! 还是要自己做一遍 总结一下才行 所以便有了今天的这篇总结文章
0x01正文
# pass 01
上传一个php之后发现是前端js的判断 所以只要把js禁用就行 或者用burp进行改包
# pass 02
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}
}
Code language: PHP (php)
可以从源码中看出 这里只校验了 content - type
所以只要burp进行修改就可以了
# pass 03
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$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); //收尾去空
if(!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
Code language: PHP (php)
这里可以根据浏览器的解析原理 把后缀改成 jsp jspx jspf
asp asa cer aspx
php php php3 php4
exe exee
都是可以的
# pass 04
通过源码我们可以看到 这里对所有的后缀都进行了限制 所以这里我们使用 .htaccess
<FilesMatch "test">
SetHandler application/x-httpd-php
</FilesMatch>
Code language: HTML, XML (xml)
这样我们之后上传一个 test.jpg文件 服务器就会把这个文件解析成 php
# pass 05
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
Code language: PHP (php)
可以看出来这里 没有对大小写进行约束 所以我们这里可以通过大小写来进行绕过
# pass 06
这题 由于没有对 空格进行绕过 由于在windows下 test.php空格 是不允许存在的所以会自动删除 还有一种情况就是 test.php. 所以在这里我们只需要上传一个 test.php 然后在burp中进行修改 成 test.php空格 就可以了
# pass 07
原理同上类似 这里是利用 test.php. 来进行绕过的
# pass 08
这里我们利用windows 的流文件来进行绕过
(1)上传不符合windows文件命名规则的文件名
test.asp.
test.asp(空格)
test.php:1.jpg
test.php::$DATA
shell.php::$DATA…….
会被windows系统自动去掉不符合规则符号后面的内容。
不过这个只使用于windows的系统 所以我们在上传的时候 test.php::$DATA
这样就可以绕过了
# pass 09
这题我们使用 .空格.来进行绕过
# pass 10
一个常见的绕过方法 双写来进行绕过 test.pphphp
# pass 11
这题按照思路的话是通过 %00 进行截断的 但是我这里由于是环境的问题 我尝试之后显示上传错误 所以这题需要后续进行研究
# pass 12
将get 改成post
ps 前面的写的比较简略后面会写的比较详细
# pass 13
根据提示我们使用图片马 结合文件包含漏洞来进行上传
直接将图片马进行上传
然后通过include.php 文件进行文件包含
所以这关的思路就是通过上传一句话木马图 然后通过文件包含漏洞来使得后面的图片可以解析
# pass 14
同上
# pass 15
同上
上面两题其实都是检测文件 是否是图片 所以我们使用一句话木马可以绕过 但是还有一个方法就是
不同的图片文件都有不同文件头,如:
PNG:文件头标识(8字节)89 50 4E 47 0D 0A 1A 0A
JPEG:文件头标识(2字节):0xff,0xd8(SOI)(JPEG文件标识)
GIF:文件头标识(6字节)47 49 46 38 39(37)61
PHP使用和getimagesize函数验证图片文件头
绕过方式
绕过这个检测只需要在恶意脚本前加上允许上传文件的头标识就可以了
在木马内容基础上再加了一些文件信息,有点像下面的结构
GIF89a <?php phpinfo (); ?>
我们利用GIF89a 来伪造图片文件头来进行绕过
# pass 16
通过二次渲染来进行绕过 我们之前的一句话木马的php <? php phpinfo();?>这句话是在最后面的 但是在这里当我们上传上去的时候图片 最后的一句话木马没有了 这篇文章说的很好 https://xz.aliyun.com/t/2657
# pass 17,18
条件竞争 这里参照 https://xz.aliyun.com/t/4029#toc-16 这篇文章
# pass 19
通过 /.进行绕过
# pass 20
<?php
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//检查MIME
$allow_type = array('image/jpeg','image/png','image/gif'); // 通过检查 mime 类型来进行判断
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//检查文件名
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name']; // 如果 save name 是空的 那么就通过 files函数来进行上传 如果不是空的那么就通过post 进行传递
if (!is_array($file)) {
$file = explode('.', strtolower($file));
} // 这是一个if 判断语句 如果不是数组就把它变成数组
// 所以如果我们上传的是数组 那么就可以
$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 = "请选择要上传的文件!";
}
?>
Code language: HTML, XML (xml)
先放上源代码
这里如果我们通过上传数组 会跳过$file = explode('.', strtolower($file));
从而构造我们想要的数组
首先我们通过代码可以看出来 这里首先对mime类型进行了一个白名单的检测 还有一个就是对文件的后缀进行了白名单的检测
$file_name = reset($file) . '.' . $file[count($file) - 1];
这个代码比较关键是一个突破口 前面 reset($file) reset 函数就是把数组指向第一个 简单的来说就是文件名 count也就是统计文件有几部分 如果我们上传 test.php 该文件有两部分 所以 最终也就是 file[1] 也就是 php 所以后面这个通俗的来说就是获取文件名的后缀 这里的构造比较巧妙
利用数组 来进行绕过 首先由于 文件后缀有白名单的限制 所以我们需要让数组的最后一个为jpg png 或gif 所以利用save_name[2] 内容为jpg 进行绕过 白名单 因为 end是获取数组的最后一个元素 这里也就是数组save_name的最后一个 也就是我们输入的jpg
又由于 $file[count($file) - 1]; 我们的数组有三部分 所以这里返回的是 file[2]为空 所以最终结果就变成
smile.php/. 然后/. 被忽略从而使得文件上传成功