PwnCollege - RE - Tweaking Images

Tweaking Images

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
int main(int argc, char **argv, char **envp)
{

struct cimg cimg = { 0 };
cimg.framebuffer = NULL;
int won = 1;

if (argc > 1)
{
if (strcmp(argv[1]+strlen(argv[1])-5, ".cimg"))
{
printf("ERROR: Invalid file extension!");
exit(-1);
}
dup2(open(argv[1], O_RDONLY), 0);
}

read_exact(0, &cimg.header, sizeof(cimg.header), "ERROR: Failed to read header!", -1);

if (cimg.header.magic_number[0] != 'c' || cimg.header.magic_number[1] != 'I' || cimg.header.magic_number[2] != 'M' || cimg.header.magic_number[3] != 'G')
{
puts("ERROR: Invalid magic number!");
exit(-1);
}

if (cimg.header.version != 3)
{
puts("ERROR: Unsupported version!");
exit(-1);
}

initialize_framebuffer(&cimg);

while (cimg.header.remaining_directives--)
{
uint16_t directive_code;
read_exact(0, &directive_code, sizeof(directive_code), "ERROR: Failed to read &directive_code!", -1);

switch (directive_code)
{
case 55369:
handle_55369(&cimg);
break;
case 52965:
handle_52965(&cimg);
break;
default:
fprintf(stderr, "ERROR: invalid directive_code %ux\n", directive_code);
exit(-1);
}
}
display(&cimg, NULL);
}

generate a flag image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
raw_flag_lines = subprocess.check_output(["/usr/bin/figlet", "-fascii9"], input=open("/flag", "rb").read()).split(b"\n")
max_line_length = max(len(line) for line in raw_flag_lines)
flag_lines = [ line.ljust(max_line_length) for line in raw_flag_lines ]

flag_pixels = [ ]
for y,line in enumerate(flag_lines):
for x,c in enumerate(line):
flag_pixels += [ (x, y, c) ]
random.shuffle(flag_pixels)

directives = [ ]
for p in flag_pixels:
directives += [ struct.pack("<HBBBBBBBB", 2, p[0], p[1], 1, 1, 0x8c, 0x1d, 0x40, p[2]) ]

img = b"cIMG" + struct.pack("<HBBI", 3, max_line_length, 1, 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
72
73
74
75
76
77
import struct

from pwn import *
from pwn import ELF, log, process

def fix_image():
img_path = "/challenge/flag.cimg"
binary_path = "/challenge/cimg"

try:
with open(img_path, "rb") as f:
broken_img = f.read()
except FileNotFoundError:
log.error(f"Cannot find {img_path}. Are you in the right environment?")
return

# 1. 解析损坏的 Header
header_format = "<4sHBBI"
header_size = struct.calcsize(header_format)

magic, version, width, height, num_directives = struct.unpack(
header_format, broken_img[:header_size]
)

# 2. 动态计算真实的 Height
real_height = num_directives // width

log.info("--- Image Header Analysis ---")
log.info(f"Magic: {magic}")
log.info(f"Version: {version}")
log.info(f"Width: {width}")
log.warning(f"Fake Height from file: {height}")
log.success(f"Calculated Real Height: {num_directives} / {width} = {real_height}")

# 3. 重新打包 Header
fixed_header = struct.pack(
header_format, magic, version, width, real_height, num_directives
)

# 4. 逐个修复 Directives
fixed_directives = bytearray()
directive_size = 10
expected_opcode = 2
fixed_opcode = 52965

offset = header_size
for i in range(num_directives):
chunk = broken_img[offset : offset + directive_size]
if len(chunk) < directive_size:
break

opcode, x, y, w, h, r, g, b, char = struct.unpack("<HBBBBBBBB", chunk)

if opcode == expected_opcode:
new_chunk = struct.pack(
"<HBBBBBBBB", fixed_opcode, x, y, w, h, r, g, b, char
)
fixed_directives += new_chunk
else:
fixed_directives += chunk

offset += directive_size

# 5. 组装修复后的镜像
fixed_img = fixed_header + fixed_directives

fixed_path = "fixed_flag.cimg"
with open(fixed_path, "wb") as f:
f.write(fixed_img)

p = process([binary_path, fixed_path], stdin=process.PTY, stdout=process.PTY)

print(p.recvall().decode(errors="ignore"))


if __name__ == "__main__":
fix_image()
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
 mmmm  m     m m mm           mmm    mmm     #      #     mmm    mmmm   mmm
#" "# "m m m" #" # #" " #" "# # # #" # #" "# #" #
# # #m#m# # # # # # # # #"""" # # #""""
##m#" # # # # # "#mm" "#m#" "mm "mm "#mm" "#m"# "#mm"
# m #
" ""

m"" mmmmm m m m m m # #
# mmm # "# # mmm ## ## # m" mmm# mmmm # m
mm" #" "# #mmm#" # #" "# # ## # #m# #" "# #" "# # m"
# # # # # # # # "" # # #m # # # # #"#
# "#m#" # #mmmmm "#m#" # # # "m "#m## "#m## # "m
"" #
" """"""

mmmm mmm m m m m mmm m mmmmm
m m # "m m" " # # # # m" " mm#mm mmm mmm mmmm #
# # # # # mm #mmmm# ## #m""#m # #" # " # #" "# #
# # # # # # # # m""m # # # #"""" m"""# # # #
"mm"# #mmm" "mmm" # # m" "m #mm#" "mm "#mm" "mm"# "#m## mm#mm
#
"

mmmmmm mmm mmm mmmm m m mmmmm mmmmmm
m m m mm #" m" " m" " mmm m" "m # # # #
"m m m" #" # m# # # mm #" " # # ## """"mm #mmmmm
#m#m# # # m" # # # # # # m""m # #
# # # # ##mmmm "mmm" "mmm" "#mm" # #mm#" m" "m "mmm#" #mmmmm
#


m m mmmmmm mmmm m mm " m m mmm
mmmmm ## ##m m # # "m # m"# mmm mmm ## ## #
m" # ## #"m m m" #mmmmm # # # #" # #" " # # ## # #
m" # "" # #m#m# # # # # #mmm#m # # # "" # #
#mmmm # # # # #mmmmm #mmm" #mmmmm # "#mm" # # # mm#mm
#
""

m m ""m
mmmm mmmmm # # # #
#" "# m" " #"# # "mm
# # m" ## ##" #
"#m"# #mmmm # # #
m # ""
""