目录
3. mysql_real_escape_string())
5. Cookie / 请求头注入(User-Agent、Referer 注入)
3. strlen() 函数%20%E5%87%BD%E6%95%B0)
4.htmlspecialchars() —— 核心防御函数 (Level 3 出现)%20%E2%80%94%E2%80%94%20%E6%A0%B8%E5%BF%83%E9%98%B2%E5%BE%A1%E5%87%BD%E6%95%B0%20(Level%203%20%E5%87%BA%E7%8E%B0))
5. str_replace() —— 危险的黑名单替换 (Level 4 - Level 8 出现)%20%E2%80%94%E2%80%94%20%E5%8D%B1%E9%99%A9%E7%9A%84%E9%BB%91%E5%90%8D%E5%8D%95%E6%9B%BF%E6%8D%A2%20(Level%204%20-%20Level%208%20%E5%87%BA%E7%8E%B0))
6. strtolower() —— 大小写统一 (Level 6 & Level 8 出现)%20%E2%80%94%E2%80%94%20%E5%A4%A7%E5%B0%8F%E5%86%99%E7%BB%9F%E4%B8%80%20(Level%206%20%26%20Level%208%20%E5%87%BA%E7%8E%B0))
7. strpos() —— 字符串查找 (Level 9 出现)%20%E2%80%94%E2%80%94%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%9F%A5%E6%89%BE%20(Level%209%20%E5%87%BA%E7%8E%B0))
8. ini_set() 函数%20%E5%87%BD%E6%95%B0)
Pass-02:MIME 类型(Content-Type)校验绕过
Pass-15:exif_imagetype EXIF 校验绕过
SQL 注入靶场作业整理:PHP 函数与漏洞防御全汇总
一、靶场中涉及的 PHP 核心函数整理
结合课程里 Less-1 到 Less-32 的所有关卡,共出现 3 个与 SQL 注入直接相关的关键 PHP 函数,对应课件里的源码与漏洞场景如下:
1. mysql_query()
- 出现关卡:Less-1 ~ Less-4、Less-11 等所有基础注入关卡
- 函数功能:PHP 早期操作 MySQL 的原生函数,作用是向数据库发送并执行一条 SQL 语句,是所有查询的执行入口。
- 漏洞关联:这是 SQL 注入最终生效的核心节点。靶场后端代码将用户输入的 id、用户名直接拼接到 SQL 字符串中,再传给mysql_query()执行,用户输入的恶意语法会被数据库当成正常命令运行。
- 对应源码片段:

$sql = "SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result = mysql_query($sql);
2. addslashes()
- 出现关卡:Less-32 宽字节注入关卡(关卡标题明确标注 Bypass addslashes())
- 函数功能:自动在单引号'、双引号"、反斜杠\、NULL 字符前添加反斜杠\,开发者原本想用它转义特殊字符,阻止单引号闭合,从而防御 SQL 注入。
- 漏洞关联:该函数不感知数据库编码格式。当网站使用 GBK 宽字节编码时,输入%df'会被函数处理为%df%5c%27(自动补充转义用的\,对应字节%5c);GBK 编码会将%df%5c识别为一个汉字,相当于 “吃掉” 了转义反斜杠,后面的单引号恢复闭合能力,从而形成宽字节注入。
3. mysql_real_escape_string()
- 出现关卡:Less-24 二次注入关卡
- 函数功能:比addslashes()更严谨的转义函数,会根据当前数据库的字符集转义 SQL 特殊字符,常规场景下可以防御普通 SQL 注入。
- 漏洞关联:仅能防御 “一次注入”。注册用户名时,函数会将admin'#中的单引号转义后写入数据库;但数据最终存入数据库时,会还原为原始的admin'#。后续修改密码等功能直接从数据库读取用户名拼接 SQL,未做二次转义,最终触发二次注入。

二、各类 SQL 注入漏洞的防御方式
核心原理回顾
这张图对应课件第一页讲的 SQL 注入本质:用户输入本该是普通数据,却被错误拼接进 SQL 语句,变成了 SQL 语法的一部分。
- 正常流程:用户传入 id=1 → 后端拼接为正常 SQL → 数据库仅返回 id=1 的单条数据
- 注入流程:用户传入1 or 1=1 → 后端直接字符串拼接 → 数据库执行恶意条件 → 返回全表数据

