之前想总结一下文件上传的类型,于是找到了upload-labs,记下了解题思路和一些知识点,如果有错误或遗漏还望师傅们指点

Pass-01(客户端JS绕过)

客户端JS判断方法:上传一个php文件,用bp抓包,如果没抓到包就弹框说不能上传,就说明是客户端JS检测

客户端JS绕过方法:
方法一:

上传一个图片马格式为jpg,然后bp抓包,将格式改为php

方法二:

攻击JS代码:查看网页元素找到那一段JS代码删除掉

Pass-02(MIME类型验证)

MIME类型验证实质就是检测Content-Type头,先bp抓包

方法一:

上传一个jpg格式图片马,将后缀在bp中改为 php ,因为上传的是jpg格式文件,所以Content-Type
内容是image/jpeg,能通过MIME验证,而我们将后缀改为了php,所以成功上传了php文件


方法二:

直接上传php格式图片马,bp抓包发现Content-Tpye内容为application/octet-stream,将其改为image/jepg,这样bp中的内容就和方法一一样,能够成功上传

Pass-03(绕过黑名单验证)

上传jpg格式图片马bp抓包,然后改后缀为php发现不能上传,给了一个提示

考虑大小写绕过,发现大小写都被过滤了,再考虑黑名单里面没有的,比如php3,phpml,ph4,发现上传成功

Pass-04(.htaccesss上传)

一样开始的操作,发现提示该类文件不运行上传,尝试大小写绕过,无果
尝试采用黑名单没有的,例如php3这种,无果,试一下.htaccess上传,发现上传成功

尝试访问一下

.htaccess文件介绍:

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能

.htaccess上传方法:

1.新建一个txt文本,里面内容为SetHandlerapplication/x-httpd-php(意思是设置当前目录所有文件都使用PHP解析,那么无论上传任何文件,只要文件内容符合PHP语言代码规范,就会当做PHP执行。不符合则报错),另存为-文件类型选择所有文件-文件名该为.htaccess,这样才能保存成功

2.保证httpd-conf配置文件里面的AllOverride后面接的是All,如果是None就改为All
上传.htaccess文件成功后直接上传jpg图片马,上传成功,该jpg格式图片马能使用php解析,这样就能菜刀连了

Pass-05(大小写绕过)

开始一样的操作无法上传,试试php3,改一下大小写,发现phP能够绕过上传

Pass-06(空格绕过)

1-5题方法都用了一遍发现都不能成功上传,再试试空格绕过,发现上传成功
空格绕过原理:Windows系统下,对于文件名中空格会被作为空处理,程序中的代码却没添加删除空格功能,从而绕过黑名单

绕过方法:bp抓包,在php后面加上空格,多少个空格无所谓

Pass-07(.号绕过)

.号绕过原理:Windows系统下,文件后缀名最后一个点会被自动去除,所以bp抓包,将文件后缀改为php.这样就能绕过,最后一个点被去除就是php格式

Pass-08(特殊符号绕过)

特殊符号绕过原理:Windows系统下,如果上传的文件名中test.php::$DATA会在服务器上生成一个test.php的文件,其中内容和所上传文件内容相同,并被解析

所以bp抓包,在php后面加上::$DATA,就能上传一个php文件上去

访问一下图片地址,发现2.php::$data文件不存在,因为上传上去的是2.php

访问一下2.php,成功上传

Pass-09(路径组合绕过)

这道题过滤了空格,过滤了后缀最后的点,过滤了特殊符号,过滤了大小写,黑名单内容很详细。。

我们看一下源代码

1
2
3
4
5
6
7
$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); //首尾去空

这道题采用路径组合绕过,bp抓包,将2.php改为2.php. .这样上传上去去掉最后的点,去掉空格,就剩下2.php.而最后的.在Windows系统下会被自动删除于是2.php就上传成功

Pass-10(双写绕过)

将图片马以jpg格式上传,bp抓包改为php格式,发现上传上去了,有点怀疑,访问一下上传的地方

发现上传上去的文件名为2. php被吃掉了,考虑一下双写绕过

将2.php改为2.pphphp,当然也可以结合大小写绕过

访问一下地址,成功上传


Pass-11(GET型00截断)

00截断需要两个条件:

1.php版本小于5.3.4

2.php的magic_quotes_gpc为OFF状态

现在php版本大都没那么低,演示一下过程

上传一个jpg格式图片马,bp抓包,在upload/后面加上2.php%00

Pass-12(POST型00截断)

在POST请求中,%00不会被自动解码,需要在16进制中进行修改00

上传一个jpg图片马,bp抓包,在upload/后面加上2.php空格,如图

进入hex,找到2.php空格,空格对应16进制也就是20,找到20修改为00

Pass-13(图片webshell上传)

上传的图片webshell或者一句话需要利用文件包含漏洞才能执行

文件包含漏洞代码

1
2
3
4
5
6
7
8
9
10
<?php
if($_GET)
{
include($_GET["file"]);
}
else
{
echo "not get args files";
}
?>

做一个文件包含漏洞php文件放入upload中用来检测是否符合要求

查看一下网页源代码发现要检测前两个字节,于是在图片马内容最前面可以加上GIF98A,成功以gif格式上传,附上检测代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
}

利用文件包含内容打开图片马

利用这个链接就可以菜刀连了

Pass-14(图片webshell上传)

可以和13一模一样的做法,能达到效果

Pass-15(图片webshell上传)

和13一模一样,能达到效果

Pass-16(二次渲染)

上传一个gif格式图片马

发现上传成功后的文件末尾的php代码被删去

对于gif格式的二次渲染可以采用对比两个文件,找到未改变的内容

在那中间插入php代码就行

再次上传,发现php代码仍然存在未被删除

用文件包含漏洞验证一下或者菜刀连一下,成功
如果是png和jpg格式的就比较麻烦,需要用到大佬写的脚本,具体参考https://xz.aliyun.com/t/2657

Pass-17(条件竞争上传)

我们先看源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
include '../config.php';
include '../head.php';
include '../menu.php';

$is_upload = false;
$msg = null;

if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;

if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}
?>

发现php文件还是能够上传,但是会被下一步骤unlink删掉,我们可以考虑利用这一步删除的时间差进行上传,bp抓包,发送到Intruder,重发进行上传文件的操作,可以多开几个(多线程)
这样就能看到能够上传,只是上传了就被删除,删除了又出现,但是能够访问

但是我一访问会报错,就是一个一句话木马,不知道哪里错了,还望师傅们指点

Pass-18(条件竞争上传)
和17一样是条件竞争,但是一直上传不上去,考虑可能是白名单,采用上传图片马形式,因为上传上去的文件都会重命名,例如下面一个上传成功的图片,测试多个图片发现前面都被加上了upload,后面是重命名

所以采用条件竞争上传让它来不及改名,上传一个图片马为2.jpg,上传上去未被命名的时候为upload2.jpg,这样上传就成功了

Pass-19(CVE-2015-2348 move_uploaded_file() 00截断)
附上源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

$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","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");

/*
$file_name = trim($_POST['save_name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
*/

$file_name = $_POST['save_name'];
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);

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 . '文件夹不存在,请手工创建!';
}
}
?>

上传webshell,同时自定义保存名称,直接保存为php是不行的,发现move_uploaded_file()函数中的img_path是由post参数save_name控制的,因此可以在save_name利用00截断绕过

先bp抓包,红色的字符串就是将要保存的名字

将其改为1.php空格,在hex中将空格20改为00就能上传成功