Server-side template injection

In this section, we introduce what server-side template injection is, outline the basic methods to exploit this vulnerability, and provide some suggestions for avoiding it.

What is server side template injection

Server template injection means that an attacker can use the template syntax to inject malicious load into the template and then execute the load on the server.

Template engines are designed to generate web pages by combining fixed templates with variable data. Server-side template injection attacks can occur when user input is concatenated directly into a template, rather than passed in as data. This allows an attacker to inject arbitrary template instructions to manipulate the template engine and thus gain full control of the server. As the name implies, server-side template injection payloads are delivered and executed on the server side, which can make them more dangerous than typical client-side template injections.

What is the impact of server side template injection

Server-side template injection vulnerabilities can expose websites to a variety of attacks, depending on the template engine in question and how the application uses it. In rare cases, these vulnerabilities pose no real security risk. In most cases, however, the effects of server-side template injection can be disastrous.

In the most serious case, an attacker could complete remote code execution to take full control of the back-end server and use it for other attacks on the internal infrastructure.

Even in cases where it is not possible to fully execute remote code, an attacker can often use server-side template injection as the basis for many other attacks, potentially gaining access to sensitive data and arbitrary files on the server.

How do server-side template injection vulnerabilities arise

Server-side template injection vulnerabilities occur when user input is concatenated directly into a template rather than passed in as data.

Static templates that simply provide placeholders and render dynamic content in them are generally not vulnerable to server-side template injection. Typical examples are extracting the username to start an email, such as the following extracted from a Twig template:

$output = $twig->render("Dear {first_name},", array("first_name" => $user.first_name) );
Copy the code

This is not vulnerable to server-side template injection because the user’s name is simply passed into the template as data.

However, it is sometimes possible for a Web developer to wire user input directly into a template, for example:

$output = $twig->render("Dear " . $_GET['name']);
Copy the code

Instead of passing static values into the template, you use GET Name to dynamically generate a portion of the template itself. Since template syntax is executed on the server side, this may allow an attacker to use the name argument as follows:

http://vulnerable-website.com/?name={{bad-stuff-here}}
Copy the code

Vulnerabilities like these are sometimes the result of flawed templates designed by people unfamiliar with security concepts. As in the example above, you might see different components, some of which contain user input, wired and embedded into the template. In some ways, this is similar to the SQL injection vulnerability, where statements are written improperly.

Sometimes, however, this behavior is actually intentional. For example, some sites deliberately allow privileged users, such as content editors, to edit or submit custom templates by design. If an attacker is able to exploit a privileged account, this obviously poses a significant security risk.

Construct a server side template injection attack

Identifying server-side template injection vulnerabilities and planning successful attacks typically involve the following abstract processes.

detection

Server-side template injection vulnerabilities often go unnoticed, not because they are complex, but because they are only really obvious to the auditors who are explicitly looking for them. If you can detect a bug, it’s easy to exploit it. This is especially true in non-sandbox environments.