1. 联合查询注入(GET/POST 字符型 / 数字型)

- 对应关卡:Less-1~Less-4、Less-11(POST 登录框注入)
- 漏洞特点:页面存在明确的数据回显位,可通过union select直接将查询结果显示在页面上,是最直观的注入类型。
- 防御方案:
- 核心防御:使用预处理语句(PDO / MySQLi prepare)
彻底禁止字符串拼接 SQL,将 SQL 语句模板与用户数据分开发送给数据库;用户数据永远只会被识别为数据,不会成为 SQL 语法,这是防御 SQL 注入的黄金标准,可同时防御绝大多数注入类型。
- 输入类型强校验
数字型参数(如 id)强制使用intval()转为整数,从根源杜绝拼接可能。
- 数据库最小权限原则
业务数据库账号仅分配当前库的必要权限,禁止访问information_schema系统库,即使存在注入也难以拖库。
2. 布尔盲注

- 对应关卡:Less-5
- 漏洞特点:页面无数据回显,仅存在 “正常显示” 与 “空白 / 错误” 两种状态,攻击者通过and 条件的真假反馈逐字符猜解数据库内容。
- 防御方案:
- 统一错误页面,无论 SQL 执行成功或失败,前端返回完全一致的页面,不提供真假判断依据。
- 接口添加访问频率限制,拦截自动化猜解脚本。
- 底层使用预处理语句,从语法层面阻断注入逻辑。
3. 时间盲注

- 对应关卡:Less-9
- 漏洞特点:页面无任何状态差异,攻击者通过sleep()等延迟函数的响应时间差,判断 SQL 条件是否成立,隐蔽性极强。
- 防御方案:
- 禁用数据库sleep()、benchmark()等高风险延迟函数。
- 后端接口设置最大执行超时,异常延迟请求直接中断返回。
- 以预处理语句作为根本防御手段。
4. 报错注入

- 对应关卡:Less-5(extractvalue、updatexml、floor 三种报错手法)
- 漏洞特点:利用数据库函数的语法错误,将查询结果夹带在报错信息中回显,属于 “有回显” 的注入变种。
- 防御方案:
- 生产环境必须关闭详细错误回显,统一返回通用错误提示,绝对禁止将数据库报错暴露给前端。
- 限制 XML 相关高危函数的使用权限。
- 预处理 + 输入校验双保险。
5. Cookie / 请求头注入(User-Agent、Referer 注入)

- 对应关卡:Less-18、Less-20
- 漏洞特点:注入点不在 URL 和表单,而在 Cookie、User-Agent、Referer 等请求头中;后端将这些值直接拼接进 SQL(如保存日志、查询用户身份)。
- 防御方案:
- 所有客户端输入一视同仁:URL、表单、Cookie、请求头都必须做校验与预处理,不能默认 “请求头不可篡改”。
- 日志写入数据库使用参数化语句,禁止字符串拼接。
- Cookie 增加签名校验,防止恶意篡改。
6. 二次注入

- 对应关卡:Less-24
- 原理流程图(对应课件 “先存后用” 的逻辑):

二次注入原理流程图
这张图完整对应课件讲解的二次注入流程:
- 第一步:注册时输入admin'#,转义函数对单引号做了转义,数据成功入库;但数据库里最终保存的仍是原始的admin'#。
- 第二步:修改密码等业务场景,直接从数据库读取用户名拼接 SQL,未做二次转义,单引号成功闭合触发注入。
- 防御方案:
- 所有 SQL 执行场景都使用预处理,无论数据来自用户输入还是数据库查询。
- 摒弃 “入库数据就是安全数据” 的错误认知,数据出库复用也必须做安全处理。
- 用户名、昵称等字段做白名单限制,禁止包含单引号、#、--等 SQL 关键字。
7. 宽字节注入
- 对应关卡:Less-32
- 漏洞特点:利用addslashes()自动添加的反斜杠,与前置字节拼接成宽字节汉字,“吃掉” 转义符,让单引号恢复闭合能力。
- 防御方案:
- 彻底废弃addslashes(),使用mysql_real_escape_string()并明确指定数据库字符集为 UTF-8。
- 数据库、PHP、前端全链路统一使用 UTF-8 编码,不使用 GBK 等宽字节编码。
- 终极方案:使用 PDO 预处理,完全不依赖转义函数,从机制上杜绝此类问题。

