PwnCollege - RE - Behold the cIMG!

Behold the cIMG! (Python)

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
def main():
if len(sys.argv) >= 2:
path = sys.argv[1]
assert path.endswith(".cimg"), "ERROR: file has incorrect extension"
file = open(path, "rb")
else:
file = sys.stdin.buffer

header = file.read1(28)
assert len(header) == 28, "ERROR: Failed to read header!"

assert header[:4] == b"cIMG", "ERROR: Invalid magic number!"

assert int.from_bytes(header[4:12], "little") == 1, "ERROR: Invalid version!"

width = int.from_bytes(header[12:20], "little")

height = int.from_bytes(header[20:28], "little")

data = file.read1(width * height)
assert len(data) == width * height, "ERROR: Failed to read data!"

pixels = [Pixel(character) for character in data]

invalid_character = next((pixel.ascii for pixel in pixels if not (0x20 <= pixel.ascii <= 0x7E)), None)
assert invalid_character is None, f"ERROR: Invalid character {invalid_character:#04x} in data!"

framebuffer = "".join(
bytes(pixel.ascii for pixel in pixels[row_start : row_start + width]).decode() + "\n"
for row_start in range(0, len(pixels), width)
)
print(framebuffer)

nonspace_count = sum(1 for pixel in pixels if chr(pixel.ascii) != " ")
if nonspace_count != 275: # frame size
return

with open("/flag", "r") as f:
flag = f.read()
print(flag)


