赞
踩
1、拉取upload-labs镜像:
docker pull c0ny1/upload-labs
2、创建docker容器:
docker run -d -p 81:80 c0ny1/upload-labs
-p:意为端口映射,格式为 宿主机端口:容器端口。
由于我的Linux的80端口已占用,所以服务映射到闲置的81端口。
3、查看容器的启动情况:
浏览器访问IP:814、upload文件夹创建
没有文件夹会出现报错,即使上传合法的文件也是报错。
a、进入upload-labs容器:
docker exec -it [CONTAINER ID] /bin/bash
#查看CONTAINER ID命令docker ps
b、创建upload文件夹:mkdir upload
c、 给upload赋权限:chmod 777 upload
靶场搭建完成
上传js.png抓包修改为js.php
上传成功右键打开图片链接
上传222.php,修改content-type为图片类型:image/jpeg、image/png、image/gif
上传设置了黑名单,可以通过上传其他可解析文件,.phtml .phps .php5 .pht
前提是apache的httpd.conf中有配置代码
$deny_ext = array('.asp','.aspx','.php','.jsp');
抓包修改后缀为php5
黑名单过滤了尽可能可以解析的文件后缀,除了.htaccess
$file_ext = strtolower($file_ext); //转换为小写
因此先上传一个.htaccess文件,内容如下:
SetHandler application/x-httpd-php
把文件都会当成php来解析
接下来直接上传文件内容为一句话木马的正确类型文件,比如222.png
同样过滤一堆黑名单
$deny_ext = array(".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");
与四不同的是没有将其后缀转换为小写
因此可以使用大小绕过
上传555.PHp
访问555.PHp
代码对后缀进行了大小写处理
文件名最后增加空格,写成666.phpx(x表示空格),上传后保存在系统上的文件名最后的一个空格会被去掉,实际上保存的文件名就是666.php
上传666.php抓包修改后缀为666.phpx(x表示空格),
访问木马文件
$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".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",".ini"); $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)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '此文件类型不允许上传!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }
代码没有对后缀名末尾的点进行处理,自此会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过:
上传222.png抓包修改为222.php.
执行成功
$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".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",".ini"); $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)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '此文件类型不允许上传!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }
没有对后缀名中的’::$DATA
’进行过滤。在php+windows的情况下:如果文件名+"::$DATA
“会把::$DATA
之后的数据当成文件流处理,不会检测后缀名.且保持”::$DATA
"之前的文件名。利用windows特性,可在后缀名中加” ::$DATA
”绕过,文件名改成222.php::$DATA
,上传成功后保存的文件名其实是222.php:
上传成功,执行
访问文件/upload/202204012129209841.php,去掉::DATA
$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".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",".ini"); $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)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '此文件类型不允许上传!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }
代码先是去除文件名前后的空格,再去除文件名最后所有的.,再通过strrchar函数来寻找.来确认文件名的后缀,但是最后保存文件的时候没有重命名而使用的原始的文件名,导致可以利用1.php. .(点+空格+点)来绕过
A:如果上传符合类型的文件抓包修改为.php. .
B:直接上传php文件抓包修改为.php. .
效果都是一样的,直接访问木马文件即可
$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess","ini"); $file_name = trim($_FILES['upload_file']['name']); $file_name = str_ireplace($deny_ext,"", $file_name); $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }
黑名单过滤,将黑名单里的后缀名替换为空且只替换一次,
绕过原理:
上传文件的后缀名凡是符合黑名单中任意一个后缀都会被替换为空,那么我们可以利用双写后缀的方式进行绕过。所以pphpph中间的php就被抹去了,剩下php达到木马文件后缀的要求。
会有两个文件生成
访问木马文件
$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类型文件!"; } }
白名单判断,但$img_path是直接拼接,因此可以利用%00截断绕过。
%00和0x00:
0x00是十六进制的0
%00是url加密,是url的终止符
当程序在输出含有chr(0)变量时,chr(0)后面的数据会被停止,换句话说,就是误把它当成结束符,后面的数据直接忽略,这就导致漏洞产生的原因。
截断条件:php版本小于5.3.4,php的magic_quotes_gpc为OFF状态
执行
$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类型文件!"; } }
与上一题不同的就是post方式传递,还是利用00截断,因为POST不会像GET对%00进行自动解码,所以需要在二进制中进行修改。
function getReailFileType($filename){ $file = fopen($filename, "rb"); $bin = fread($file, 2); //只读2字节 fclose($file); $strInfo = @unpack("C2chars", $bin); $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); $fileType = ''; switch($typeCode){ case 255216: $fileType = 'jpg'; break; case 13780: $fileType = 'png'; break; case 7173: $fileType = 'gif'; break; default: $fileType = 'unknown'; } return $fileType; } $is_upload = false; $msg = null; if(isset($_POST['submit'])){ $temp_file = $_FILES['upload_file']['tmp_name']; $file_type = getReailFileType($temp_file); if($file_type == 'unknown'){ $msg = "文件未知,上传失败!"; }else{ $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type; if(move_uploaded_file($temp_file,$img_path)){ $is_upload = true; } else { $msg = "上传出错!"; } } }
通过读文件的前2个字节判断文件类型,也就是绕过文件头检查,添加GIF图片的文件头GIF89a,绕过GIF图片检查。也可制作图片马:
copy 212.jpg /b + 222.php /a 444.jpg
直接上传
但是不能把图片当做PHP解析,因此还需要利用文件包含漏洞
访问用于测试图片
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。