Testing for SSI Injection (OWASP-DV-009)
Web servers usually give to the developer the possibility to add small pieces of dynamic code inside static html pages, without having to play with full-fledged server-side or client-side languages. This feature is incarnated by the Server-Side Includes (SSI), a very simple extensions that can enable an attacker to inject code into html pages, or even perform remote code execution.
Description of the Issue
Server-Side Includes are directives that the web server parses before serving the page to the user. They represent an alternative to writing CGI program or embedding code using server-side scripting languages, when there's only need to perform very simple tasks. Common SSI implementations provide commands to include external files, to set and print web server CGI environment variables and to execute external CGI scripts or system commands.
Putting an SSI directive into a static html document is as easy as writing a piece of code like the following:
<!--#echo var="DATE_LOCAL" -->
to print out the currint time.
<!--#include virtual="/cgi-bin/counter.pl" --> <pre> to include the output of a CGI script.<br> <pre> <!--#include virtual="/footer.html" -->
to include the content of a file.
<!--#exec cmd="ls" -->
to include the output of a system command.
Then, if the web server's SSI support is enabled, the server will parse these directives, both in the body or inside the headers. In the default configuration, usually, most web servers don't allow the use of the exec directive to execute system commands.
As in every bad input validation situation, problems arise when the user of a web application is allowed to provide data that's going to make the application or the web server itself behave in an unforseen manner. Talking about SSI injection, the attacker could be able to provide an input that, if inserted by the application (or maybe directly by te server) into a dynamically generated page would be parsed as SSI directives.
We are talking about an issue very similar to a classical scripting language injection problem; maybe less dangerous, as the SSI directive are not comparable to a real scripting language and because the web server needs to be configured to allow SSI; but also simpler to exploit, as SSI directives easy to understand and powerful enough to output the content of files and to execute system commands.
Black Box testing
The first thing to do when testing in a Black Box fashion is finding if the web server actually support SSI directives. The answer is almost certainly a yes, as SSI support is quite common. To find out we just need to discover which kind of web server is running on our target, using classical information gathering techniques.
Whether we succeded or not in discovering this piece of information, we could guess if SSI are supported just looking at the content of the target web site we are testing: if it makes use of .shtml file then SSI are probably supported, as this extension is used to identify pages containing these directives. Unfortunately, the use of the shtml extension is not mandatory, so not having found any shtml files doesn't necessarily mean that the target is not prone to SSI injection attacks.
Let's go to the next step, which is needed not only to find out if an SSI injection attack is really plausible, but also to identify the input points we can use to inject our malicious code.
In this step the testing activity is exactly the same needed to test for other code injection vulnerabilities. We need to find every page where the user is allowed to submit some kind of input and verify whether the application is correctly validating the submitted input or, otherwise, if we could provide data that is going to be displayed unmodified (as error message, forum post, etc.). Beside common user supplied data, input vectors that are always to be considered are HTTP request headers and cookies content, that can be easily forged.
Once we have a list of potential injection points, we can check if the input is correctly validated and then find out where in the web site the data we provided are going to be displayed. We need to make sure that we are going to be able to make characters like that used in SSI directives:
< ! # = / . " - > and [a-zA-Z0-9]
go through the application and be parsed by the server at some point.
Exploiting the lack of validation, is as easy as submitting, for example, a string like:
<!--#include virtual="/etc/passwd" -->
in a input form, instead of the classical:
The directive would be then parsed by the server next time it needs to serve the given page, thus including the content of the Unix standard password file.
The injection can be performed also in HTTP headers, if the web application is going to use that data to build a dynamically generated page:
GET / HTTP/1.0 Referer: <!--#exec cmd="/bin/ps ax"--> User-Agent: <!--#virtual include="/proc/version"-->
Gray Box testing and example
Being able to review the application source code we can quite easily find out:
- if SSI directives are used; if they are, then the web server is going to have SSI support enabled, making SSI injection at least a potential issue to investigate;
- where user input, cookie content and http headers are handled; the complete input vectors list is then quickly built;
- how the input is handled, what kind of filtering is performed, what characters the application is not letting through and how many type of encoding are taken into account.
Performing these steps is mostly a matter of using grep, to find the right keywords inside the source code (SSI directives, CGI environment variables, variables assignment involving user input, filtering functions and so on).
- IIS: Notes on Server-Side Includes (SSI) syntax
- Apache Tutorial: Introduction to Server Side Includes
- Apache: Module mod_include
- Apache: Security Tips for Server Configuration
- Header Based Exploitation
- Web Proxy (Burp Suite, Paros, WebScarab, Suru Web Proxy)
- Enconding/Decoding tools
- String searcher (grep, your favorite text editor)
OWASP Testing Guide v2