关于靶场说几点:单纯用phpstudy 可能无法复现所有的漏洞,而且phpstudy中的php可能是线程不安全的,所以建议大家在自己本机或者虚拟机的中亲自搭建一下apache和php的环境,便于复现upload-labs的所有靶场环境。配置有问题的可以参考我写的这篇文章:
https://blog.csdn.net/qq_51550750/article/details/124062273
pass12-环境说明:
这一关啊真是奇葩,试了一圈,只有php版本是下面这个才成功:5.5.9nts
如果你也没有成功,也看看这个这个版本你行不行吧。
其实 upload-labs这个靶场要是实在做不出来也没有关系,因为牵扯到环境问题,还牵扯到php的版本问题。没做出来要放弃也很正常,不用灰心。
pass12-源码提示
源码:
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
提示:
源码中,限制了文件名(白名单,‘jpg’,‘png’,‘gif’)
再注意一下上传的路径:
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
有一个参数是save_path
上传抓包:
上传shell.php
看到save_path在URL中的路径,其实提示中说的“路径可控”就是这个意思。
在这个请求头中,可以看到一个比较特别的字段:
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
介绍一下Content-Disposition这个字段
首先学习安全的小伙伴们一定对于Content-Type这个字段很熟悉。在客户端,发送Content-Type这个字段是告诉服务器应该响应给客户端什么字段,在服务端,这个字段的发送就是告诉客户端应该以什么格式去解析数据包。
而Content-Disposition这个字段其实是作为对下载文件的一个标识字段。
可以看一下firefox网站对于这个字段的说明:
Content-Disposition这个字段简单来说就是:当浏览器弹出一个下载框的时候,会给出一个文件名。比如在服务器上放置了一个文件,通过Content-Disposition去响应给浏览器,指定文件名叫做1.txt,打开保存框的时候,文件名就是1.txt。
但是看到我们包中的这个字段,是放在请求中使用的。
Content-Disposition: form-data; name=“upload_file”; filename=“shell.php”
前面有一个保存路径,后面有一个文件名,估计filename会用来做白名单的校验,“…/upload/”会用来做实际的文件保存。
如何绕过?
1.将shell.php改成shell.png(或者其他图片的格式,在白名单中的格式)
2.路径“…/upload/”改成“…/upload/shell.php”
这时候会有一个问题:路径会和文件名进行拼接,变成:“…/upload/shell.php/shell.png”
那不就会有问题吗?
其实pass12和pass13都要用到一个知识点:
文件名截断
什么是文件名截断?
简单来说,就是在文件名最后加上一些特殊的字符或者控制字符,当程序遇到这个字符的时候,就会认为字符串结束了,后面的会跳过忽略。
所以我们在pass12这一关中,可以这么做:在文件名之后加一些特殊的字符,再拼接一些在白名单之中的后缀。
因此,我们就可以绕过白名单,又能使得一些特殊控制字符使无效而最终保存在靶机上的是我们想要的文件名。
截断字符:
chr(0),类似于C++的"\0"
filename=test.php%00.txt -------------- filename=test.php
URL encode | ASCII value |
---|---|
%00 | 0 |
在很多编程语言(比如java,PHP)中,ASCII中的0都是作为字符串的结束符号来看待的。
产生这个字符:
特别注意:这一关的路径实在URL中的,所以需要对0进行URL编码
所以最后我们应该这么改正:
上传之后,貌似是成功了:
但是我查看文件路径的时候非常奇怪:
而且是404页面:
尝试访问:
/upload-labs/upload/shell.php
是可以的。
尝试连接蚁剑:
没有问题。pass12就可以了
pass13-源码和提示
第13关其实和第12关是同一组。
源码:
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传失败";
}
} else {
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
提示:
提示和pass12是一样的。源码好像也是一致的。
具体区别通过下面的文件上传来抓包获取:
pass13-文件上传和抓包
上传文件之前我先把自己环境的已经上传的文件清除了:
然后开始上传shell.php并且抓包。
一抓包就能看到区别:
可以看到保存路径和文件名都放在了Content-Disposition中。
按照上一关的套路,应该进行差不多的修改。
特别注意这里应该写十六进制的%00
利用Hex这个模块
首先用+进行占位(注意+的十六进制是2b)
然后切换到Hex将其改为00
改之前:
改之后:
再回到Raw中,注意,看起来没有其实是有的。
最终的效果是:
放包。
上传成功。
然后连接webshell
Pass也成功了。
pass1-pass13总结
pass | 绕过姿势 |
---|---|
1 | 前端绕过 |
2 | Content-Type |
3 | 等价扩展名 |
4 | .htaccess文件 |
6 | 大小写过滤不全面,一样大小写绕过 |
7 | 扩展名最后加一个空格 |
8 | 扩展名最后加一个点 |
9 | 扩展名最后加上::$DATA |
10 | 扩展名最后加上点空点 |
11 | 双写文件扩展名 |
12 | 文件名截断(URL)%00 |
13 | 文件名截断(HEX)加号[2b]占位再改为00 |
欢迎关注公众号“小东方不败”。写博客不容易,欢迎交流!!