As with any vulnerability, the first step to exploiting it is to find it. Perhaps the easiest way to start is to try to obfuze templates by injecting a series of special characters commonly found in template expressions, such as ${{<%[%'”}}%\. If an exception is thrown, it indicates that the server may have interpreted the injected template syntax in some way, indicating a potential vulnerability in server template injection.

Server-side template injection vulnerabilities occur in two different contexts, each requiring its own detection method. Regardless of the outcome of the obfuscation attempt, try the following context-specific methods. If obfuscation is uncertain, vulnerabilities may be exposed using one of these methods. Even if obfuscation does indicate a template injection vulnerability, you still need to determine its context to take advantage of it.

Plaintext context

Plain text context.

Most templating languages allow you to freely enter content by directly using HTML tags or template syntax, which the back end renders to HTML before sending an HTTP response. For example, in a Freemarker template, render(‘Hello ‘+ Username) might render as Hello Carlos.

This is sometimes often mistaken for a simple XSS vulnerability and used in XSS attacks. However, by setting the math to the value of the parameter, we can test whether it is also a potential attack point for server-side template injection attacks.

For example, consider including the following template code:

render('Hello ' + username)
Copy the code

During the review process, we can test server-side template injection by requesting the following URL:

http://vulnerable-website.com/?username=${7*7}
Copy the code

If the result output contains Hello 49, it indicates that the math has been performed by the server. This is a good example of the server-side template injection vulnerability.

Note that the specific syntax required to successfully evaluate mathematical operations will vary depending on the template engine used. We’ll explain in detail in the Identify step.

Code context

Code context.

In other cases, the vulnerability is exposed by putting user input into a template expression, as seen in the E-mail example above. This can take the form of placing user-controlled variable names in parameters, for example:

greeting = getQueryParameter('greeting')
engine.render("Hello {{"+greeting+"}}", data)
Copy the code

The URL generated on the site looks something like:

http://vulnerable-website.com/?greeting=data.username
Copy the code

The rendered output might be Hello Carlos.

It’s easy to ignore this context during the evaluation process, because it doesn’t yield obvious XSS and is almost indistinguishable from a simple HashMap lookup. In this case, one way to test server-side template injection is to first determine that the parameter does not contain a direct XSS vulnerability by injecting arbitrary HTML into the value:

http://vulnerable-website.com/?greeting=data.username<tag>
Copy the code

In the absence of XSS, this usually results in blank space (just Hello, no username), encoding tags, or error messages in the output. The next step is to try to exit the statement using generic template syntax and try to inject arbitrary HTML after it:

http://vulnerable-website.com/?greeting=data.username}}<tag>
Copy the code

If this again results in an error or blank output, you are using the wrong template syntax. Or, if none of the template style syntax is valid, server side template injection cannot take place. If the output is rendered correctly with any HTML, this is a key proof that a server-side template injection vulnerability exists:

Hello Carlos<tag>
Copy the code

identify

Once potential template injection is detected, the next step is to identify the template engine.

Although there are a large number of template languages, many use very similar syntax, which was chosen specifically to avoid collisions with HTML characters. Therefore, it may be relatively simple to construct exploratory payloads to test which template engine is being used.

Simply submitting invalid syntax is sufficient, because the generated error message will tell you which template engine you used, and sometimes even which version. For example, the illegal expression <%=foobar%> triggers the following response from the Ruby-based ERB engine:

(erb):1:in `<main>': Undefined the local variable or method ` foobar 'for the main, the Object (NameError) from/usr/lib/ruby / 2.5.0 erb. Rb: 876: in ` eval' The from/usr/lib/ruby / 2.5.0 erb. Rb: 876: in ` result 'for the from e: 4: in ` < main >'Copy the code

Otherwise, you’ll need to manually test different language-specific payloads and study how the template engine interprets them. Using a process of exclusion based on whether grammar is valid or invalid, you can narrow down options faster than you think. A common approach is to inject arbitrary math using syntax from different template engines. Then, observe whether they are successfully executed. To do this, you can use a decision tree similar to the following:

You should note that the same payload can sometimes get successful responses from multiple template languages. For example, payload {{7*’7′}} returns 49 in Twig and 7777777 in Jinja2. So don’t jump to conclusions just because you’ve responded successfully.

using

Once a potential vulnerability has been detected and the template engine has been successfully identified, you can start trying to find a way to exploit it. Please refer to the following for details.

How to prevent server template injection vulnerability

The best way to prevent server-side template injection is to not allow any users to modify or submit new templates. However, this is sometimes unavoidable due to business requirements.

One of the easiest ways to avoid introducing server-side template injection vulnerabilities is to always use a “no-logic” template engine like Mustache unless absolutely necessary. Separating logic from presentation as much as possible can greatly reduce the risk of dangerous template-based attacks.

Another option is to execute the user’s code only in a sandbox environment that has completely removed potentially dangerous modules and features. Unfortunately, sandboxing untrusted code is inherently difficult and easily bypassed.

Finally, another way to complement situations where arbitrary code execution is unavoidable is to apply your own sandbox by deploying a template environment in a locked container such as a Docker.


Exploit server-side template injection vulnerabilities

In this section, we’ll take a closer look at some typical server-side template injection vulnerabilities and demonstrate how to exploit the previously summarized approach. By putting this into practice, you can potentially discover and exploit a variety of server-side template injection vulnerabilities.

Once a server-side template injection vulnerability is discovered and the template engine in use is identified, successful exploitation of the vulnerability typically involves the following process.

  • reading
    • Template syntax
    • Security documents
    • Known exploits
  • To explore the environment
  • Construct custom attacks

reading

Unless you already know the template engine inside out, you should read its documentation first. While this can be a bit boring, don’t underestimate that documentation can be a useful source of information.

Learn basic template syntax

Learning basic syntax, key functions, and variable handling is obviously important. Even simply learning how to embed a block of native code in a template can sometimes quickly lead to vulnerability exploitation. For example, once you know you are using the Python-based Mako template engine, implementing remote code execution can be as simple as:

<%
import os
x=os.popen('id').read()
%>
${x}
Copy the code

In a non-sandbox environment, implementing remote code execution and using it to read, edit, or delete arbitrary files is simple in many common template engines.

Read the Safety section

In addition to providing the basics of how to create and use templates, the document may also provide some kind of “security” section. The name of this section varies, but it generally Outlines all the potentially dangerous things one should avoid doing with templates. This can be an invaluable resource and even serve as a kind of cheat sheet, providing guidance on what behaviors you should look for and how to use them.

Even without a dedicated “security” section, there is almost always some kind of warning in the documentation if a particular built-in object or function poses a security risk. This warning may not provide much detail, but it should at least be flagged as something to dig deeper into.

For example, in an ERB template, the document display can list all directories and then read any file as follows:

<%= Dir.entries('/') %>
<%= File.open('/example/arbitrary-file').read %>
Copy the code

Look for known exploits

Another key aspect of exploiting server-side template injection vulnerabilities is being good at finding other online resources. Once you can identify the template engine you are using, you should browse the Web to find any vulnerabilities that others may have found. Due to the widespread use of major template engines, it is sometimes possible to find well-documented exploits that you can adapt to take advantage of your target site.

explore

At this point, you may have stumbled upon a viable exploit while working with the documentation. If not, the next step is to explore the environment and try to discover all the objects you can access.

Many template engines expose some type of self or Environment object that acts like a namespace containing all the objects, methods, and properties supported by the template engine. If such an object exists, it can potentially be used to generate a list of objects in scope. For example, in a Java-based templating language, it is sometimes possible to list all variables in the environment using the following injection:

${T(java.lang.System).getenv()}
Copy the code

This can serve as a basis for creating a short list of potentially interesting objects and methods for further research.

Objects provided by the developer

Note that the web site will contain built-in objects provided by templates and custom, site-specific objects provided by Web developers. You should pay special attention to these non-standard objects because they are particularly likely to contain sensitive information or exploitable methods. Since these objects may vary between different templates on the same site, be aware that you may need to study the behavior of the object in the context of each different template before finding a way to leverage it.

Although server-side template injection can lead to remote code execution and complete server takeover, this is not always possible in practice. However, the mere exclusion of remote code execution does not necessarily mean that there are no other types of attacks. You can still exploit server-side template injection vulnerabilities for other high-hazard attacks, such as directory traversal, to access sensitive data.

Construct custom attacks

So far, we have focused on building attacks by reusing documented vulnerability attacks or using known vulnerabilities in a template engine. However, sometimes you need to build a custom exploit. For example, you might find that the template engine executes templates in a sandbox, making attacks difficult, if not impossible.

After identifying the attack point, if there is no obvious way to exploit the vulnerability, you should continue to use traditional auditing techniques to examine the exploitable behavior of each function. By methodically going through this process, you can sometimes build a complex attack that can even be exploited for more secure targets.

Construct custom attacks using chains of objects

As mentioned above, the first step is to identify the objects and methods you have access to. Some objects might pop up right away. By combining your own knowledge with the information provided in the documentation, you should be able to put together a short list of objects that you want to explore more thoroughly.

When exploring the documentation of objects, pay special attention to what methods those objects allow access to and what objects they return. By digging into the document, you can find combinations of objects and methods that can be linked together. Linking the right objects and methods together sometimes allows you to access dangerous features and sensitive data that at first seem out of reach.

For example, in Velocity, the Java-based templating engine, you can call $class to access the ClassTool object. The research documentation shows that you can refer to any object chained using the $class.inspect() method and the $class.type attribute. In the past, this was used to execute shell commands on the target system, as follows:

$class.inspect("java.lang.Runtime").type.getRuntime().exec("bad-stuff-here")
Copy the code

Construct custom attacks using developer-supplied objects

Some template engines run in secure, locked environments by default to minimize risk. Although this makes remote code execution with these templates difficult, objects created by developers exposed to templates can provide further points of attack.

However, while there is usually a lot of documentation for template-built objects, there is almost no documentation at all for site-specific objects. So, to figure out how to exploit these vulnerabilities, you need to manually investigate your site’s behavior to determine the point of attack and build your own custom attacks accordingly.