if __name__ == "__main__":
try:
main()
except AssertionError as e:
print(e, file=sys.stderr)
sys.exit(-1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from pwn import process

header = b"cIMG"
version = 1
width = 25
height = 11
data_length = width * height

file_header = struct.pack("<4sQQQ", header,version, width, height)

pixel_data = b"A" * data_length

payload = file_header + pixel_data

file = open("payload.cimg", "wb")
file.write(payload)
file.close()

p = process(["/challenge/cimg", "payload.cimg"], stdin=process.PTY, stdout=process.PTY)
print(p.recvall())

Behold the cIMG! (C)

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
// ...
#define CIMG_NUM_PIXELS(cimg) ((cimg)->header.width * (cimg)->header.height)
#define CIMG_DATA_SIZE(cimg) (CIMG_NUM_PIXELS(cimg) * sizeof(pixel_t))
// ...
int main(int argc, char **argv, char **envp)
{

struct cimg cimg = { 0 };
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 != 1)
{
puts("ERROR: Unsupported version!");
exit(-1);
}

unsigned long data_size = cimg.header.width * cimg.header.height * sizeof(pixel_t);
pixel_t *data = malloc(data_size);
if (data == NULL)
{
puts("ERROR: Failed to allocate memory for the image data!");
exit(-1);
}
read_exact(0, data, data_size, "ERROR: Failed to read data!", -1);

for (int i = 0; i < cimg.header.width * cimg.header.height; i++)
{
if (data[i].ascii < 0x20 || data[i].ascii > 0x7e)
{
fprintf(stderr, "ERROR: Invalid character 0x%x in the image data!\n", data[i].ascii);
exit(-1);
}
}

display(&cimg, data);

int num_nonspace = 0;
for (int i = 0; i < cimg.header.width * cimg.header.height; i++)
{
if (data[i].ascii != ' ') num_nonspace++;
}
if (num_nonspace != 275) won = 0; //frame size

if (won) win();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from pwn import process

header = b"cIMG"
version = 1
width = 25
height = 11
data_length = width * height

file_header = struct.pack("<4sQHH", header,version, width, height)

pixel_data = b"A" * data_length

payload = file_header + pixel_data

file = open("payload.cimg", "wb")
file.write(payload)
file.close()

p = process(["/challenge/cimg", "payload.cimg"], stdin=process.PTY, stdout=process.PTY)
print(p.recvall())

Behold the cIMG! (x86)

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
│ ┌┌─> 0x00401345      e816feffff     call sym.imp.puts           ;[2]
│┌───> 0x0040134a 83cfff or edi, 0xffffffff ; -1
│╎╎╎ 0x0040134d e8cefeffff call sym.imp.exit ;[3]
└────> 0x00401352 837c240e01 cmp dword [rsp + 0xe], 1 ; version -> 1 dword -> 4 bytes
╎╎╎ 0x00401357 488d3dd50d.. lea rdi, str.ERROR:_Unsupported_version_ ; 0x402133 ; "ERROR: Unsupported version!"
╎└──< 0x0040135e 75e5 jne 0x401345
╎ ╎ 0x00401360 440fb7642412 movzx r12d, word [rsp + 0x12]
╎ ╎ 0x00401366 440faf642414 imul r12d, dword [rsp + 0x14]
╎ ╎ 0x0040136c 4489e7 mov edi, r12d
╎ ╎ 0x0040136f e86cfeffff call sym.imp.malloc ;[4]
╎ ╎ 0x00401374 488d3dd40d.. lea rdi, str.ERROR:_Failed_to_allocate_memory_for_the_image_data_ ; 0x40214f ; "ERROR: Failed to all
╎ ╎ 0x0040137b 4889c3 mov rbx, rax
╎ ╎ 0x0040137e 4885c0 test rax, rax
╎ └─< 0x00401381 74c2 je 0x401345
╎ 0x00401383 4489e2 mov edx, r12d
╎ 0x00401386 4889c6 mov rsi, rax
╎ 0x00401389 4183c8ff or r8d, 0xffffffff ; -1
╎ 0x0040138d 31ff xor edi, edi
╎ 0x0040138f 488d0dee0d.. lea rcx, str.ERROR:_Failed_to_read_data_ ; 0x402184 ; "ERROR: Failed to read data!"
╎ 0x00401396 e880020000 call sym.read_exact ;[1]
╎ 0x0040139b 0fb7542412 movzx edx, word [rsp + 0x12] ; 2 bytes
╎ 0x004013a0 0faf542414 imul edx, dword [rsp + 0x14] ; 4 bytes
╎ 0x004013a5 31c0 xor eax, eax
╎ ┌─> 0x004013a7 39c2 cmp edx, eax
╎┌──< 0x004013a9 762f jbe 0x4013da
╎│╎ 0x004013ab 0fb60c03 movzx ecx, byte [rbx + rax]
╎│╎ 0x004013af 48ffc0 inc rax
╎│╎ 0x004013b2 8d71e0 lea esi, [rcx - 0x20]
╎│╎ 0x004013b5 4080fe5e cmp sil, 0x5e ; '^' ; 94
╎│└─< 0x004013b9 76ec jbe 0x4013a7
╎│ 0x004013bb 488b3d7e2c.. mov rdi, qword [obj.stderr] ; obj.stderr__GLIBC_2.2.5
╎│ ; [0x404040:8]=0
╎│ 0x004013c2 488d15d70d.. lea rdx, str.ERROR:_Invalid_character_0x_x_in_the_image_data__n ; str.ERROR:_Invalid_character_0x_x_
╎│ ; 0x4021a0 ; "ERROR: Invalid character 0x%x in the image data!\n"
╎│ 0x004013c9 be01000000 mov esi, 1
╎│ 0x004013ce 31c0 xor eax, eax
╎│ 0x004013d0 e85bfeffff call sym.imp.__fprintf_chk ;[5]
└───< 0x004013d5 e970ffffff jmp 0x40134a
└──> 0x004013da 4889de mov rsi, rbx
0x004013dd 4889ef mov rdi, rbp
0x004013e0 e886020000 call sym.display ;[6]
0x004013e5 0fb74c2412 movzx ecx, word [rsp + 0x12]
0x004013ea 31c0 xor eax, eax
0x004013ec 31d2 xor edx, edx
0x004013ee 0faf4c2414 imul ecx, dword [rsp + 0x14]
┌─> 0x004013f3 39c1 cmp ecx, eax
┌──< 0x004013f5 760d jbe 0x401404
│╎ 0x004013f7 803c0320 cmp byte [rbx + rax], 0x20
┌───< 0x004013fb 7402 je 0x4013ff
││╎ 0x004013fd ffc2 inc edx
└───> 0x004013ff 48ffc0 inc rax
│└─< 0x00401402 ebef jmp 0x4013f3
└──> 0x00401404 81fa13010000 cmp edx, 0x113 ; 275
┌─< 0x0040140a 7507 jne 0x401413
│ 0x0040140c 31c0 xor eax, eax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from pwn import process

header = b"cIMG"
version = 1
width = 25
height = 11
data_length = width * height

file_header = struct.pack("<4sIHI", header,version, width, height)

pixel_data = b"A" * data_length

payload = file_header + pixel_data

file = open("payload.cimg", "wb")
file.write(payload)
file.close()

p = process(["/challenge/cimg", "payload.cimg"], stdin=process.PTY, stdout=process.PTY)
print(p.recvall())