We were given the following files:
$ ls -latotal 804drwxrwxr-x 3 kali kali 4096 Nov 9 17:01 .drwxr-xr-x 15 kali kali 4096 Nov 9 15:44 ..-rwxrwxr-x 1 kali kali 18632 Nov 5 15:49 cat-rw-rw-r-- 1 kali kali 774592 Nov 5 15:49 core.39382cat program takes a file as command line argument, opens it and reads random sizes that it generates (0x8, 0x18, 0x28, …, 0x318) of file into the heap in a while-loop until the file is completely read.
int main(int argc,char **argv)
{
...SNIP...
if (argc != 2) {
puts("./cat [file]");
exit(1);
}
seed = time((time_t *)0x0);
srand((uint)seed);
__fd = open(argv[1],0);
while( true ) {
random_no = rand();
__size = (size_t)((random_no % 0x32) * 0x10 + 8);
__buf = malloc(__size);
ret = read(__fd,__buf,__size);
if (ret == 0) break;
write(1,__buf,__size);
}
free(::brk);
return 0;
}Analyzing the virtual memory of the process in gdb using the provided core dump, we see that that load5 looks like heap.
$ gdb -q ./cat core.39382...SNIP...pwndbg> vmmapLEGEND: STACK | HEAP | CODE | DATA | WX | RODATA Start End Perm Size Offset File (set vmmap-prefer-relpaths on) 0x64fee8b1a000 0x64fee8b1b000 r--p 1000 0 /home/dog/Desktop/heap_exploitation/cat 0x64fee8b1b000 0x64fee8b1c000 r-xp 1000 1000 /home/dog/Desktop/heap_exploitation/cat 0x64fee8b1c000 0x64fee8b1d000 ---p 1000 2000 /home/dog/Desktop/heap_exploitation/cat 0x64fee8b1d000 0x64fee8b1e000 r--p 1000 2000 /home/dog/Desktop/heap_exploitation/cat 0x64fee8b1e000 0x64fee8b1f000 ---p 1000 3000 /home/dog/Desktop/heap_exploitation/cat 0x64ff01557000 0x64ff01578000 ---p 21000 0 load5 0x7d2545800000 0x7d2545828000 r--p 28000 0 /usr/lib/x86_64-linux-gnu/libc.so.6...SNIP..Looking at the heap memory we find the header of a .png file starting at 0x64ff015572a0:
pwndbg> dq 0x64ff01557000 100000064ff01557000 0000000000000000 0000000000000291...SNIP...000064ff01557290 0000000000000000 0000000000000301000064ff015572a0 0a1a0a0d474e5089 524448490d000000000064ff015572b0 49010000a9040000 e95ddf0000000208000064ff015572c0 47527301000000cc 0000e91cceae0042000064ff015572d0 0000414d41670400 00000561fc0b8fb1000064ff015572e0 0000735948700900 c701c30e0000c30e000064ff015572f0 492f36000064a86f bddded5e78544144000064ff01557300 85b7e1c6dbb6dc95 982b158a24e1402d000064ff01557310 2db402e016c3dfec 276281ddb09a9228
pwndbg> x/s 0x000064ff015572a00x64ff015572a0: "\211PNG\r\n\032\n"If you don’t know how the glibc heap looks like in memory, please read this excellent blog by azeria on heap implementation in glibc. But, in a nutshell heap consists of chunks whose structure looks like this:

What we want is to dump the data of all the chunks until we reach the end of the .png file (0000000049454E44AE426082).
We can do just that using gdb scripting by writing a while-loop that transverses the heap chunks dumping data of each chunk until it reaches the chunk containing the IEND.
pwndbg> search IENDSearching for byte: b'IEND'warning: Unable to access 4096 bytes of target memory at 0x64fee8b1c000, halting search.load5 0x64ff0155aa5a 0x826042ae444e4549
pwndbg> set $cur = 0x64ff015572a0pwndbg> set $stop = 0x64ff0155aa38pwndbg> set $i = 0pwndbg> while $cur < $stop >set $size = *((unsigned long long *) ($cur - 8)) & ~1ULL >eval "dump memory chunk%02d.bin %p %p", $i, $cur, ($cur + $size - 8) >set $cur = $cur + $size >set $i = $i + 1 >endpwndbg> dump memory chunk35.bin 0x64ff0155aa40 0x64ff0155aa5a+8If we take a look at the main() function we will notice that if the random number is 0 then, the __size = (0)*0x10 + 8 = 8 but, the smallest chunk that malloc() returns is 0x18 size. Here the program is only using the first 8-bytes of chunk while the rest 0x10 bytes are null bytes so, we have to trim them so they don’t corrupt the image.
Looking at all the 0x18-byte chunks we find that the chunk04.bin has two null qwords:
$ ls -la | grep ' 24 '-rw-rw-r-- 1 kali kali 24 Nov 9 17:50 chunk04.bin-rw-rw-r-- 1 kali kali 24 Nov 9 15:26 chunk12.bin-rw-rw-r-- 1 kali kali 24 Nov 9 15:27 chunk18.bin
$ xxd chunk04.bin00000000: 5e69 ba20 6f34 a5fd 0000 0000 0000 0000 ^i. o4..........00000010: 0000 0000 0000 0000 ........
$ xxd chunk12.bin00000000: 4a99 41ec b9a3 4afd f7ef f9cf a075 7dcc J.A...J......u}.00000010: d20d ae77 1c99 d9db ...w....
$ xxd chunk18.bin00000000: fb9f 1f3c c694 7594 de91 26ee 9ac6 4cb3 ...<..u...&...L.00000010: ccfe 6c30 eea6 32b7 ..l0..2.Let’s trim them using python:
$ python3
...SNIP...
>>> open("chunk04.bin", 'rb').read()[0:8]
b'^i\xba o4\xa5\xfd'
>>> open("chunk04.bin", 'wb').write(b'^i\xba o4\xa5\xfd')
8Now, combining the chunks yields the image:
$ cat $(ls -v chunk*.bin) > final.png