less7
任务
拿到一个shell服务器
提示
禁止上传所有可以解析的后缀
发现所有可以解析的后缀都被禁了
查看一下源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists($UPLOAD_ADDR)) {$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");$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)) {if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {$img_path = $UPLOAD_ADDR . '/' . $file_name;$is_upload = true;}} else {$msg = '此文件不允许上传';}} else {$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';}
}
第六关的源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists($UPLOAD_ADDR)) {$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");$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);//去除字符串::$DATAif (!in_array($file_ext, $deny_ext)) {if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {$img_path = $UPLOAD_ADDR . '/' . $file_name;$is_upload = true;}} else {$msg = '此文件不允许上传';}} else {$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';}
}
通过源码我们发现,第七关少了删除文件名末尾的
$file_name = deldot($file_name) //删除文件末尾的点
第七关没有对末尾的点进行一定的限制,那么就可以用了,在文件的末尾加上一个点看看
上传了3.php,然后在文件末尾加上一个点,文件上传成功
less8
提示
禁止上传.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|.htaccess后缀文件
源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists($UPLOAD_ADDR)) {$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");$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)) {if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {$img_path = $UPLOAD_ADDR . '/' . $file_name;$is_upload = true;}} else {$msg = '此文件不允许上传';}} else {$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';}
}
也是观察的源代码,发现没有对pHp6进行限制,就先上传一个看看,发现是可以的
这个显然有点勉强,从源代码着手看看
与第七关的代码对比一下,这一关没有字符串的限制
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
在文件的末尾加上::$DATA看看eg 3.php::$DATA
less9
ps
只允许上传.jpg|.png|.gif后缀的文件
源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists($UPLOAD_ADDR)) {$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");$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)) {if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {$img_path = $UPLOAD_ADDR . '/' . $file_name;$is_upload = true;}} else {$msg = '此文件不允许上传';}} else {$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';}
}
发现它先将后缀名后的‘.’删除,然后删除空格
先按照提示的上传jpg,是可以的上传的
从代码出发
只过滤了一次点,那么就用上两个点
“点+空格+点”过滤,抓包之后进行修改
eg
3.php. .
也是可以的
less10
ps
从文件名中去除.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|.htaccess字符!
源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists($UPLOAD_ADDR)) {$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");$file_name = trim($_FILES['upload_file']['name']);$file_name = str_ireplace($deny_ext,"", $file_name);if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $file_name)) {$img_path = $UPLOAD_ADDR . '/' .$file_name;$is_upload = true;}} else {$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';}
}
$file_name = str_ireplace($deny_ext,"", $file_name); //这段代码是去除黑名单里面的名称
换句话说就是文件后缀没有了,那么就可以双写绕过,后面也是试了一下pHp6也是可以的
less11
提示
本pass上传路径可控
源代码
$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类型文件!";}
}
1.$ext_arr = array('jpg','png','gif'); 这里使用了数组做了一个白名单,也就是只能上传这三种类型的 文件
2.$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
截取文件名的后缀从点的位置开始截取,并且使用的是循环的方式截取,不是采用 一次性
对($_FILES['upload_file']['name']进行验证,也是对上面代码的进一步验证,限制文件的类型
3. if(in_array($file_ext,$ext_arr)){ 判断上传的文件名后缀是否在白名单中,如果在进入循环。
4. $temp_file = $_FILES['upload_file']['tmp_name']; 进入循环,给上传的文件放在一个临时的目录下,并且生成一个临时文件名
5.$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;(这一步是关键)
使用$_GET['save_path']接受自定义的路径,并且随机从10,99的数组在随机生成一个文件名,
在拼接上$file_Ext 前面截取的后缀名。
6.(move_uploaded_file($temp_file,$img_path)){
最终将前面保存的$temp_file临时文件移动 到$img_path
借鉴一下其他师傅的
原理 :
00截断利用的是php的漏洞,php的基础是C语言实现的,在C语言中认为%00是结束的符号,所以就基础了c的特性,在PHP<5.3.4的版本中,在进行存储文件时碰见了move_uploaded_file这个函数的时候,这个函数读取到hex值为00的字符,认为读取结束,就终止了后面的操作,出现00截断
绕过思路:
首先使用的是白名单,从代码中可以看出他首先对上传的文件名的后缀进行了验证。
所以在第一步上传$_FILES['upload_file']['name'],文件名的时候必须后缀是.jpg.png.gif的格式。绕过后缀名的验证后,进入到循环。最后重点他保存的文件是
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;,由上传路径决定的,原参数$_GET['save_path'],save_path=../upload/。 那么上传路径可控的 。我们就使用%00截断,把上传的路径修改为文件名。最后利用move_uploade_file这个函数发挥出%00截断的功能。
假如我们没有使用%00截断前最终上传的文件名可能是
../upload/ 237298 .png
$_GET['save_path'] rand(10, 99).date("YmdHis") $file_ext;
使用%00截断后
../upload/1.php%00 237298 .png
$_GET['save_path'] rand(10, 99).date("YmdHis") $file_ext;
最后 保存的文件就变成了
../upload/1.php
因为到%00后面的结束了
思路就是要先上传.php类型的 然后%00截断路径,就可以上传成功
less12
提示还是路径可控
源代码
$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类型文件!";}
}
与上一关的差不多,就下面的地方不同
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
POST方法较为特殊,直接在明文中添加%00不会被服务器解码,得将%00进行url编码后再提交
服务器会自动解码
save_path"=../upload/4.php%00
选中%00进行编码
less13
提示
本pass检查图标内容开头2个字节
源代码
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_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;}else{$msg = "上传失败";}}
}
检查的是文件头部信息,通过检查文件的前2个字节,检查上传文件二进制的头部信息,来进行判断文件的类型。所以这一关修改后缀是没有用的
使用图片码进行绕过
第一种方法
将图片用编辑器打开,在最后加上<?php phpinfo();?>,图片还是可以正常打开的
第二种方法
准备好一张图片和一句话木马php文件,将其放在桌面上使用命令去合成
copy 1.png/b + 2.php/a 3.png
做好就可以直接上传,显示上传成功
less14
提示
本pass使用getimagesize()检查是否为图片文件
源代码
function isImage($filename){$types = '.jpeg|.png|.gif';if(file_exists($filename)){$info = getimagesize($filename);$ext = image_type_to_extension($info[2]);if(stripos($types,$ext)){return $ext;}else{return false;}}else{return false;}
}$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){$temp_file = $_FILES['upload_file']['tmp_name'];$res = isImage($temp_file);if(!$res){$msg = "文件未知,上传失败!";}else{$img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").$res;if(move_uploaded_file($temp_file,$img_path)){$is_upload = true;}else{$msg = "上传失败";}}
}
首先知道函数的意思
getimagesize() 函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息
array getimagesize ( string $filename [, array &$imageinfo ] )
getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型及图片高度与宽
$info = getimagesize($filename);
如果上传的文件是php格式就得不到图片的尺寸,就会返回错误,后面的代码就无法执行,文件就没办法成功上传
结合任务
上传一个图片马
到服务器,所以上传刚刚做好的图片码看看
include.php?file=/upload/图片的链接,就可以查看了
less15
提示
本pass重新渲染了图片
源代码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径$filename = $_FILES['upload_file']['name'];$filetype = $_FILES['upload_file']['type'];$tmpname = $_FILES['upload_file']['tmp_name'];$target_path=$UPLOAD_ADDR.basename($filename);// 获得上传文件的扩展名$fileext= substr(strrchr($filename,"."),1);//判断文件后缀与类型,合法才进行上传操作if(($fileext == "jpg") && ($filetype=="image/jpeg")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefromjpeg($target_path);if($im == false){$msg = "该文件不是jpg格式的图片!";}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".jpg";$newimagepath = $UPLOAD_ADDR.$newfilename;imagejpeg($im,$newimagepath);//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = $UPLOAD_ADDR.$newfilename;unlink($target_path);$is_upload = true;}}else{$msg = "上传失败!";}}else if(($fileext == "png") && ($filetype=="image/png")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefrompng($target_path);if($im == false){$msg = "该文件不是png格式的图片!";}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".png";$newimagepath = $UPLOAD_ADDR.$newfilename;imagepng($im,$newimagepath);//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = $UPLOAD_ADDR.$newfilename;unlink($target_path);$is_upload = true; }}else{$msg = "上传失败!";}}else if(($fileext == "gif") && ($filetype=="image/gif")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im = imagecreatefromgif($target_path);if($im == false){$msg = "该文件不是gif格式的图片!";}else{//给新图片指定文件名srand(time());$newfilename = strval(rand()).".gif";$newimagepath = $UPLOAD_ADDR.$newfilename;imagegif($im,$newimagepath);//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path = $UPLOAD_ADDR.$newfilename;unlink($target_path);$is_upload = true;}}else{$msg = "上传失败!";}}else{$msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";}
}
这个函数的主要功能就是,使用上传的图片去生成一张新的图片,生成的结果会返回一个变量,
成功返回ture,失败返回false。并且这个函数,可以在他进行重新创建图片的时候,会将我们图片的信息和非图片的信息进行分离,也就是说如果我们在一张图片中加入了代码,那么他会 在你上传后把这张图片在新建的时候把其中的代码筛选出来,并且去除。最后只保留你的图片信息,在进行排序重建。
图片的二次渲染的操作就是在imagecreatefrom这里进行的
图片码也是可以的,后面这道题是要重新看看的
less17
提示
需要代码审计
源代码
$is_upload = false;
$msg = null;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_ADDR . '/' . $file_name;if(move_uploaded_file($temp_file, $upload_file)){if(in_array($file_ext,$ext_arr)){$img_path = $UPLOAD_ADDR . '/'. rand(10, 99).date("YmdHis").".".$file_ext;rename($upload_file, $img_path);unlink($upload_file);$is_upload = true;}else{$msg = "只允许上传.jpg|.png|.gif类型文件!";unlink($upload_file);}}else{$msg = '上传失败!';}
}
解析
创建了一个只包含图片文件的白名单,随后提取出文件的后缀名,将文件移动至上传目录后再判断是否合法,不合法就删除。我们可以使用条件竞争方法(即在文件被删除之前访问该文件)绕过。此方法需要不停且迅速地上传、访问文件。我们使用BurpSuite和Python进行上传和访问