Pass-11
场景分析
$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 . '文件夹不存在,请手工创建!'; } }
这是一个后端校验的 PHP 代码,从上可知其中定义了文件后缀名黑名单,黑名单里几乎包含了所有可解析的后缀名、.htaccess以及.ini,当上传文件的后缀名与黑名单匹配时会自动去除后缀名,没有了后缀名文件自然也无法解析,但由于只过滤单次后缀名,因此我们可以双写后缀名绕过限制
双写后缀名
上传名为mac.pphphp的 php 文件
成功访问上传文件
Pass-12
场景分析
$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类型文件!"; } }
这是一个后端校验的 PHP 代码,从上可知其中定义了文件后缀名白名单,白名单中包含了jpg、png、gif,脚本会检测上传数据包的 MIME 类型是否在白名单当中,但由于文件上传路径可控,因此我们可以使用00截断的方式绕过限制。
那什么是00截断呢?
在 ASCII 码中0一般作为特殊字符保留,一般代表字符串结束。0x00、%00、/00其实都代表同一意思,当%00出现时其实就目标就会认为内容读取已经结束,从而忽略到%00后的字符串。但在 PHP 中的00截断需要注意几个前提:
1、PHP版本小于5.3.42、 PHP中的magic_quotes_gpc关闭
00截断
上传 php 文件并将文件路径修改为../upload/mac.php%00
成功访问上传文件
Pass-13
场景分析
$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类型文件!"; } }
这是一个后端校验的 PHP 代码,从上可知其中定义了文件后缀名白名单,白名单中包含了jpg、png、gif,脚本会检测上传数据包的 MIME 类型是否在白名单当中,但由于文件上传路径可控,因此我们可以使用00截断的方式绕过限制。
那什么是00截断呢?
在 ASCII 码中0一般作为特殊字符保留,一般代表字符串结束。0x00、%00、/00其实都代表同一意思,当%00出现时其实就目标就会认为内容读取已经结束,从而忽略到%00后的字符串。但在 PHP 中的00截断需要注意几个前提:
1、PHP版本小于5.3.42、 PHP中的magic_quotes_gpc关闭
00截断+URL编码
上传php 文件并将文件路径修改为../upload/mac.php%00,本题与上题类似,只不过修改位置进行了替换,我们需要对%00进行URL编码
成功访问上传文件
Pass-14
场景分析
本题对文件内容的前两个字节进行检测,同时提示其中存在文件包含漏洞
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 = "上传出错!"; } } }
这是一个后端校验的 PHP 代码,从上可知其中定义了文件白名单,白名单中包含了jpg、png、gif,脚本会检查文件开头的两个字节来判断文件是否为白名单。如果判断文件不为白名单则上传失败,因此我们可以伪造图片头并在图片中插入代码,使用图片马上传的方式可绕过限制吗,然后配合文件包含完成脚本解析
结合文件包含漏洞
文件包含漏洞通过参数file来指定图片马可进行解析
文件包含+图片马
首先我们需要制作图片马,在不同系统中制作方式也不同
# Windows copy 1.png /a + 2.php /b 3.png # Linux cat 1.png 2.php > 3.png
图片马生成后开始上传文件
成功访问上传文件
配合文件包含成功解析
include.php?file=upload/4720220519155838.png
Pass-15
场景分析
查看提示信息本题使用getimagesize()进行检测,同时提示其中存在文件包含漏洞
那什么是 getimagesize() 函数呢?
getimagesize() 函数用于获取图像大小及相关信息,图片对象包括 GIF、JPG、PNG 等,如果获取成功会返回一个数组,失败则会返回 FALSE 并产生一条 E_WARNING 级的错误信息。
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 = "上传出错!"; } } }
这是一个后端校验的 PHP 代码,从上可知其中定义了文件后缀名白名单,白名单中只包含了图片后缀,与此同时它通过getimagesize()函数检查文件是否为图片。我们可以使用上传图片马的方式绕过限制。但它与上一题略有不同,在上一题中如果我们只修改文件前两个字节还能够上传成功,那么这题就不行了,需要实实在在构造一个图片马才行。
结合文件包含漏洞
由于题中本身存在文件包含漏洞,通过参数file来指定图片马可完成解析
文件包含+图片马(首部检查)
首先我们需要制作图片马,在不同系统中制作方式也不同
# Windows copy 1.png /a + 2.php /b 3.png # Linux cat 1.png 2.php > 3.png
图片马生成后开始上传文件
成功访问上传文件
配合文件包含成功解析
include.php?file=upload/4720220519161618.png
Pass-16
场景分析
本题使用exif_imagetype()进行检测,同时提示其中存在文件包含漏洞
那什么是 exif_imagetype() 函数呢?
exif_imagetype() 函数会读取一个图像的第一个字节并检查其签名。主要用来检查某个文件是否为图像。但它需要在php.ini中添加php_exif扩展并重启应用,否则无法调用该函数
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 = "上传出错!"; } } }
这是一个后端校验的 PHP 代码,从上可知其中定义了文件后缀名白名单,白名单中只包含了图片后缀,与此同时它通过exif_imagetype()函数检查文件是否为图片。我们可以使用上传图片马的方式绕过限制。
结合文件包含漏洞
由于题中本身存在文件包含漏洞,通过参数file来指定图片马可完成解析
文件包含+图片马(函数检查)
首先我们需要制作图片马,在不同系统中制作方式也不同
# Windows copy 1.png /a + 2.php /b 3.png # Linux cat 1.png 2.php > 3.png
图片马生成后开始上传文件
成功访问上传文件
配合文件包含成功解析
include.php?file=upload/9220220519163603.png