Back

EXPLOIT EDUCATION - NEBULA

Nebula covers a variety of simple and intermediate challenges that cover Linux privilege escalation, common scripting
language issues, and file system race conditions.Nebula is an ideal place to get started for people new to Linux
exploitation.Hints will be provided in this walkthrough to give a chance for your wheels to spin.
Try your best to solve each level on your own before looking at the solution. Goodluck!!!


level00

Username : level01
Password : level01

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.
Files for this level can be found in /home/flag00.

You are looking for commands that can search for files based on its permissions and user.

Use the find command.

We can use the find command to search for this file.

find / -perm -u=s -user "flag00" 2> /dev/null


this command will search the direcrtory / (which means it will search for the file everywhere.)
-perm option lets us search for a file with matching permissions.
;eg.-perm u=r will search for files that exacly match the specified permission.(files with read permissions only for the user.).That is why we specified -u=s for permission so that the command searches for files that also has the suid bit set and not for files that has only the suid bit set.
-user searches for files that are owned by the user flag00.
2> /dev/null redirects the error (stderr) to /dev/null, which is a file that accepts and discards anything and everything.(its morelike a small blackhole inside linux.)
We get two files when we run the find command.
Now we execute the file

/bin/.../flag00

level01

Username : level01
Password : level01

There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
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?");
}

char *buffer;
gid = getegid();
uid = geteuid();

The group id , user id of the current user is copied into the gid and uid using the getegid() and geteuid() functions. (Get Effective group id and Get Effective User id functions)

gid = getegid();
uid = geteuid();

Then the setresgid, setresuid functions are used to set gid and uid of the current user. setresgid - set real, effective and saved user or group ID setresuid - set real, effective and saved user or user ID

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

Echo command is used to print "and now what?"

We here can make use of shell functions.

Find out how to export shell funtions. Which command here can be changed into a shell function that is called by the program itself ?

You may need to use bash to solve this level.
Create a shell function called /usr/bin/env(). Use the function to run the getflag command.

We can either change the environment variables or use shell funtions for this level. We will be using shell functions.
Create the function using

function /usr/bin/env() { getflag; }

Now we will have to export the function and execute the program using

export -f /usr/bin/env
./flag01

Now he program runs the getflag for us.

level02

Username : level02
Password : level02

There is a vulnerability in the below program that allows arbitrary programs to be executed, can you find it?
Files for this level can be found in /home/flag02.

Source Code


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

char *buffer;
gid = getegid();
uid = geteuid();

A character pointer is declared. (Can be used to store strings.) The group id , user id of the current user is copied into the gid and uid using the getegid() and geteuid() functions. (Get Effective group id and Get Effective User id functions)

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

Then the setresgid, setresuid functions are used to set gid and uid of the current user. setresgid - set real, effective and saved user or group ID setresuid - set real, effective and saved user or user ID

buffer = NULL; asprintf(&buffer, "/bin/echo %s is cool", getenv("USER")); printf("about to call system(\"%s\")\n", buffer);

The character string is set to null and the string "USER is cool" is copied into the "buffer" string which is print out in the next command using the printf() function. Where "USER" is substituted by the environment variable USER. To see the USER environment variable, just run

env | grep USER

Then, the system() function is used to execute the "buffer" string.

system(buffer);

i.e In this case it will execute "echo level02 is cool".

Manipulate an environment variable

The program is executing a line of command for us. Think what all to add to the environment variable so that we can execute what we want.

Change the environment varibale to include multiple commands.

We will be changing the environment variable USER which is used by the program . Multiple commands can be executed in one line using " ; ".
Change the USER environment variable and execute the program by :

USER=hello\;getflag\;echo

The reason for such behaviour is the code that is executed by the c program using the system() fucntion. The code that is executed is :

echo hello ;getflag ;echo is cool


Allowing us to execute getflag.

level03

Username : level03
Password : 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.
Files for this level can be found in /home/flag03.

The writable.sh is executed every couple of minutes. writable.sh
Every file in /home/flag03/writable.d, is executed and then removed.
ulimit -t : ulimit limits the resource usage of a process. The -t 5 sets the time limit to 5 seconds.
bash -x: Prints the command before executing it. This mode is very useful when debuggging code.

You just need to add a file to the writable.d folder

You need to add a file into writable.d directory that executes the getflag for us. And as proof that it was executed, redirect the output into the out.txt file in the parent directory.

A file called code.sh is created and "getflag > out.txt" is written into it.
When executed, the the ouput of the getflag is redirected to out.txt

level04

Username : level04
Password : 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 :)
Files for this level can be found in /home/flag04.

Source Code

#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);
}
if(argc == 1) {
      printf("%s [file to read]\n", argv[0]);
      exit(EXIT_FAILURE);
 }

Argc is the number of command line arguments used while executing the program including the name of the c program . So if there are no command line arguments, argc = 1.
The above condition checks whether there were any command line arguments while executing the program and if there are none, prints the correct way to use this executable.

