漏洞重温之文件上传
Pass-11
进入第十一关,首先我们先查看源码。
从代码中,我们可以看到。
if (isset($_POST['submit']))
这行代码是在验证我们上传是否为空
$ext_arr = array('jpg','png','gif')
这行代码告诉我们,网页建立了一个数组,从里面的内容可以猜测,这可能是网站设置的白名单数组。
$file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1)
这行代码提取了我们上传的文件名中的后缀,并且将其存储到了$file_ext这个变量中。
if (in_array($file_ext,$ext_arr)){
$temp_file = $_FILES['upload_file']['temp_name'];
$img_path = $_GET['save_path']."/".rand(10,99).data("YmdHis").".".$file_ext;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else{
$msg = '上传出错!';
}else {
$msg = "只允许上传.jpg|.png.gif类型文件!";
}
}
这行代码则是做了一个判断,如果我们上传文件的后缀在白名单数组里面,那么我们的文件可以被上传,并且会被重命名,如果不是,则返回只允许上传只允许上传.jpg|.png.gif类型文件!这条提示。
但是$img_path 是直接拼接,因此可以利用%00截断绕过。
PS:截断条件:php版本小于5.3.4,php的magic_quotes_gpc为off状态。
因为%00截断绕过,我们所利用的并非正常的上传方式,所以在这里我们并不需要通过返回包知道路径,所以在上传之后,可以直接访问。
第十一关,通关。
Pass-12
进入十二关,直接查看源码,可以发现,源码内容基本和第十一关一致。
但是注意下面这行代码。
$img_path = $_POST['save_path']."/".rand(10,99).data("YmdHis").".".$file_ext;
这条代码是十二关和十一关不同的地方,一个是get请求,一个是post请求。
因为代码一致,所以绕过方式我们依然选择%00截断,只是post请求不像get请求会将%00进行自动解码,所以我们需要在二进制中进行修改。
在修改成功之后,就可以上传,并且直接访问了。
第十二关,通关。
Pass-13
第十三关源码很长,就不截图了,源码如下。
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
include "上传文件名"
?>
因为网站在我们图片上传完成之后会对我们的文件进行重命名,所以我们需要抓取返回包,记录文件名称,以此来验证我们上传的图片马是否可以使用。
第十三关,通关。
Pass-14
第十四关,源码如下。
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函数来进行的,该函数判断了文件类型,但是因为我们上传的图片马从本质上是图片和代码的结合,并且格式依然是图片格式,所以此处过滤对我们的图片马并无影响,可直接上传,方法跟第十三关一致。
第十四关,通关。
Pass-15
第十五关代码如下。
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模块来判断文件类型,所以这关的限制条件依然是文件类型,图片马本质为图片,所以依然可以使用直接使用图片马来绕过。
第十五关,通关。