July 30, 2026
Cyborg: From a Careless Shoutbox to Root via a Backup Script’s Blind Spot
Introduction

By Enryuuu
8 min read
Introduction
Cyborg is TryHackMe's easy-rated boot-to-root box, built around a small home-studio website. What actually breaks the box open is a string of small operational mistakes: a public chat log that says more than it should, a config directory that never should have been reachable by a browser, a password reused in two unrelated places, and a "helper" script that will run whatever you hand it, as long as you ask with sudo.
None of the individual steps here are hard on their own. What made Cyborg worth writing up is how each step only works because of the one before it. Crack a hash here, and it unlocks a backup there; read a chat log here, and it tells you exactly where to look next. That chaining felt closer to how a real intrusion plays out than a lot of "find one exploit and get a shell" rooms do.
Phase 1: Enumeration
Started the usual way: a full TCP port sweep instead of trusting a top-1000 scan to catch everything.
nmap -p- -sV -sC
Two ports came back open:
The web server was serving nothing but the stock Apache2 Ubuntu default page "It works," and not much else. Nothing to fingerprint, nothing to click. Time to go looking for whatever wasn't linked from the front page.
Phase 2: Directory Discovery
Ran dirsearch against the web root, cycling through the usual set of extensions:
Two hits stood out. /admin redirected into a small site with its own index.html and admin.html pages. And, oddly, /etc came back with a 200 and a suspiciously small response size. A folder literally called /etc , sitting at the web root and actually browsable, was not something I expected to find intact.
Phase 3: A Portfolio Page, and a Shoutbox That Says Too Much
/admin turned out to be a personal site for someone named Alex, a music producer, going by the "about me" copy, with a home studio and a page of childhood photos. Harmless on its own.
admin.html was more interesting: an "Admin Shoutbox," a running log of casual messages between three people Josh, Adam, and Alex. Most of it was small talk about a football match. The last message, posted from Alex, was not:
"…uhh i was playing around with the squid proxy i mentioned earlier… all the config files are laying about… other than that im pretty sure my backup 'music_archive' is safe just to confirm."
That message did a fair bit of damage on its own. It confirmed a Squid proxy was running, admitted the config files were sitting around unremoved, and almost as an afterthought named the backup I hadn't gone looking for yet: music_archive . None of this sat behind any access control. It was just there, in a public shoutbox.
Security Issue #1: Operational Details Leaked in a Public Chat Log. A shoutbox meant for casual back-and-forth between staff named a misconfigured service, gave away where its leftover files were, and pointed straight at a backup archive by name. Anyone who found the page got a head start on the rest of the box.
Phase 4: Walking Into /etc
The earlier dirsearch hit was exactly what it looked like: a directory literally named etc , sitting at the web root with Apache's directory listing switched on. Inside it was a single folder, squid/ , and inside that, two files (passwd and squid.conf) both open for anyone to read.
squid.conf explained what passwd was for:
Squid was running basic auth, checked against that exact file. And the file held one line:
An APR1 (Apache MD5) hash, for a username that lined up almost exactly with the backup name from the shoutbox.
Security Issue #2: Configuration and Credential Files Served Directly Over HTTP. A directory that should never have been reachable from a browser was public, with listing turned on. Anyone who found it could read both the proxy's configuration and its password file directly.
Phase 5: Cracking the Hash
John, pointed at its default wordlist and told the format was md5crypt, finished instantly with nothing to show for it.
APR1 needed to be treated as its own mode rather than lumped in with generic md5crypt. Hashcat's mode 1600 is built for exactly that:
Two seconds later:
Security Issue #3: A Password Weak Enough to Fall in Seconds. Once the correct hash mode was used, the password turned out to be common enough to sit well inside the first few million lines of rockyou.txt.
Phase 6: Downloading the Backup
Back on the /admin site, an easy-to-miss download link produced archive.tar. Extracting it unpacked into a nested path, home/field/dev/final_archive , alongside a three-line README:
That put a name to the mystery files: this wasn't a plain tarball, it was a BorgBackup repository, which meant it needed Borg itself and a passphrase to actually open.
Security Issue #4: A Full Backup Repository Offered as a Public Download. This wasn't one leaked file; it was an entire encrypted backup, sitting behind a download link with nothing in front of it to check who was asking.
Phase 7: Opening the Archive
Installed borgbackup and pointed it at the extracted repository:
Prompted for a passphrase, I tried the password just cracked from the Squid auth file (squidward) and it worked. Extraction dropped a new home/ directory containing two folders: field , the repository's owner, and alex.
Security Issue #5: The Same Password Protecting Two Unrelated Systems. "squidward" wasn't just the Squid proxy's password. It was also the Borg archive's passphrase. Cracking one hash effectively cracked two separate layers of the box in a single move.
Phase 8: Login as Alex
Inside home/alex/Documents/ sat note.txt , a short, almost apologetic message:
SSH with that pair dropped me straight into alex's shell.
Flag 1
User.txt was sitting in the home directory, readable immediately.
Security Issue #6: Plaintext Credentials Stored in a Personal Note. Writing a password down so you don't forget it defeats the point of having one, and this particular note ended up inside a backup archive that left the server entirely.
Phase 9: A Script That Runs Whatever You Tell It
sudo -l as alex showed exactly one entry, but a generous one:
Reading through backup.sh , the part that mattered was the argument parsing at the top and the final two lines at the bottom:
The script takes a -c flag, stores whatever follows it in $command , does its actual job of archiving some mp3 files, and then runs $command and echoes whatever it produced. No allowlist, no validation, nothing stopping -c from being an entire shell.
Security Issue #7: Arbitrary Command Execution Through an Unvalidated sudo Script. A maintenance script that accepts a free-form "command" argument and executes it, paired with blanket NOPASSWD sudo rights, turns a scheduled backup job into a root shell for anyone who can read the script
A quick proof-of-concept confirmed it:
Phase 10: Root Shell
I change the command to /bin/bash:
Phase 11: The Shell That Wouldn't Talk Back
This is the part of the room I actually enjoyed working out. The command above did spawn a root bash (the prompt even changed to root@ubuntu) but every command I typed into it seemed to vanish. whoami , ls , cat root.txt : nothing came back.
The script's last two lines explain exactly why:
cmd=$($command)
echo $cmd
$(…) is command substitution: it runs $command and captures its standard output into a variable instead of letting that output reach the terminal. With $command set to /bin/bash , everything the resulting shell printed to stdout was getting swallowed into $cmd instead of showing up on screen. What I could see live was only what never went through that capture the shell's own prompt, and anything sent to stderr, which is exactly why a failed cd root showed up instantly while a working ls showed nothing at all.
Flag 2
None of that output was actually lost, though. It was just waiting. The moment I typed exit , the inner bash process ended, the command substitution finished collecting whatever it had captured, and the script's own echo $cmd printed all of it at once. Every command I'd run in that "silent" shell, cat root.txt included, arriving in a single line the instant the subshell closed.
Blue Team Perspective
Working back through the chain, here's where I think a defensive team would have had a real chance to catch this, and what I'd fix.
1. Public-Facing Chat Logs and Directory Listings Leaking Internal Details.
A shoutbox never meant for outsiders named a misconfigured proxy and a backup archive by name, and a literal /etc folder sat browsable at the web root with listing enabled. Either one alone hands an attacker a head start. Fix: never expose staff communication tools on a public web root, and explicitly disable directory listing ( Options -Indexes in Apache) on every directory that doesn't need it, especially anything named after a system path.
2. Weak Credential Hygiene: Reuse and Plaintext Storage.
The same password unlocked both a Squid proxy account and a completely unrelated Borg backup archive, and a separate password existed only as plaintext in a personal note, one that ended up shipping inside a backup that left the server entirely. Fix: treat every service's credentials as independent and manage them with a password vault instead of memory or text files; rotate anything shared the moment it's discovered, and treat any password that has ever touched a plaintext file as compromised.
3. Full Backup Archives Reachable With No Authentication.
An entire encrypted repository was offered as a plain download link, so the only thing standing between an attacker and the data inside was the strength of a single password. Fix: never publish backup archives through a web-accessible path; store them somewhere that requires its own authentication layer, separate from whatever password protects the archive's contents.
4. An Overprivileged sudo Script With No Input Validation.
backup.sh accepted an arbitrary command through a -c flag and executed it, and NOPASSWD sudo rights meant nothing else stood in the way. Fix: never let a privileged script accept free-form input as a command; if a script genuinely needs configurable behavior, restrict it to a fixed, validated set of options, and audit sudoers entries for any script that takes arguments at all.
This write-up is part of my ongoing series documenting CTF challenges as I build my portfolio in cybersecurity. I approach each challenge from both offensive and defensive perspectives, because understanding both sides is what makes a well-rounded security professional.
If you're also on the journey toward a SOC or Security Engineering role, feel free to connect — I'm always happy to discuss techniques and share resources.