目录
pass-11

分析源代码 ,发现上传文件的存放路径可控
php
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类型文件!";
}
}
抓包查看,利用%00截断

save_path=../upload/修改为save_path=../upload/web.php%00
抓包后的信息可以看见有save_path,说明路径可控。我们通过修改路径令
save_path: ../uploads/web.php%00
,然后上传一个文件后缀为.jpg
的phpinfo
文件,代码处得到的后缀为jpg,能够通过对文件后缀的检测,$img_path
变量为../uploads/info.php%00+随机日期.jpg
,当执行move_uploaded_file
函数时,服务器会对路径中%00后的内容不做解析,默认迁移文件为../uploads/web.php
。

结果

漏洞点:文件上传路径可控,利用%00截断
pass-12

php
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类型文件!";
}
}
分析代码发现11关是get传参,本关是post传参,
二者区别
在GET请求中会对输入的内容进行URL解码。但POST请求有不同,因为在上传表单中存在一个enctype的属性,而且在enctype="multipart/form-data"这里,是不会对表单中的数据进行解码的,需要我们将POST中的%00解码后传入。

再web.php后面的%00进行url解码



成功
pass-13

本关设计文件包含漏洞
需要上传图片马
制作图片马
php
copy a.png /b + 1.php /a webshell2.png
应该包含如下内容

接着直接上传图片,然后我们通过文件包含漏洞进行解析文件。该文件包含解码通过get传参,我们复制图片地址,链接到文件包含界面,然后访问。

成功
pass-14
同13关,直接上传我们的图片马即可

pass-15
同13关

pass-16

同样,我们尝试上传图片马
发现上传成功,但是访问文件发现并没有执行我们的php脚本
查看源代码
php
if(move_uploaded_file($tmpname,$target_path)){
//使用上传的图片生成新的图片
$im = imagecreatefromgif($target_path);
if($im == false){
$msg = "该文件不是gif格式的图片!";
@unlink($target_path);
}else{
//给新图片指定文件名
srand(time());
$newfilename = strval(rand()).".gif";
//显示二次渲染后的图片(使用用户上传图片生成的新图片)
$img_path = UPLOAD_PATH.'/'.$newfilename;
imagegif($im,$img_path);
@unlink($target_path);
$is_upload = true;
}
发现图片进行了二次渲染。
针对二次渲染,我们的方法是利用beyond compare工具,进行上传前和上传后的16进制对比,找出相同的位置插入我们的脚本代码,接着重新上传该图片。


访问图片,成功

当然,还可以尝试利用jpg和png格式的图片
pass-17

上传我们的php文件,发现上传失败
查看源代码
php
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
<?php file_put_contents('../web.php','<?php phpinfo();?>');?>
创建的路径在上一级路径防止被删除
可以利用bp一边进行竞争,一边进行访问


访问文件

成功。
pass-18

上传图片,发现upload中没有该图片,而是在上一级目录中


我们上传图片马,然后可以利用文件包含。

成功。
pass-19

本关可以利用大小写绕过或者/.绕过
大小写绕过

直接将web.php改为web.phP
当然利用/.也可以,生成一个一句话木马的脚本改为jpg类型上传

然后bp抓包修改保存的文件名即可

修改为

查看文件

上传成功
pass-20

源代码分析
php
if (file_exists(UPLOAD_PATH)) {
$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
//mime check
$allow_type = array('image/jpeg','image/png','image/gif');
if(!in_array($_FILES['upload_file']['type'],$allow_type)){
$msg = "禁止上传该类型文件!";
}else{
//check filename
$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 = "请选择要上传的文件!";
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
分析代码
php
empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
如果save_name为空,则把$_FILES['upload_file']['name']
赋值给file,反之`_POST['save_name']`赋值给$file
php
if (!is_array($file)) {
$file = explode('.', strtolower($file));
}
如果$file不是数组,则将其处理为数组,通过.
符号将其分割 [ "muma.php","","jpg"]
php
$ext = end($file); //文件后缀
$allow_suffix = array('jpg','png','gif');
if (!in_array($ext, $allow_suffix)) {
$msg = "禁止上传该后缀文件!";
}
end()
函数获得file中的最后一个元素,赋值给ext,并进行后缀校验
php
}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 = "文件上传失败!";
}
后缀符合,则拼接文件名为首元素.尾元素
reset()
获取数组首元素
因此我们可以修改数组,上传php文件,后缀名改为jpg
抓包查看一下

我们需要的是web.php,可以试着将数组传为save_name=["web.php"," ","jpg"]
,当我们save_name[1]不设置的时候,count结果仍然是2,但是文件名后缀拼接出来为空,结果为web.php. 再根据windows特性将.
省略,从而上传文件。
我们可以构造数组
php
------geckoformboundary55e8518e38caa5df9e9d15a4791fe8bd
Content-Disposition: form-data; name="save_name[0]"
web.php
------geckoformboundary55e8518e38caa5df9e9d15a4791fe8bd
Content-Disposition: form-data; name="save_name[2]"
jpg
修改为如下内容


上传成功。

访问文件

至此upload-labs靶场实验实例完成。