文件上传之内容逻辑数组绕过(三)

PHP自带的过滤函数以及配合文件包含利用

copy 1.png /b + shell.php /a webshell.jpg意思是将shell.php中的代码追加到1.png中并重新生成一个叫webshell.php的代码,或者用文本打开图片 直接在后面添加后门也得。

读取每个文件的头两个字节获取图片格式以及绕过

14

先上传一个webshell.png  里面写了phpinfo()的函数

14-1

图片马上传后找到路径,利用文件包含成功解析!

14-2

靶场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 = "上传出错!";
        }
    }
}

php自带Getimagesize函数以及绕过

getimagesize代码的核心就是使用这个函数这个函数会对文件头进行验证,比如GIF的文件头问GIF89apng的文件头为塒NG,所以此处正常上传一个图片马将后缀改名为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 = "上传出错!";
        }
    }
}

他只检测文件头,那就上传然后再找路径 文件包含利用

这里有一个插曲 我上传抓包改后缀为php 一样能上传成功 不过他还是以图片保存

我猜测他是函数检查文件头发现是jpg 就以这个格式储存

15-1

成功解析

自带exif_imagetype函数判断是否图片

exif_imagetype() 读取一个图像的第一个字节检查其签名。如果发现了恰当的签名则返回一个对应的常量,否则返回 FALSE。返回值跟getimagesize() 返回的数组中的索引 2 的值是一样的,但exif_imagetype函数快得多。

返回值跟对应的图片类型图:

20200729155359380

这种都非常安全,你只能上传图片,想要利用要么中间件要么文件包含漏洞配合来使用才能getshell。

二次渲染+条件竞争漏洞

1、在图片上传之后,可以进行图片的放大等操作,在上传脚本格式的文件时会暂时保存在服务器中,然后服务器再进行更改 典型的有phpcms

这时候可以用条件竞争来进行绕过,条件竞争也是操作系统特性的问题,在我们打开一个文件时并不能在对该文件进行删除等操作,这个时候就有了一个空“闲”阶段,我们可以上传一个脚本格式的文件,然后用bp去对他不停的去访问,利用这个间隙在服务器删除后门文件的之前连接它

2、二次渲染不只是靠条件竞争去绕过,只能说有个技术叫二次渲染并不能说有漏洞,有利用的原因是因为他在第一步上传的时候没有检查我们的文件格式而是先保存在了服务器在进行二次处理。我们利用操作系统的特性防止他第二步的操作,从而当成绕过

过滤源码:

$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函数把文件保存了,然后再去判断后缀名是否合法,合法就重命名,如果不合法再删除。重点在于,在多线程情况下,就有可能出现还没处理完,我们就访问了原文件,这样就会导致防护被绕过。
  我们上传一个文件上去,后端会检验上传文件是否和要求的文件是否一致。如果不能达到要求就会删除文件,如果达成要求就会保留,那么当我们上传文件上去的时候,检测是否到达要求需要一定的时间,这个时间可长可短,但是我们确确实实在某一刻文件已经上传到了指定地址,并且访问到这个文件。这时候就会造成条件竞争。

场景:

条件竞争场景:
  营造10000人同时上传文件1.php,另外有10000人在同时访问这个1.php;上传文件时,这个文件会有一段时间留存在服务器的上传目录下,而服务器脚本在进行判断文件是否合法而对文件进行删除时,会有一定的处理时间,可能在某个时间里,服务器还未来得及删除文件,从而导致我们对这个上传文件成功访问。

1.php代码:

<?php 
$f= fopen ("test.php","w") ;
fputs ($f,'<?php phpinfo();?>');
?>

二次渲染2

这里选择上传 然后抓包

二次渲染3

把这个包重放10000次

然后通过浏览器疯狂访问这个上传地址 最终1.php被占用  服务器删除不了

二次渲染

这时已经生产test.php了我们进行访问:

二次渲染4

成功!

数组接受逻辑绕过

这种类型 白盒性极强,黑盒几乎不可能,ctf常见这种题。

过滤代码如下:

$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
    //检查MIME
    $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 = "请选择要上传的文件!";
}

审计了一下 很好理解 

比如上传一个 abc.png 他就会把这个文件名分为三部分 分别为 abc  和 .  和png   放到一个数组里

a[0]=abc; a[1]=. ;  a[2]=png  拿a[2]跟白名单进行比较。

如果符合 他就a[0]+a[1]+a[2]进行命名

绕过思路: 抓包

我们自定义 第一个值为abc.php 

                   第二个值为空

                    第三个值为png  

第一个值这样命名是为了最后保存为php格式 第二个值为空是为了在保存命名时截断第三个值

第三个值是为了过检测。

开始动手:

数组

数组2

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论