Hell Walkthrough
So, Peleus released a vulnerable VM on VulnHub, also known as a “boot2root”, called Hell.
A lot of the techniques in this VM are known to me apart from the very last step. I will go through my thought process for each step and how I managed to go from enumeration to a root shell.
@0x42424242 Finally rooted your fucking VM :P
Scoping the Joint
NMAP - the start of any fulfilling enumeration stage. I ran a simple NMAP scan against the VM, which returned the following results
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
OK, so we have SSH, HTTP and apparently Doom (yay Doom !) servers running. Based on previous experience, port 666 is more likely to be a service that is hidden behind a well known port. I wont go into the details of port 666 nor the service behind it, but lets say it’s a distraction and a diversionary tactic - don’t go there unless you want to waste time. Unless you want to waste time, in which case fire up Netcat and go for your life !
Visting the web server in a browser presents a pretty boring page that welcomes us to the server and shows a cartoon.
This doesn’t give us much to go on, therefore let’s try out some simple things any pentester should try - let’s see if a robots.txt file exists. Well what do you know…
The /personal/ folder shows a creepy shrine site (this is incidentally the closest I’ve ever been to the face of a cow)
Yeah, creepy… The /super_secret_login_path_muhahaha/ folder presents a login page
Getting In
It is assumed the username is either admin or jack, and the password relates to g0tmi1k in some way because this Jack guy is quite smitten. I could run Rockyou against the login page, but let’s think simpler and first make a word list from the shrine site and mutate it a little with John The Ripper using a modified ruleset as per netsec.ws
1 2 3 4 5 6 7 8 9 10 11 |
|
Now we have a password list, we can use hydra to brute force the login.
1 2 3 4 5 6 7 8 9 10 |
|
Success, username jack, password g0tmi1k69 (yes, more creepiness, this Jack guy needs locking up). Using these credentials presents us with a management style interface
I won’t explain each section, but the two sections we are going to use are Notes and Personal. Notes allows us to write arbitrary text to a note.txt file stored in “temporary storage”, which is assumed to be /tmp as this is usually what people define as temporary storage.
Personal presents another login page, which sets a cookie which has an attribute that increases with each failed login.
When you hit 3 failed logins, the page reverts to the main panel, and adds an error message to the top.
On further investigation, the intruder attribute of the cookie is set which defines the file that is included at the top of the panel. I wonder if there’s a local file inclusion vulnerability there. I went about editing the cookie to try and include other files on the filesystem. After a few minutes of frustration, I worked out that the code was filtering any instance of ../ in the include path - however, being the sneaky person I am, I discovered this can be bypassed by using ….// or …/./ instead. Here’s /etc/passwd included by setting the intruder cookie attribute to ….//….//….//….//etc/passwd
It looks like the page parses any code (HTML etc) in the included file, therefore we can poison the note.txt file with PHP via the Notes feature, and include it to execute the code. First, a PHP based reverse staged Meterpreter is created and hosted on an HTTP server.
1
|
|
As we are using a staged payload, a handler is required, therefore one is set up via Metasploit
1 2 3 4 5 6 7 8 9 10 11 |
|
Once the failed login cookie is cleared to allow us to get to features again, the following is added to the note.txt file via the Notes feature, which will download our payload from our HTTP server to the /tmp folder on the host
1
|
|
Three failed logins are once again performed via the Personal feature to create the cookie, which is modified to include /tmp/note.txt (which includes our download PHP command)
When the main panel page is reloaded, our poisoned note.txt file is included, the PHP is parsed and our payload file is downloaded.
We’re onto something here ! The cookie is edited once again to include /tmp/sneaky.txt and the panel page reloaded to execute stage 1 of our Meterpreter payload, which makes a connection to our waiting handler.
1 2 3 4 |
|
Now would be a good time for a party, but there’s hacking to do. Plus I have no cake or balloons. Or friends. whimper … HACKING !!!
The Metepreter session can be used to get a shell, which doesn’t seem to be TTY, but we can fix that with a nifty command thanks to g0tmi1k himself (who is presumably hiding from Jack, the creepy so-and-so). The id command shows that we are currently under the context of the www-data user.
1 2 3 4 5 6 7 8 |
|
BAM ! We’ve just started the journey.
Catting /etc/passwd gives us a list of users that are potentially useful
1 2 3 4 5 6 7 8 9 |
|
Imagine Jack and Jill, But With Half the Cast Replaced with a Cardboard Cutout of g0tmi1k
Escalating from the www-data user to the jack user is pretty inconsequential. People who write web sites, especially disturbing ones such as this, will usually not bother to create separate accounts for things such as database logins.
A quick grep on the files in /super_secret_login_path_muhahaha/ for the word “password” results in the following
1 2 3 4 5 6 |
|
Oooh, what do I spy with my little eye ? Could that be Jack’s password commented out in login.php ? Let us try this password…
1 2 3 4 5 6 |
|
Well, that was easy. But then the 2nd hurdle usually is - you kinda get cocky after clearing the first one, that the second one is jumped based on pure thrill. Now we get to trip over on every hurdle between us and the finish line. Get the first aid kit ready, we’re going to need it.
Got Milk ? Want Any ?
Poking around Jack’s home folder is like walking into a public toilet while bursting for a wee - you don’t really want to touch anything, but have to else you’re going to have problems.
The first thing that draws my eye is the g0tmi1k_pics folder. It’s somewhere you know you don’t want to go, but seems to have this strange come-hither vibe about it. It’s like a car crash… gruesome but you can’t help but look. So I did. Now I wish I didn’t. Exhibit A, and B, and C.
Yeah… Jack, you’re a strange one, I’ll give you that. Hang on, I think I can hear the men in white coats knocking. Yup, they’re asking for you - shall I tell them you’re “out” ?
So, while Jack might reuse passwords, he’s sensible enough to use PGP when sending emails. /var/mail/jack/received contains an email, which is encrypted.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
As suspected, Jack uses PGP on the local host, therefore his PGP keys are stored in /home/jack/.pgp, complete with a note giving us a password hint.
1 2 3 4 5 6 7 8 9 |
|
We can assume the password is either g0tmi1k69 or zgcR6mU6pX. GPG is installed, so the next logical step is to try and decrypt the email using either of these two passwords and Jack’s PGP private key.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Thank you, Jack, for being a predictable - yet persistent - weirdo. A quick hop and a skip over to the worryingly named milk_4_life account and we can carry on.
1 2 3 4 5 6 |
|
I Want to Play a Game, But No Jigsaws, OK ?!
The home folder for milk_4_life is pretty sparse, just a binary called “game”. However, it’s owned by the george user, and has the suid attribute set.
1 2 3 |
|
Running the binary produces the following output, which doesn’t tell us much other than it’s “listening”. Like a overly intrusive neighbour.
1 2 |
|
Netstat isn’t available on this VM, so we have to find another way to obtain listening port information. Thankfully ss saves the day and shows the game binary IS actually listening, on port 1337 - h4x !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Connecting to the port from another session asks us to type “START” to begin. It’s more fun to troll the code, though, by typing something completely different. Did you expect anything less of me ?
1 2 3 4 5 6 7 8 9 10 |
|
OK, enough messing around, let’s see what this game does. Typing START presents us with a high score, and then math questions that only your high school math teacher would ask you infront of the rest of the class. Needless to say I’m not answering any of these correctly !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Being the competitive person I am, I figured it would be fun to try and beat the score. More than 133723 points in 30 seconds means I have to answer 4457 correct answers a second. I can type quickly, but not that quickly. This requires some scripting - Python to the rescue ! This script connects to the game, reads the question, splits it based on “ x ” to get both numbers, performs the multiplication and sends the answer back. Granted I had some help on with this code - thanks c0ne !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Running it produces a sense of authority over our robot overlords - I’m gaming the game.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
It seems that the binary performs an action when the highscore is beaten. I’m not sure what it chmods, but I wonder if we can play this game at it’s own game and make it run a bogus binary. There’s a distinct possibility the code is relying on the PATH environment variable and just calling system(“chmod file”) rather than using an absolute path.
So, a bogus chmod binary is created using the following source, compiled, placed in /tmp on the VM and made executable (do I need to show you how to do this ? No ? Good. Saves me the typing.)
1 2 3 4 5 6 7 8 9 10 |
|
The path environment variable is modified to make /tmp the first location checked
1 2 3 |
|
So, hopefully, if all goes to plan, when we beat the score it should run our fake chmod binary and drop us to a shell. How about we give it a go ? The game is started, and the Python script is run to beat the score (I’m not going to show you again, just scroll up if you want to see what it looks like).
The score is beaten and we are indeed dropped to a new shell as the george user.
1 2 3 4 |
|
Tales from the Crypt, But First I’ll Rock You
George has one file in his home folder - a Truecrypt container. I guess no one has told George that TrueCrypt isn’t recommended any more - he should be using something else. shakes fist at the NSA
Mounting the TrueCrypt container requires us to know the container password, which we currently don’t have.
1 2 3 4 5 6 |
|
Looking around a bit more, it looks like George has also signed up for RockYou
1 2 3 4 5 6 |
|
ka-ching George’s password will be on the leaked RockYou wordlist. oclHashCat can help us out here, thanks to the ability to use GPU’s. Yes, I’m using a Windows PC for this, sue me.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
That didn’t take too long now did it ? But we have the TrueCrypt container password, which makes mounting it a tiny bit easier now.
1 2 3 4 5 6 7 8 9 10 11 |
|
Hmm, a private key - lets try SSHing in as bazza using this key and see what happens.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Oh… I was expecting a bit more of a fight, but I guess Bazza trusts George, even though he uses defunct software that allows privilege escalation (look it up). Fool.
Bazza’s Blockade
Once again we’re presented with 2 binaries, with SUID attributes set. This time, however, we can read the files, which means we can decompile them. Time to take a look
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
|
OK, so part1 runs part2 (this time with an absolute path), so time for a quick peek into part2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
So, part2 will run only if the effective group identifier is 1003. part1 has a SUID attribute set as group developers, which means you have to run part1 before part2. If you run part2 first, this happens
1
|
|
Running part1 changes our effective group identifier, and part2 changes our effective user identifier, but doesn’t seem to drop us to a shell as that user (oj)
1 2 3 4 5 6 7 8 9 10 11 |
|
A further look into the source code for part2 shows that it is not using an absolute path for the system(“id”) function, therefore we can trick this application into running a bogus id binary in the same way we did with the bogus chmod binary. The source code is pretty much the same, apart from the fact I’m using uid 1005 rather than 1000.
1 2 3 4 5 6 7 8 9 10 |
|
This is compiled, placed in /tmp and made executable. The path environment variable is modified as per last time and we’re good to go.
1 2 3 4 5 6 7 8 9 10 11 |
|
Success !
Nearly there, only this hoop to jump through and we’re done.
Orange Juice Doesn’t Echo
The OJ user has 1 file, a binary called echo which does exactly that, it repeats what you send it. This guy is the height of programming ability. There’s got to be something wrong with it.
A quick look at the binary in IDA, and yes there is something wrong with it, there seems to be something in it that is called a “format string vulnerability”.
wut ?
What felt like 12 days of reading, and video watching (Fuzzy Security videos are the best - check this one out for formatstr vuln explanation and the follow up) I still felt none the wiser. But I figured I’d give it a go anyway. What’s the worst that can happen ? I can’t make it any more wrong now can I ?
Meh, let’s put our shellcode (setuid plus /bin/sh) into memory anyway, just so it looks like we’re progressing.
1
|
|
So, I started to play around with gdb and format strings. There are several ways you can do format string vulnerabilities - you can put your shellcode in memory using an environment variable, then overwrite a global offset table entry to execute your code (as per the videos), or if you’re unlucky like me and have a statically linked binary, you have to find another way such as jumping to a location in the stack. I tried that… it didn’t work because my shellcode kept moving in memory.
Apparently, though, you can overwrite entries in the .dtor part of the binary - don’t ask me what .dtor is, but I had great fun gradually overwriting random memory locations and crashing the application over and over and over again…
Here are some of the format strings I fabricated while on my journey - you can get an idea of my thought pattern and the things I tested. It’s also pretty obvious when I went back to basics about 7 attempts in.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
I spent a lot of time staring at segfault after segfault until I stumbled upon this random combination of characters (I really really want to explain how I worked it out, but I’m not 100% sure myself. I guess that’s a follow up post sometime. Also, it is possible this wont work for you).
1
|
|
Which when executed like this
1
|
|
dropped me to a shell.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Like a baws. Now I’m going to exorcise the VM and purge every last shred of it from my SSD. BEGONE FOUL DEMON !