当转义失效:从sqli-labs第32关看字符集如何击穿addslashes

admin 2026-01-23 10:36:11 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文深入解析sqli-labs第32关,阐述了利用GBK等多字节字符集绕过PHPaddslashes()函数防御的原理。通过构造%df等高字节使反斜杠被MySQL解析为汉字的一部分,导致单引号转义失效,从而成功进行显错与联合查询注入。文章强调安全机制依赖环境上下文,开发需严格确保字符集配置一致以防此类漏洞。 综合评分: 94 文章分类: WEB安全,渗透测试,漏洞分析


cover_image

当转义失效:从 sqli-labs 第 32 关看字符集如何击穿 addslashes

原创

武文学网安 武文学网安

武文学网安

2026年1月23日 01:05 中国香港

大家好,我是武文。

在进入第 32 关之前,先简单交代一下进度上的取舍。

在 第 29 关 中,我们已经系统学习了 HTTP 参数污染(HPP) 的注入思想; 第 30 / 31 关本质仍然是 HTTP 参数污染,只是闭合方式从单引号变为双引号,因此不再展开,直接进入一个全新的考点。


一、第 32 关整体说明

第 32 关的官方标题:GET – Error based – Bypassing addslashes()

这一关的关键词只有一个: addslashes()

| 项目 | 说明 | | — | — | | 请求方式 | GET | | 页面回显 | 有报错 | | 注入类型 | 显错注入 | | 核心考点 | PHP 转义函数绕过 | | 本质问题 | 字符集不一致导致转义失效 |

这一关第一次把重点从过滤规则转移到了 “防御函数本身是否可靠”


二、原理:addslashes() 真的安全吗?

2.1 addslashes() 在做什么?

addslashes() 是 PHP 中一个非常常见的防御函数,用于给特殊字符加反斜杠:

'  →  \'"  →  \"\  →  \\NULL → \0

设计初衷是: 防止单引号破坏 SQL 语句结构

很多初学者甚至会形成一种错觉:“只要用了 addslashes(),就不会有 SQL 注入了。”

第 32 关,就是专门用来打破这个错觉的。

2.2 问题的根源:字符集不一致

addslashes() 的工作方式有一个隐含前提:它假设:一个字符 = 一个字节

但在真实环境中,尤其是 MySQL 使用 GBK / BIG5 等多字节字符集时,这个前提并不成立。

在 GBK 编码中:

  • 一个汉字 = 两个字节
  • 某些字节组合 恰好包含 0x5c(\)

这就会导致一个致命问题:addslashes() 转义的 \,可能只是多字节字符的一部分

一旦 MySQL 在解析时:

  • 把这两个字节当作一个合法字符
  • 而不是「转义 + 引号」

👉 转义就失效了


三、第 32 关实战通关

3.1 注入点确认

基础测试:

?id=1        → 正常?id=1'       → 正常?id=1"       → 正常

在Hint中发现单双引号都被加了‘\’,也就是说被addslashes() 转义为 \'


3.2 构造绕过思路(核心)

这一关的目标其实非常明确:让 MySQL 在解析时,“忽略” addslashes() 加上的反斜杠。

在ASCII编码中,反斜杠是0x5C。

addslashes() 的防御逻辑正是围绕它展开的——只要在单引号前加上 0x5C,就认为 SQL 结构被安全地转义了。

问题在于: 👉 MySQL 并不是总按 ASCII 解析字符串。

① 利用点:GBK 多字节编码

在 GBK 编码 中,一个字符通常由 两个字节 组成:

[高字节] [低字节]

而在 GBK 的字符集中,存在一类高字节范围为 0x81–0xFE 的字符,它们的低字节可以恰好是 0x5C(反斜杠)

这就产生了一个关键效果:0x5C 不再是“转义符”,而是“汉字的一部分”


② addslashes() 为什么会失效?

假设我们提交如下 payload(URL 编码):

%df%27

处理过程如下:

1️⃣ PHP 层(addslashes)看到的是:

