PwnCollege - RE - Extracting Knowledge

Extracting Knowledge

How well do you grasp the cIMG format? This is a chance to show yourself just how much you’ve learned!

This level’s /challenge/cimg has no way to give you the flag, but we’ll give you a cimg file containing it!

generate the flag.cimg

1
2
3
4
5
6
7
8
9
10
11
12
sprites = { }
directives = [ ]
for c in open("/flag", "rb").read().strip():
if c not in sprites:
sprites[c] = len(directives)
sprite = subprocess.check_output(["/usr/bin/figlet", "-fascii9"], input=bytes([c])).split(b"\n")[:-1]
directives += [ struct.pack("<HBBB", 3, sprites[c], len(sprite[0]), len(sprite)) + b"".join(sprite) ]
directives += [ struct.pack("<HBBBBBB", 4, sprites[c], 0xff, 0xff, 0xff, 0, 0) ]

img = b"cIMG" + struct.pack("<HBBI", 3, 16, 16, len(directives)) + b"".join(directives)
with open("/challenge/flag.cimg", "wb") as o:
o.write(img)
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
import struct
import sys

def parse_and_dump_flag():
img_path = "/challenge/flag.cimg"
try:
with open(img_path, "rb") as f:
data = f.read()
except FileNotFoundError:
print(f"[!] Cannot find {img_path}.")
return

# 1. 解析 Header
header_format = "<4sHBBI"
header_size = struct.calcsize(header_format)
magic, version, width, height, num_directives = struct.unpack(
header_format, data[:header_size]
)

if magic != b"cIMG":
print("[!] Invalid magic number.")
return

print(f"[*] Parsed Header: {num_directives} directives found.")

offset = header_size
sprites = {}
flag_sequence = []

# 2. 遍历所有的 Directives
for _ in range(num_directives):
opcode = struct.unpack("<H", data[offset : offset + 2])[0]
offset += 2

if opcode == 3:
# Handle 3: 注册 Sprite
sp_id, sp_w, sp_h = struct.unpack("<BBB", data[offset : offset + 3])
offset += 3

# 读取 Figlet 原始字符数据
raw_sprite = data[offset : offset + sp_w * sp_h]
offset += sp_w * sp_h

# 还原 2D 文本结构
art = ""
for i in range(sp_h):
line = raw_sprite[i * sp_w : (i + 1) * sp_w]
art += line.decode(errors="ignore") + "\n"
sprites[sp_id] = art

elif opcode == 4:
# Handle 4: 渲染 Sprite
# 只需要记录它渲染了哪个 ID
sp_id, r, g, b, x, y = struct.unpack("<BBBBBB", data[offset : offset + 6])
offset += 6
flag_sequence.append(sp_id)

print("[*] Data extraction complete.\n")
print("=" * 60)

# 3. 按调用顺序打印出 Flag 对应的 Figlet 字符
for sp_id in flag_sequence:
if sp_id in sprites:
print(sprites[sp_id])
print("-" * 60)
else:
print(f"[!] Warning: Missing dependency for sprite ID {sp_id}")


if __name__ == "__main__":
parse_and_dump_flag()

pwn.college{**********************************************}