三、全类型通用防御总结
- 首选方案:PDO 预处理语句,是最彻底、最可靠的防御手段
- 输入校验:优先使用白名单校验,而非黑名单过滤
- 错误隐藏:生产环境禁止暴露数据库详细报错信息
- 权限最小化:数据库账号仅分配业务必需的最低权限
- 辅助防护:部署 WAF Web 应用防火墙,拦截常见注入 payload
XSS
一、靶场中用到的 PHP 函数整理
1. $_GET 超全局变量

- 功能:接收客户端通过 URL 参数以 GET 方式提交的数据,是 Web 应用最基础的输入入口。
- 靶场应用:level1~level10、level16 等绝大多数关卡,通过
name、keyword等参数接收用户输入,是所有反射型 XSS 的输入源头。 - 对应文档图片:

2. echo 输出函数
- 功能:向 HTML 页面输出字符串内容,直接拼接到页面源码中。
- 靶场应用:所有关卡的输出点,将用户输入渲染到页面标题、搜索结果、input 输入框值等位置;未做编码时,用户输入的脚本会被浏览器直接解析执行。
- 对应文档图片:
- 反射型 XSS 流程图里的
echo "<h2 align=center>欢迎用户".$str."</h2>";源码片段 - level2 页面中输出搜索结果的
<h2>标签源码截图 
- 反射型 XSS 流程图里的
3. strlen() 函数
- 功能:统计字符串的字节长度。
- 靶场应用:每一关页面底部显示「payload 的长度」,用于统计用户提交输入的字符数。
- 对应文档图片:各关卡页面底部
payload的长度: xx的展示区域
4.htmlspecialchars() —— 核心防御函数 (Level 3 出现)
作用: 将 HTML 特殊字符(如
<、>、&、")转换为 HTML 实体(如<、>)。浏览器在渲染时只会将它们当作普通文本显示,而不会将其解析为可执行的 HTML 标签或 JavaScript 代码。靶场利用点:
早期版本的
htmlspecialchars()默认只转义双引号("),不转义单引号(')。在 Level 3 中,当你发现
<和>被过滤,但输入<input value='你的输入'>时,可以通过单引号闭合属性:' onfocus=alert(123) x='来绕过。

5. str_replace() —— 危险的黑名单替换 (Level 4 - Level 8 出现)
作用: 字符串替换函数。格式为
str_replace("被替换的字符", "替换成的字符", $目标变量)。靶场利用点: 开发人员常把它当黑名单用,但这往往千疮百孔。
Level 4 过滤了
<和>: 利用事件属性绕过(如" onfocus=alert(123) autofocus=")。Level 5 过滤了
<script>和on(变为o_n): 转换为利用href属性结合伪协议绕过,如"><a href=javascript:alert(123)>。Level 7 进行了关键字删除: 采用双写绕过,如
oonnfocus或scscriptipt,替换函数执行一次后,剩下的字符刚好拼成完整的恶意 payload。

6. strtolower() —— 大小写统一 (Level 6 & Level 8 出现)
作用: 将字符串转化为小写。
靶场利用点:
在 Level 6 中,因为没有使用此函数,所以可以通过大小写混写绕过限制,如
" ONfocus=alert(123)或<sCrIpT>。在 Level 8 中加入了此函数,导致大小写绕过失效,从而逼迫你使用了 HTML 实体编码(如
s代表s)来绕过关键字检测。

7. strpos() —— 字符串查找 (Level 9 出现)
作用: 查找字符串在另一字符串中首次出现的位置。
靶场利用点:
Level 9 代码
if(false===strpos($str7, 'http://'))要求输入中必须包含http://。绕过方式:将其作为 JavaScript 的单行注释附在 Payload 后面。如:
javascript:alert(123)//http://。
8. ini_set() 函数
- 功能:动态修改 PHP 运行时的配置项。
- 靶场应用:多数关卡开头
ini_set("display_errors",0);,关闭 PHP 错误提示,避免错误信息泄露服务器源码与路径。

二、三类 XSS 漏洞的防御方式
1. 反射型 XSS(Reflected XSS)

漏洞核心
恶意脚本随单次请求传入、随本次响应返回,不存入数据库;需要诱导用户点击恶意链接触发,一次性生效。
完整防御方案
- 输出编码(核心措施) 所有用户可控内容输出到 HTML 页面时,必须使用带完整参数的
htmlspecialchars():htmlspecialchars($data, ENT_QUOTES, 'UTF-8');ENT_QUOTES会同时转义单引号和双引号,彻底避免属性闭合绕过。 - 输入白名单校验 对输入做格式校验(比如姓名只能是中英文 + 数字),不符合格式直接拒绝,比黑名单过滤更可靠。
- 不依赖黑名单过滤 仅靠
str_replace替换script、on等关键字不可靠,可通过大小写、双写、HTML 编码等多种方式绕过。
2. 存储型 XSS(Stored XSS)
漏洞核心
恶意脚本被写入数据库永久保存,所有访问该内容的用户都会触发;危害远大于反射型,不需要诱导点击,访问即中招。
完整防御方案
输出编码(核心措施) 和反射型一致,从数据库取出的所有用户内容,渲染到 HTML 时必须用
htmlspecialchars(..., ENT_QUOTES, 'UTF-8')做实体编码。注意:写入数据库时不需要转义 HTML 实体,只在输出到页面时转义,避免数据重复转义。
输入侧校验 提交内容时做格式校验,限制长度、允许的内容范围;如果必须使用富文本,要用专业的白名单过滤库(不能自己写黑名单)。
- 深度防御
- 配置 CSP(内容安全策略),限制页面可执行的脚本来源,即使存在 XSS 也无法加载恶意脚本
- 关键 Cookie 设置
HttpOnly属性,防止 XSS 盗取用户 Cookie
3. DOM 型 XSS(DOM Based XSS)
漏洞核心
完全发生在客户端浏览器,恶意 Payload 不需要出现在服务器响应中;前端 JS 直接从 URL(hash/search)、本地存储等读取数据,未经处理写入innerHTML、document.write等危险位置。
- 常见可控来源(Source):
location.hash、location.search、document.URL - 常见危险操作点(Sink):
innerHTML、document.write()、eval()
完整防御方案
- 前端输出处理(核心措施)
- 插入纯文本优先使用
textContent替代innerHTML,纯文本不会被解析为 HTML - 必须使用 innerHTML 时,先对内容做 HTML 实体编码,或使用成熟的 XSS 净化库(如 DOMPurify)
- 插入纯文本优先使用
- 禁止危险操作 避免把用户可控数据传入
eval()、setTimeout()等可执行字符串代码的函数;避免直接把用户数据拼接到href、src等属性中。 - 服务端辅助 对 URL 参数做输入校验,同时配置 CSP 策略做深度防御。
文件上传
一、靶场中使用到的 PHP 函数汇总
1. 一句话木马 & 代码执行类(危险函数)
对应你笔记里「PHP 一句话木马」「免杀变形」章节的截图,是 Webshell 的核心组成。
|
函数名
|
核心作用
|
出现场景
|
| --- | --- | --- |
|
eval()
|
将字符串当作 PHP 代码执行,一句话木马最核心函数
|
基础木马 <?php @eval($_POST['cmd']); ?>,所有关卡木马的核心逻辑
|
|
assert()
|
断言函数,同样可执行 PHP 代码
|
木马变形免杀,配合回调函数间接调用
|
|
system()
|
直接执行操作系统命令(如 whoami、ipconfig)
|
木马传参 cmd=system('whoami'),调用系统命令
|
|
phpinfo()
|
输出 PHP 环境配置信息
|
上传后测试文件是否能被 PHP 解析器正常执行
|
|
call_user_func()
|
回调函数,动态调用指定函数
|
木马变形:间接调用危险函数,绕过关键字检测
|
|
base64_decode()
|
Base64 解码
|
编码隐藏木马:将关键字编码后再解码执行,绕过 WAF 关键字查杀
|
对应你笔记的图片:
补充原理示意图:

PHP一句话木马执行原理
2. 文件上传处理核心函数
对应每一关 PHP 源码里的上传基础逻辑,所有关卡通用。

|
函数 / 超全局变量
|
核心作用
|
| --- | --- |
|
$_FILES
|
超全局变量,获取上传文件的全部信息(文件名、临时路径、类型、大小等)
|
|
move_uploaded_file()
|
将上传的临时文件移动到目标保存目录,PHP 文件上传的核心函数
|
|
isset()
|
判断变量是否存在,用于检测用户是否点击上传按钮
|
|
file_exists()
|
判断目录 / 文件是否存在,用于检查上传目录是否存在
|
3. 文件类型 & 图片校验类函数
对应笔记第 13-15 关的校验源码、魔数对照表。

|
函数名
|
核心作用
|
出现关卡
|
| --- | --- | --- |
|
fopen()
|
打开文件句柄
|
Pass-13 自定义getReailFileType函数,打开文件读取头部
|
|
fread()
|
读取指定长度的文件字节
|
Pass-13 读取文件前 2 字节,判断魔数
|
|
fclose()
|
关闭文件句柄
|
读取文件头后释放资源
|
|
unpack()
|
将二进制数据解包为数组
|
Pass-13 把 2 字节魔数转为数字,判断是 jpg/png/gif
|
|
getimagesize()
|
获取图片尺寸,同时返回图片类型常量
|
Pass-14 通过图片宽高和类型判断合法性
|
|
image_type_to_extension()
|
将图片类型常量转为后缀名
|
Pass-14 配合getimagesize获取合法后缀
|
|
exif_imagetype()
|
读取文件头魔数判断图片类型(需开启 exif 扩展)
|
Pass-15 更专业的魔数校验,需要在 php.ini 开启扩展
|
对应你笔记的图片:


4. 文件名 & 字符串处理类(黑名单校验核心)
对应笔记第 3-8 关的黑名单绕过逻辑,每少一个函数就对应一种绕过方法。
|
函数名
|
核心作用
|
对应绕过关卡
|
| --- | --- | --- |
|
strrchr()
|
截取最后一个.后的字符串,提取文件扩展名
|
所有黑名单关卡
|
|
strtolower()
|
将字符串转为小写
|
Pass-5 无此函数,可用.PHP大写后缀绕过
|
|
str_ireplace()
|
不区分大小写替换字符串
|
用于去除::$DATA等特殊后缀
|
|
trim()
|
去除字符串首尾空格
|
Pass-6 无此函数,可用.php 后缀加空格绕过
|
|
deldot()
|
自定义函数,删除文件名末尾的点
|
Pass-7 无此函数,可用.php.后缀加点绕过
|
|
in_array()
|
判断值是否在数组中
|
黑白名单校验核心逻辑
|
|
date() + rand()
|
生成日期 + 随机数
|
组合生成唯一文件名,防止文件覆盖
|
5. 其他文件操作函数
|
函数名
|
核心作用
|
出现场景
|
| --- | --- | --- |
|
file_put_contents()
|
向文件写入内容,可创建新文件
|
Pass-17 条件竞争:在文件被删除前写入一个永久木马
|

二、各关卡漏洞类型、原理与防御方式
Pass-01:前端 JS 校验绕过
对应笔记图片:


- 页面弹窗:「该文件不允许上传,请上传 jpg/png/gif 类型的文件」
- JS 源码截图:checkFile() 函数在浏览器端提取后缀判断
漏洞原理:
校验完全在浏览器前端执行,服务端没有二次校验。禁用 JS 或抓包修改文件名即可直接绕过。
绕过方式:BurpSuite 抓包,把文件名从.png改回.php再放行。
防御方式:
- 前端校验仅做用户体验优化,服务端必须做二次校验
- 永远不能信任客户端侧的任何校验结果
Pass-02:MIME 类型(Content-Type)校验绕过
对应笔记图片:

- PHP 源码截图:判断$_FILES['upload_file']['type']是否为三种图片类型
- Burp 抓包修改Content-Type字段的截图
漏洞原理:
只校验 HTTP 请求头里的Content-Type字段,该字段由客户端完全可控,抓包修改即可绕过。
绕过方式:抓包把Content-Type改为image/png,文件名保持.php。
防御方式:
- 不能信任客户端传来的Content-Type,必须服务端检测文件真实内容
- 配合文件头魔数、图片二次渲染做多重校验
Pass-03:黑名单不全 + Apache 后缀解析绕过
对应笔记图片:


- 黑名单数组:仅禁止.asp/.aspx/.php/.jsp
- Apache 解析特性说明:.php3/.php5也会被当作 PHP 执行
漏洞原理:
- 黑名单过滤不完整,遗漏了 Apache 可识别的 PHP 变体后缀
- Apache 多后缀解析特性:从右往左识别后缀,遇到不认识的就继续往左解析
绕过方式:文件名改为.php5、.php3等变体后缀。
防御方式:
- 放弃黑名单,改用白名单机制,只允许指定后缀上传
- 关闭中间件多后缀解析功能,强制只按最后一个后缀解析
- 上传后文件统一重命名,禁止保留原始文件名
Pass-04:.htaccess 配置文件绕过
对应笔记图片:


- 超长黑名单列表,封死了几乎所有 PHP 相关后缀
- .htaccess文件内容截图:SetHandler application/x-httpd-php
漏洞原理:
黑名单未禁止.htaccess文件,攻击者可上传 Apache 目录级配置文件,让当前目录下所有文件(包括图片)都用 PHP 解析器执行。
补充示意图:

.htaccess文件上传绕过原理
绕过方式:先上传.htaccess配置文件,再上传图片马,图片会被当作 PHP 执行。
防御方式:
- 白名单中禁止.htaccess、.user.ini等配置文件
- Apache 全局配置设置 AllowOverride None,禁止目录级配置生效
- 上传目录关闭 PHP 解析权限
Pass-05:大小写绕过
对应笔记图片:

- 源码截图:黑名单只有小写.php,代码中无strtolower()转小写步骤
漏洞原理:
Windows 系统对文件名大小写不敏感,.php和.PHP是同一个文件;但黑名单只校验小写,未做大小写转换。
绕过方式:文件名改为.PHP、.Php等大小写混合形式。
防御方式:
- 提取后缀后统一用strtolower()转小写再校验
- 优先使用白名单机制
Pass-06:空格绕过
对应笔记图片:

- Burp 抓包截图:文件名末尾加空格 .php
- 源码中缺少trim()首尾去空步骤
漏洞原理:
Windows 系统会自动去除文件名末尾的空格,而校验时带空格的后缀不在黑名单中。
绕过方式:抓包在文件名后缀后加空格。
防御方式:
- 校验前先用trim()去除文件名首尾空白字符
- 对文件名做规范化处理后再校验
Pass-07:点号绕过
对应笔记图片:


- 源码截图:缺少deldot()删除末尾点的步骤
- 文件名.php.的抓包示例
漏洞原理:
Windows 系统会自动去掉文件名末尾的点,.php.最终保存为.php;但校验时点号后缀不在黑名单中。
绕过方式:文件名末尾加一个点 .php.。
防御方式:
- 校验前删除文件名末尾所有点号
- 规范化文件名路径,规避 Windows 系统特性绕过
Pass-08:::$DATA 文件流绕过
对应笔记图片:



- NTFS 文件流说明截图:index.txt::$DATA是默认数据流
- 抓包文件名test.php::$DATA示例
漏洞原理:
Windows NTFS 文件系统中,::$DATA代表默认数据流,加上后系统仍按原文件保存;但黑名单中没有这种后缀形式。
绕过方式:文件名后追加::$DATA。
防御方式:
- 校验前去除文件名中的::$DATA等特殊流标识
- 用严格的白名单正则匹配文件名,只允许字母、数字、点、下划线
Pass-13:文件头魔数校验绕过
对应笔记图片:


- 自定义getReailFileType函数源码:只读前 2 字节判断魔数
- Burp 抓包截图:文件内容开头加GIF89a
- 完整魔数对照表
漏洞原理:
只校验文件开头的魔数字节,攻击者在木马文件开头加上图片文件头,就能骗过检测,后半部分仍是 PHP 代码。
绕过方式:
- 木马文件开头加GIF89a(GIF 文件头标识)
- 用命令 copy /b 图片.png + 木马.php 图片马.png 制作图片马
防御方式:
- 不能只校验文件头,需配合二次渲染、图片重绘
- 对上传图片重新编码生成,清除附加的恶意内容
Pass-14:getimagesize 图片尺寸校验绕过
对应笔记图片:

- 源码截图:getimagesize() + image_type_to_extension() 校验
- 十六进制编辑器打开图片的截图
漏洞原理:
getimagesize()读取图片尺寸信息,只要图片结构完整就能通过。尾部追加 PHP 代码的图片马仍保留完整图片结构,可以绕过。
绕过方式:普通图片马即可绕过。
防御方式:
- 使用 GD 库对图片进行二次渲染(重绘),破坏附加代码
- 上传目录禁止 PHP 执行权限,即使有图片马也无法解析
Pass-15:exif_imagetype EXIF 校验绕过
对应笔记图片:


- 源码截图:exif_imagetype() 函数校验
- php.ini 开启php_exif.dll的修改截图
漏洞原理:
本质仍是魔数校验,只是用 PHP 官方扩展实现,比自定义函数更规范,但图片马依然可以绕过。
绕过方式:正常图片马即可绕过。
防御方式:同第 14 关,二次渲染 + 目录禁止执行权限。
Pass-16:二次渲染绕过
对应笔记图片:

- 关卡说明:GD 库对图片二次渲染,会清除大部分附加数据
漏洞原理:
二次渲染会将图片解码再重新编码,尾部追加的代码会被清除。但图片中部分区块(如 GIF 注释块、PNG 特定数据块)渲染后保持不变,可将木马藏在这些稳定区域。
绕过方式:找到图片渲染前后不变的字节区域,将 PHP 代码写入该位置。
防御方式:
- 使用成熟图片处理库做严格二次渲染
- 强制统一图片格式、压缩质量,最大化清除额外数据
- 上传目录必须关闭脚本执行权限
Pass-17:条件竞争(时间差)绕过
对应笔记图片:
、

- Burp Intruder 设置截图:上传包和访问包各发送 5000 次
- 访问结果截图:大量 404 中找 200 成功请求
- file_put_contents() 函数说明截图
漏洞原理:
服务端逻辑是「先保存文件 → 再校验后缀 → 不合法就删除」,保存和删除之间存在极短时间窗口。攻击者高并发上传 + 访问,就能在删除前执行代码,写入永久木马。
绕过方式:
- 木马内容用file_put_contents()生成一个新的永久木马文件
- Burp Intruder 同时高并发发送上传和访问请求,抢占时间窗口
防御方式:
- 先校验文件合法性,校验通过后再移动到目标目录
- 先保存到临时不可访问目录,校验通过后再重命名到公开目录
- 限制上传频率,防御高并发攻击
三、文件上传漏洞通用防御总结
结合所有关卡,企业级防御的核心原则:
- 白名单优先:永远用白名单限制允许的文件类型,不使用黑名单
- 多重校验:后缀名 + MIME + 文件头 + 二次渲染 多层校验
- 强制重命名:上传后文件统一随机重命名,禁止保留原始文件名
- 目录隔离:上传目录单独存放,关闭该目录的脚本执行权限
- 路径安全:禁止路径穿越,固定保存路径,不使用用户传入的路径
- 权限最小化:上传目录设置只读权限,禁止执行、禁止列目录






