一,工具资源下载
百度网盘资源下载链接地址:
二,靶场安装及 1-5关
三,6-15关
3-6 第六关:
空格和点配合绕过
先看一下源代码里面的代码将上传的文件名都改为小写了,那么上面的方法就不行了。
利用Windows系统的文件名特性。文件名最后增加空格和点,写成1.php .,这个需要用burpsuite抓包修改,上传后保存在Windows系统上的文件名最后的一个.会被去掉,实际上保存的文件名就是1.php
改完以后放行,然后关闭拦截
回来查看发现已经上传成功了
这一关主要用的是windows文件命名的特性
3-7 第七关
原理同Pass-06,文件名后加点和空格,改成 1.php. ,这个我们就不演示了
3-8 第八关
基于文件流特性::$DATA来绕过,windows下的ntfs文件流特性来玩的。
先查看源码,分析代码,少了 file_ext = str_ireplace('::DATA', '', file_ext);//去除字符串::DATA 这一句,我们可以采用Windows文件流特性绕过,文件名改为1.php::$DATA , 上传成功后保存的文件名其实是1.php
正常上传的话不让上传php木马文件,我们上传时抓包
在文件名tu.php后面加上::$DATA
成功绕过去了
3-9 第九关:
点空格点绕过
先看源码
原理同Pass-06,上传文件名后加上点+空格+点,改为 1.php. . ,这里我就不演示了
1.php. . 先通过trim函数去左右空格,然后删除文件名末尾的点,就剩1.php. 了;strchr函数是从一个字符串中查找指定的字符,并返回从这个字符到结尾的内容,所以得到的是.php. ;然后转换小写,去除文件流没影响,最后首位去空,剩下.php. ;最后保存的时候Windows自动会把末尾的点也会去掉,就这样成功绕过去了
3-10 第十关:
双写绕过
先看源代码
看到str_ireplace,这是一个替换用的函数,第一个参数为替换的内容,这里指定是是deny_ext数组,第二个参数为'',第三个参数为文件名,意思就是文件名里包含数组里的后缀的话直接替换为''
这个很好绕过,比如说我们传一个tu.php;发现php在数组里面,就会替换成'';最后就剩下一个tu了,我们的做法是双写,上传一个tu.pphphp文件,这样的话发现确实存在php,就会进行替换替换以后就剩下tu.php了,就绕过去了
我把服务端文件存储的文件夹清空了,上传以后我们看一看效果
选择我们改过后缀的文件
发现上传成功嘞了
如我们所料,成功上传了
3-11 第十一关:
**%00截断,**这个属于白名单绕过,这是php语言自身的问题,php低版本存在的漏洞
php
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']
['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_GET['save_path']."/".rand(10,99).date("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
}
}
分析代码,这是以时间戳的方式对上传文件进行命名,使用上传路径名%00截断绕过,不过这需要对文件有足够的权限,比如说创建文件夹,上传的文件名写成1.jpg, save_path改成../upload/1.php%00 (1.php%00.jpg经过url转码后会变为1.php\000.jpg),最后保存下来的文件就是1.php
选择一个webshell文件,然后抓包
抓包如下
按如下图进行修改,然后放包,关闭抓包
我的一直提示上传错误,原理是没问题的,你们自己试一下,我回去好好研究研究
3-12 第十二关:
0x00绕过
php
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_ext = substr($_FILES['upload_file']
['name'],strrpos($_FILES['upload_file']['name'],".")+1);
if(in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = $_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类型文件!";
}
}
原理同Pass-11,上传路径0x00绕过。利用Burpsuite的Hex功能将save_path改成../upload/1.php【二进制00】形式
跟十一关不同的地方在于,第十一关的上传路径在URL上我们可以通过%00(也就是0URL编码以后就是%00)来截断,现在文件上传路径在数据中,所以需要0x00十六进制形式截断
我们上传一个webshell.jpg图片,然后抓包
发现上传路径在数据部分里
我们可以这样做,后面接上aini.php (注意有个空格),为了方便改数据的时候定位
点击上面的Hex,让数据以十六进制形式显示
往下翻,找到我们路径的位置,我们在aini.php后面加了空格,空格转换为十六进制就是20,所以很好定位,左边红色框里的20就是我们自己故意留下的空格
然后就是把20改为00,也就是十六进制的00了,跟第十一关%00截断原理一模一样
切换回来以后,其实aini.php后面看不出来有变化,但是确实已经加上了截断
不过还是跟第十一关一样的文件上传失败的错误,暂时没找出原因,不过原理就是这个,你们自己试一下看看
3-13 第十三关:
绕过文件头检查
php
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 = "上传出错!";
}
}
}
以上是检查文件头的函数
绕过文件头检查,添加GIF图片的文件头GIF89a,绕过GIF图片检查。
或者我们使用命令copy 1.jpg /b + shell.php /a webshell.jpg,将php一句话追加到jpg图片末尾,代码不全的话,人工补充完整。形成一个包含Webshell代码的新jpg图片,然后直接上传即可。但是我们没有办法拿到shell,应为我们上传的图片马无法被解析成php形式,通常图片马配合%00或者0x00截断上传,或者配合解析漏洞
我在下面这篇博客里讲了绕过文件头检查的三种方式,可以去这篇博客里参考
3-14 第十四关:
php
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() 一样,参考以下博客
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这里有详解:
image_type_to_extension() 函数用于获取图片后缀
3-15 第十五关:
exif_imagetype()绕过
跟第十三,第十四关差不多
php
function isImage($filename){
//需要开启php_exif模块
$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 = "上传出错!";
}
}
}
其中:exif_imagetype() 此函数是php内置函数,用来获取图片类型