目录
(1)首先当然是需要phpstudy的环境,所以要先下载安装phpstudy。
(2)然后到github的网址中下载源码的压缩包。
github网址:https://github.com/Tj1ngwe1/upload-labs
(3)下载后解压缩到phpstudy目录下的WWW子文件夹中,这里要注意把压缩包的名字改成upload-labs,不然靶场的页面会显示得不对。
(4)然后在输入url HTTPS://127.0.0.1/upload-labs/就可以访问靶场。
通关时对后缀名单操作可通过burp抓包实现。
Pass-01
首先观察页面,需要上传一个文件。我们先尝试进行上传。
发现页面进行了提示,根据提示信息我们知道上传的途中对文件的后缀名进行了验证。 用弹窗进行错误提示的话证明是运用了前端验证。
这时我们有几种不同的解决办法。
(1)首先第一种,F12找到验证部分的代码,然后删除,就可以上传。
(2)第二种方法是增加要上传的文件类型,跟第一种方法一样,也是找到代码所在位置进行修改即可。
(3)第三种方法是我们先将要上传的文件后缀名修改成页面允许上传的类型,这样在点击上传后就可以通过前端的验证,用burp工具进行抓包,在burp中将文件后缀名改回原本想要上传的格式,再进行上传,这样就可以上传我们想要的类型文件而不会被前端的验证拦截。
这里代表上传文件成功。
上传的文件在upload目录下。(如果没有的话在WWW中的upload-labs里自己手动建一个,不然会报错),最终上传的文件为html类型的文件。
Pass-02
进入页面发现还是需要上传一个文件,我们先上传看看回显情况。
上传了一个文件名后缀为.php的文件后提示类型错误,错误回显的方式不是弹窗,是页面直接提示,所以不是前端验证。查看一下源码。
$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists($UPLOAD_ADDR)) { if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) { $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name']; $is_upload = true; } } else { $msg = '文件类型不正确,请重新上传!'; } } else { $msg = $UPLOAD_ADDR.'文件夹不存在,请手工创建!'; }}
其中如图中框住的代码部分可以看出,上传文件的途中是验证了content-type,并且固定了可以上传的文件类型。关于content-type的相关信息可以参考这篇博客。
(1条消息) Http中Content-Type的详解_阿祥小王子的博客-CSDN博客_content-type
接下来要绕过就很简单了,我们只需要用burp工具抓包,抓到之后修改content-type的类型为允许上传的类型即可,也就是判断语句中写到的类型。注意有两个content-type,不要改错。
上传文件成功。
Pass-03
本关依旧是要上传一个脚本文件,我们查看源码。
$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists($UPLOAD_ADDR)) { $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)) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR. '/' . $_FILES['upload_file']['name'])) { $img_path = $UPLOAD_ADDR .'/'. $_FILES['upload_file']['name']; $is_upload = true; } } else { $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!'; } } else { $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!'; }}
从源码中我们可以看出设定了黑名单,'.asp','.aspx','.php','.jsp'后缀的文件都不允许上传,并且会检查大小写、删除点和空格。
想要绕过黑名单可以使用脚本的其他拓展名。
这里我想要上传一个'.php'后缀的文件,所以列举一些php文件的其他拓展名。
.php .phtml .phps .php5 .pht
修改拓展名再进行上传即可上传成功,上传文件的位置依旧是upload文件夹。
Pass-04
观察源码,我们发现这次黑名单限制更多了,基本更改其他拓展名进行绕过基本没戏,需要我们换一种思路。
$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists($UPLOAD_ADDR)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".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"); $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)) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) { $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name']; $is_upload = true; } } else { $msg = '此文件不允许上传!'; } } else { $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!'; }}
可以选择通过'.htaccess'文件进行绕过。
'.htaccess'文件相当于一种部分配置文件,好比局部变量一样,只在当前目录生效。比如你设置解析'.txt'解析为'.php',那么'.htaccess'文件在的子目录中就会执行,而上一级目录不执行。
使用前需要在Apache的配置文件中进行两步配置。
AllowOverride All
LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so
创建'.htaccess'文件,然后在其中写入代码,使得文件在解析时将'.jpg'文件解析为'.php'文件,代码如下。
SetHandler application/x-httpd-php
在上传时我们只需要将文件后缀名改为'.jpg',访问时会自动被执行为'.php'文件。
Pass-05~Pass-07
5~7关通关的思路是一样的,首先观察源码,能看到原本的限制因素减少,且限制了'.htaccess'文件类型。比如原本1~4关强制小写,但第5关去掉了强制小写的代码。
05 - 本关从源码可看出没有了大小写的限制,所以我们可以对后缀名进行大小写混合如将'test.php'改写为'test.Php',以此绕过黑名单。
$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists($UPLOAD_ADDR)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) { $img_path = $UPLOAD_ADDR . '/' . $file_name; $is_upload = true; } } else { $msg = '此文件不允许上传'; } } else { $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!'; }}
06 - 本关从源码可以看出没有了删除空格的代码,所以可以在文件后缀名末尾加空格,如'test.php'改写为'test.php ',windos在存储时会自动去处空格,但在检测时可以绕过黑名单限制。
$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists($UPLOAD_ADDR)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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 if (!in_array($file_ext, $deny_ext)) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) { $img_path = $UPLOAD_ADDR . '/' . $file_name; $is_upload = true; } } else { $msg = '此文件不允许上传'; } } else { $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!'; }}
07 - 本关源码中没有删除文件末尾点的代码,所以可以在文件后缀名后加点,如'test.php'改写为'test.php.',并且和06一样,Windows存储时也会自动去除后缀名末尾的点,但检测时可绕过黑名单。
$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists($UPLOAD_ADDR)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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_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_ADDR . '/' . $_FILES['upload_file']['name'])) { $img_path = $UPLOAD_ADDR . '/' . $file_name; $is_upload = true; } } else { $msg = '此文件不允许上传'; } } else { $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!'; }}
Pass-08
本关原理参考05~07,但是这里缺少的限制类型是::$DATA类型。
当php在windows环境的时候,如果文件名+ “::$DATA" 会 把 "::$DATA" 之后的数据当成文件流处理,不会检测后缀名.且保持"::$DATA"之前的文件名
所以最终‘test.php’改写为'test.php::$DATA',并且在存储时存储的文件名为'test.php'。
Pass-09
本关通过查看源码发现,不仅黑名单奇长无比,且限制了'.htaccess'文件类型。这时我们理解代码的含义,发现首先会去处文件名末尾的点,然后首尾去空。
我们可以利用这样的检验机制,首先我们在文件后缀名后添加一个点,希望最终以此来绕过黑名单检测,但是因为存在去除文件名末尾的点的代码,所以我们需要不止一个点,注意我们用来绕过黑名单的点显然不能够被消除,所以要在他后面放一个东西防止他落在最后一位。我们看到收尾去空的代码在去点代码之后,所以用空格来充当占位符号。
最终‘test.php’改写为'test.php. .',即可实现绕过黑名单。
$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists($UPLOAD_ADDR)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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 = trim($file_ext); //首尾去空 if (!in_array($file_ext, $deny_ext)) { if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) { $img_path = $UPLOAD_ADDR . '/' . $file_name; $is_upload = true; } } else { $msg = '此文件不允许上传'; } } else { $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!'; }}[点击并拖拽以移动]
Pass-10
注意这句代码,这句代码的意思是,所有与黑名单相同的后缀名都会被替换为空。利用这一特点,我们可以进行双写后缀名操作,即加一个后缀名让他替换掉,如‘test.php’改写为'test.pphphp'当后缀名被替换掉后会变成空格,可以绕过黑名单的检测,但是存储时空格会被去掉,最后剩下的文件后缀名合并为'test.php'。
Pass-11~Pass-12
这两关采用的是一个原理:00截断。
0x00,%00这两类截断都是属于同种原理,%00在url解码后为空字符,0X00即16进制的00。在解析后这两个内容都会被当做chr(0)来处理。
chr()函数的作用:返回括号中的参数所代表的字符。
chr(0)代表的含义是返回ASCII码中0代表的字符,也就是NULL。
当一个字符串中存在空字符的时候,在被解析的时候会导致空字符后面的字符被丢弃。
而当传参方式为GET则需要使用%00,因为GET传参时url会自动编码,转移为空字符;而POST型传参时则不会进行自动编码,所以需要使用0x00进行截断。
00截断的使用条件:
(1)php版本要小于5.3.4。
(2)文件路径可控。
(3)magic_quotes_gpc需要为OFF状态。(在php.ini中)
11 - 传参方式为GET型,且传参路径可控,将文件改名为phpinfo.jpg后,抓包修改savepath,存储后存储路径会和文件名称合并,最终形成文件名为'phpinfo.php%00phpinfo.jpg'。
12 - 传参方式为POST,使用0x00进行截断,方法同上。
Pass-13~Pass-16
需要引进一个新的概念:图片一句话木马。
具体的原理可以参考:upload-labs-master Pass1-20笔记_skynet_x的博客-CSDN博客
感觉写的非常详细了。
制作图片一句话木马:图片一句话木马简单制作方法_TimeOldman的博客-CSDN博客_图片一句话
Pass-17~Pass-18
这两关采用了相同的原理,条件竞争。
观察源码可知,对于上传的文件处理是先保存到服务器,再对比拓展名,如果拓展名不属于白名单中的后缀,便将保存的文件删除。
$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_ADDR . '/' . $file_name; if(move_uploaded_file($temp_file, $upload_file)){ if(in_array($file_ext,$ext_arr)){ $img_path = $UPLOAD_ADDR . '/'. rand(10, 99).date("YmdHis").".".$file_ext; rename($upload_file, $img_path); unlink($upload_file); $is_upload = true; }else{ $msg = "只允许上传.jpg|.png|.gif类型文件!"; unlink($upload_file); } }else{ $msg = '上传失败!'; }}
这里注意到先保存再进行删除,也就是说有很短的一段时间这个文件是被保存并且可以访问的,我们利用这个先后顺序的中间差时间进行访问,访问到文件即可执行代码。
因为时间差很短,所以我们使用脚本进行访问即可。
import requestsurl = "http://192.168.159.128/upload-labs-master/upload/eval.php"while True: html = requests.get(url) if html.status_code == 200: print("OK") break
17 - 因为这里没有做验证图片真伪的验证,所以直接使用'.php'文件进行上传即可。
18 - 这里需要上传的文件为图片一句话木马类型,其余步骤跟17一致。
Pass-19
其实这里也是一种黑名单绕过方式,这里有一个新的函数
这个函数的特点是上传时会忽略/.,也就是说可以通过这一点更改文件后缀名,进行黑名单绕过。
如'phpinfo.php'改写为'phpinfo.php/.'即可绕过。
因为是边学习边写博客,所以借鉴了许多网上的博客内容,也有许多不够清晰的地方,如果有不正确的地方欢迎指正~
给大家推荐一篇个人觉得非常棒的参考博客,写的很详细也很有条理。
upload-labs-master Pass1-20笔记_skynet_x的博客-CSDN博客
来源地址:https://blog.csdn.net/K_ShenH/article/details/122438998