环境配置
- 需要的东西
phpstudy-2018
链接: https://pan.baidu.com/s/1D9l13XTQw7o6A8CSJ2ff9Q
提取码:0278
32 位 vc 9 和 11 运行库
链接: https://pan.baidu.com/s/1pBV3W8UWJe0bmDl_cPFDQw
提取码:0278
upload-labs-master 靶场
链接: https://pan.baidu.com/s/1ERYzrlBe94PAi3A-WagLAw
提取码:0278
Burpsuit 安装
官网: Professional / Community 2024.9.5 | Releases
- 上述安装解压后,打开
phpstudy
,点击启动
- 然后在本地浏览器输入
127.0.0.1
打开,显示如下界面表示成功
- 将
upload-labs-master
解压后的整个文件目录复制到.../PHPTutorial/WWW...
,比如我的C:\phpStudy2018\PHPTutorial\WWW
,建议是将整个文件目录复制过来,修改目录名称为upload
(复制整个目录是因为防止文件零散,以后不便于管理)
- 在
upload-labs-master
(重命名的upload
) 根目录下创建upload
文件夹,用来存储我们上传的文件,如果存在就不需要创建了
- 在浏览器输入
127.0.0.1/upload
或者未重命名的127.0.0.1/upload-labs-master
,或者如果不是复制整个目录,而是目录中的文件到上述目录中,直接127.0.0.1
即可
解题思路
- 查看这一关的源码,去上述的
upload
或者未重命名之前的upload-labs-master
目录中,找到 21 关,然后以记事本打开index.php
- 查看源码
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){//检查MIME$allow_type = array('image/jpeg','image/png','image/gif');if(!in_array($_FILES['upload_file']['type'],$allow_type)){$msg = "禁止上传该类型文件!";}else{//检查文件名$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];if (!is_array($file)) {$file = explode('.', strtolower($file));}$ext = end($file);$allow_suffix = array('jpg','png','gif');if (!in_array($ext, $allow_suffix)) {$msg = "禁止上传该后缀文件!";}else{$file_name = reset($file) . '.' . $file[count($file) - 1];$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH . '/' .$file_name;if (move_uploaded_file($temp_file, $img_path)) {$msg = "文件上传成功!";$is_upload = true;} else {$msg = "文件上传失败!";}}}
}else{$msg = "请选择要上传的文件!";
}
解析:
检查的机制
// 这是表示 content-type 类型必须为这几个
$allow_type = array('image/jpeg','image/png','image/gif');// 这是表示保存的文件名如果为空,就使用上传的文件的那个文件名,如果指定了保存的文件名,则使用指定的
$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];// file 如果不是数组,就将其变为数组,以 '.' 为分割,如 file=shell.php,那么就变为 file[0]=shell, file[1]=php
if (!is_array($file)) {$file = explode('.', strtolower($file));
}// 按数组来取,取数组最后一个,如上述的就是php,而它的检查机制是需要是jpg,png,gif
$ext = end($file);
$allow_suffix = array('jpg','png','gif');
漏洞的存在
$file_name = reset($file) . '.' . $file[count($file) - 1];
- 这个就是上述检查都通过后,实际最终的文件名形成,取数组第一个和最后一个拼接
- 如
file[0]=shell
,file[1]=php
,最终形成就是shell.php
- 这也是存在的漏洞,会发现它取的数组最后一个元素,我们考虑利用数组机制来绕过,如何利用呢
利用漏洞
- 由于刚开始不是数组,不是数组就会被上述直接变为数组,我们就直接手动让它变为数组,如何修改呢,是通过抓包修改参数解决
- 如赋值
file[0]=shell.php
,这个是实际的木马源文件,也是我们想上传的,但是由于不是图片类型,content-type
不是满足的类型,通过抓包修改解决。 - 赋值
file[1]=null
,... 以此类推,由于上述会取数组最后一个元素检查拓展名是否在白名单中,因此最后一个如file[5]=jpg
,这个赋值就只需要满足是jpg,png,gif
中一个即可,使其检查通过 - 这样赋值后的数组,就能完美绕过上述的检查,由于
file[1]~file[4]=null
,所以count
函数计算出来的为 2,那么上述的拼接完整文件名部分就会导致取出file[0]=shell.php
,file[2-1]=file[1]=null
,然后会添加一个.
,最终shell.php.
,但实际最后一个.
后没有内容,服务器会直接忽略,也就变成了shell.php
作为服务器端保存的文件名,也就达到了绕过的要求
操作演示
- 准备一个一行木马文件,保存为
shell.php
<?php phpinfo(); ?>
- 打开
Burpsuit
软件,点击open browser
- 在地址栏中输入
127.0.0.1/upload
进入靶场,然后点击pass-21
,选择上传的文件,准备上传(此时不点击上传), 填写保存名称,随意填写,因为后续会通过抓包修改的
- 在
Burpsuite
中,点击intercept is off
变为intercept is on
- 回到靶场,点击上传,然后回到
Burpsuite
,会发现捕捉到了信息,然后找到下面的content-type
修改为满足要求的,如image/jpeg,image/png,image/gif
- 手动将
file
变为数组,修改name=save_name[0]
,变为数组,然后将值修改为shell.php
,然后复制一份,目的填写数组最后一个元素save_name[3]
,修改为png
, 目的是跳过扩展名的检查,由于save_name[1]
,save_name[2]
没有赋值,所以为空,也就是我们思路的那个样子
- 像上述修改后,此时点击左上角的
forward
,让行这个抓包的请求,会发现文件上传成功了,也就是我们绕过了这个检查
- 在浏览器中访问上传文件的路径(不是在那个
Burpsuite
中的那个open browser
打开的地址栏,在本地浏览器中),例如http://127.0.0.1/upload/upload/shell.php
,如果成功执行了 PHP 代码,说明攻击成功。因为我重命名upload-labs-master
为upload
,在这个子目录下的upload
才是上传文件的保存路径,所以写了两个upload