if(strstr(argv[1], "token") != NULL) {
      printf("You may not access '%s'\n", argv[1]);
      exit(EXIT_FAILURE);
  }

argv is the list of command line arguments including the name of the program where argv[0] is the name of the program and the rest are the command line arguments.
Strstr() function checks for the occurance of a string within another string.

If the command line argument specified (which is the file to be read according to this program) contains the string "token" in it, it denies access to the file as shown above.

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

The file specified is opened and any error in opening or reading the file is checked for and results in program temination.

write(1, buf, rc);

If no error are encountered, the file read is printed.

Think of other ways to point to a file. You know about it if you know linux basics.

We will be using links to refer to the token file.


To execute getflag, we need to switch to the flag04 account. So we can switch to flag04 using the content of the token file as password and execute getflag.


level05

Username : level05
Password : level05

Check the flag05 home directory. You are looking for weak directory permissions. To do this level, log in as the level05 account with the password level05. Files for this level can be found in /home/flag05.

Use the ssh key to login to the appropriate account.

Use the ssh -i command.

Extract the file found in the .backup file using the tar command.

-C option of the tar command lets you extract the file to a specific directory.
The ssh key (id_rsa) can be used to login to the flag05 account after which the getflag command can be executed. I couldn't ssh to flag05 account so i had to use another machine to ssh into the account.

level06

Username : level06
Password : level06

The flag06 account credentials came from a legacy unix system. To do this level, log in as the level06 account with the password level06. Files for this level can be found in /home/flag06.

Traditionally, the /etc/passwd file is used to keep track of every registered user that has access to a system. The passwd file contains the information of every users including the username,encrypted password, user id, group id etc. But the passwd file is readable by everyone which means the encrypted password was up for grabs making it an easy attack vector.

Crack the password. You can use johnny the ripper.

Since the credentials are from legacy unix system, the /etc/passwd contains the encrypted password of the flga06 user. So we copy the password of the flag06 user and store it in pass.tx using grep and tee commands.

tee command splits the output into two and reditects one into the file pass.txt and the other to stdout.
The tee command is not at all a necessity, I just used it to show you its usage. Then, we use john (johnny the ripper) to crack the password.

Just to be clear, the password is "hello". The password is used to login to flag06 and execute the getflag.

level07

Username : level07
Password : level07

The flag07 user was writing their very first perl program that allowed them to ping hosts to see if they were reachable from the web server. To do this level, log in as the level07 account with the password level06. Files for this level can be found in /home/flag07.

Source Code

#!/usr/bin/perl

use CGI qw{param};

print "Content-type: text/html\n\n";

sub ping {
  $host = $_[0];

  print("<html><head><title>Ping results</title></head><body><pre>");

  @output = `ping -c 3 $host 2>&1`;
  foreach $line (@output) { print "$line"; }

  print("</pre></body></html>");
  
}

# check if Host set. if not, display normal page, etc

ping(param("Host"));

This program takes the first argument it receives, pings it and prints the output. From the config file thttpd.conf, we can find out the port number used by the scipt. We can see the output by visiting the page using curl .

curl http://<ip addr of machine>:7000/index.cgi?Host=127.0.0.1

In the program the value of Host is passed on to the ping funciton. Here the passed value is stored into a 'host' variable ($_[0] means the first argument passed into the function). That value is later used in the ping command to ping the specified host and the output is printed out.
Reading this may help you: How can i call shell command in my perl scirpt

If executing system commands from a program doesnt ring any bells i dont know what does. You can manipulate the input to chain commands.

You may need to use URL encoding.

The command we can try to execute is

ping -c 3 127.0.0.1;getflag

I first tied to use the query string (the whole request is in quotes or else our system splits the command into two)

?Host=127.0.0.1;getflag
So i url encoded ';' which is %3B.
curl http://<ip addr of machine>:7000/index.cgi?Host=127.0.0.1%3Bgetflag

level08

Username : level08
Password : level08

World readable files strike again. Check what that user was up to, and use it to log into flag08 account.To do this level, log in as the level08 account with the password level08. Files for this level can be found in /home/flag08.

There is a .pcap file in the home dir of flag08. We can use wireshark to open the file and read it.

level08@nebula:~$ cd /home/flag08
level08@nebula:/home/flag08$ ls
capture.pcap

We can copy this file to our machine using scp (secure copy). Just like cp command, the scp requires a souce and destinaiton

scp level08@192.168.196.149:/home/flag08/capture.pcap .

Use wireshark to analyse the file

wireshark capture.pcap

We can see that a login was attempted and we even have the credentials. Right click on a packet and select TCP Stream in the Follow option.We can see the username and password. But, there is a catch.

The non printable characters are represented with '.'. Find out what they actually represent. You may want to see the data as hex instead of ascii.

The non printable characters were hex values '7f' and '0d'. 7f represents backspace and 0d represents Carriage Return. So the password is not backdoor...00Rm8.ate but insteas is 'backd00Rmate'.
You can now switch user to flag08 and execute the getflag.