Mentor — Attack Chain
Current Path (complete — rooted)
nmap 22,80
└─ 80 = Apache proxy → FastAPI (Werkzeug/2.0.3, Python 3.6.9 banner)
└─ vhost fuzz → api.mentorquotes.htb (add to /etc/hosts)
└─ /docs Swagger → register user, login → JWT
└─ /admin/backup exists but needs admin
UDP/161 SNMP
└─ snmpbrute → community "internal" (default "public" failed)
└─ snmpwalk -v2c -c internal → process table (hrSWRunParameters)
└─ "/usr/local/bin/login.py kj23sadkj123as0-d213" ← admin API password
└─ login to API as admin → admin JWT
└─ POST /admin/backup {"path":";<revshell>;"} ← COMMAND INJECTION
└─ reverse shell = ROOT in Docker container (/app)
└─ /app/app/db.py → postgres:[email protected]/mentorquotes_db
└─ select * from users → MD5 hashes
└─ crack svc: 53f2...fd8 → 123meunomeeivani
└─ SSH svc@mentor (host)
└─ read /etc/snmp/snmpd.conf
└─ createUser bootstrap ... SuperSecurePassword123__
└─ = james's Linux password (reuse)
└─ su/ssh james
└─ sudo -l → (ALL) /bin/sh
└─ sudo /bin/sh → ROOT
Branch Points / Decisions
- Query DB from inside container vs. chisel tunnel to Kali. Chose in-container query — the app already reaches the DB and the libs are installed; no binary upload, no tunnel, no port-forward. Tunnel was a detour (and the "chisel!" download was the installer script, not the binary — see lessons).
- Which SNMP leak matters. The proc-table
login.py <arg> leaked the API admin password, not a Linux password. Easy to waste time SSH-spraying it. It only works against the web app.
- Two different "SuperSecure"-style secrets.
kj23sadkj123as0-d213 (API) and SuperSecurePassword123__ (SNMPv3 = james system). Don't conflate them.
Lessons Learned
- FastAPI single-worker deadlock. A synchronous, blocking reverse-shell payload injected into a request handler pins the only uvicorn worker → the entire API hangs for every later request. Killing the local
nc orphans the child, so the worker never frees and the API stays dead until box reset. Symptom: Burp AND listener both hang; main site fine but api. vhost times out on every path. Fix: reset, then use a detached payload (setsid ... &) so the handler returns immediately.
not found vs Permission denied on a file that exists. Permission denied = exec bit missing. not found on an existing file = missing interpreter/loader (bad shebang or dynamic linker). The chisel! from i.jpillora.com is a bash installer script (#!/bin/bash, 7 KB) meant for curl | bash — Alpine has no bash → not found. The real static chisel binary (~10 MB) was already on Kali at /usr/bin/chisel.
- Check tun0 every session. Payloads were pointed at a stale
10.10.14.6; live tun0 was 10.10.14.175. Wrong callback = listener never fires even when RCE works.
- SNMP leaks secrets in two places on this box: process arguments (a password passed to a script on the CLI) and
snmpd.conf itself (createUser stores the SNMPv3 auth passphrase in cleartext).