0xDF 0x27   →   0xDF 0x5C 0x27

也就是

%df\'

2️⃣ MySQL 层(GBK 编码)看到的是:

0xDF 0x5C   →   一个合法的 GBK 汉字0x27        →   单引号

此时:

  • \ 并没有作为转义符存在
  • 单引号重新获得 SQL 语义

③ 最终结果

addslashes() 以为自己完成了转义 MySQL 实际上把转义字符“吃掉”了

最终效果就是:

  • 单引号成功闭合
  • SQL 结构被重新打断
  • 注入成立

👉 这正是第 32 关的核心突破点。

我在mysql中尝试用df来验证能否正常查询结果:

可以看到id=’1df\”仍然能够正常查询结果。

3.2.1 不止 %df:常见可用绕过字节总结

这里非常关键的一点是:并不是只有 %df能绕过 addslashes()

只要满足条件:

[GBK 高字节] + 0x5C

常见可用示例:

| | | | — | — | | 绕过字节 | URL编码形式 | | DF | %df%27 | | BF | %bf%27 | | A1 | %a1%27 | | A2 | %a2%27 | | A3 | %a3%27 |

这些字节的共同点是:

  • 位于 GBK 高字节区间
  • 与 0x5C 组合后可构成合法多字节字符

⚠️ 注意: 是否成功还与 数据库字符集 / 连接字符集 有关,并非所有环境都通用。本质上并不是这些字节“特殊”,而是它们位于 GBK 高字节区间,在 addslashes 插入 0x5C 后,仍能被 MySQL 解释为一个完整字符。

3.2.2 为什么这个漏洞在真实环境中非常危险?

因为它揭示了一个根本性问题:addslashes() 只在“字符集假设成立”的前提下才安全

一旦出现:

  • GBK / BIG5
  • 历史项目
  • 错误的字符集配置

那么:

  • 防御代码“看起来很安全”
  • 实际却是 完全失效

3.3 实际 payload(显错注入)

测试能否绕过反斜杠,构造payload:

?id=1%df'        报错?id=1%df"        正常?id=1%df' --+    正常

加入%df后单引号会引发语法错误,加入注释符后正常。说明闭合方式为单引号。

3.4 测试XPATH显错注入:

?id=1%df' and updatexml(1,concat(0x7e,database(),0x7e),1)--+

能够成功利用显错获取数据。

3.5 UNION 注入验证

继续验证 UNION:

?id=-1%df' union select 1,2,3--+

依然能够成功注入。

至此:

  • 显错注入 ✔
  • UNION 注入 ✔

第 32 关正式通关。


四、第 32 关在整个 sqli-labs 中的意义

如果回头看前面的关卡,会发现一条非常清晰的设计路径:

| 阶段 | 关注点 | | — | — | | 1–20 | SQL 语法与注入基础 | | 21-24 | 请求体注入方式 | | 25–28 | 黑名单过滤的脆弱性 | | 29–31 | HTTP 参数解析问题 | | 32 | 防御函数自身的安全边界 |

第 32 关第一次明确告诉我们:安全函数不是银弹,安全必须建立在完整上下文之上


五、总结

第 32 关并没有引入新的 SQL 技巧,却第一次把视角从「怎么过滤」转向了「防御本身是否可靠」。

它揭示了一个经常被忽视的事实:安全不是函数本身的属性,而是上下文的结果。

addslashes() 在假设「单字节字符集」时看似安全,一旦进入 GBK 等多字节环境,转义逻辑就可能被字符解析过程吞噬。

这一关真正教会我们的不是某个 %df payload,而是一个更重要的安全认知:SQL 注入从来不只是 SQL 的问题,它同时属于字符编码、解析顺序与环境假设。

任何脱离上下文讨论的“安全防御”,本身就是不完整的。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:武文学网安 武文学网安 武文学网安《当转义失效:从 sqli-labs 第 32 关看字符集如何击穿 addslashes》

评论:0   参与:  0