In dieser Serie von Blog-Posts, Check Point Verwundbarkeit Forscher Netanel Rubin eine Geschichte in drei Akten erzählt - seinen langen Weg entdeckte Mängel und Schwachstellen im Kern Wordpress zu beschreiben, was ihn von einem Read-Only "Teilnehmer" Benutzer, durch das Erstellen, Bearbeiten und das Löschen von Beiträgen, und den ganzen Weg SQL-Injection und persistent XSS-Angriffe auf 20% der beliebten Web durchführen.
Zusammenfassung
Eine Reihe von kritischen Schwachstellen existieren in Standard-Wordpress-Installationen, mögliche Kompromiss von Millionen von Live-Web-Sites zu ermöglichen.
MITRE hat für diese Schwachstellen CVE-2015-5623, CVE-2015-2213, CVE-2015-5714, CVE-2015-5715, CVE-2015-5716 als Bezeichner zugewiesen. * CVE-2015-2212 wurde als Duplikat von CVE-2015-5623 markiert.
Die erste Schwachstelle in dieser Reihenfolge (CVE-2015-5623) wurde kürzlich in einem Wordpress-Sicherheitsupdate (4.2.3) gepatcht.
Site-Administratoren sind aufgefordert, Sicherheitsupdates anwenden, wie sie (bei Auto-Update deaktiviert wurde) freigegeben werden.
Für weitere Updates in unserem Blog sowie kommende Wordpress Security Advisories bitte folgen.
Check Point-Kunden sind geschützt gegen die Verwundbarkeit Sequenz über IPS-Signaturen. Prolog
Wordpress ist ein PHP-basiertes CMS (Content Management System), in der Tat der prominenteste Web-Plattform auf dem Internet heute. Es wird geschätzt, weltweit mehr als 20% der Top 1 Million Websites laufen.
Wordpress-Instanzen werden von Cyber-Kriminellen und Hackern häufig gezielt, da sie auf private Datenbanken und interne Netzwerkzugriff führen kann. Ein typischer Wordpress-Kompromiss ist in einem veralteten Plug-in-Komponente auf Exploits von Sicherheitslücken beruhen.
Sein solch eine beliebte Plattform, Wordpress ist auch einer der am meisten geprüft Teile der Software der Welt in Bezug auf die Sicherheitsbewertungen und Vulnerabilitätsforschung, mit Tausenden von Augen neue Features und Bugfixes Überprüfung sowie 3rd-Party-Plug-Ins.
Gelegentlich Forscher entdecken Schwachstellen in bestimmten Plug-Ins, die von Dritten geschrieben und getrennt von Site-Administratoren installiert. Solche Schwachstellen lassen auf wöchentlicher Basis in verschiedenen Kanälen, einschließlich der "Full Disclosure" Mailingliste veröffentlicht.
Im Gegensatz zu diesen häufigen Befunde in 3rd-Party-Plug-Ins 'Code, sind Barebone Wordpress Probleme selten, wie Wordpress Kern-Entwickler gut ausgebildete sind für alle freigegebenen Code hohe Sicherheitsbewusstsein zu halten. Das können wir während unserer Prüfung des Quellcodes bestätigen wir die Entwickler erlebt "nichts dem Zufall überlassen", und die Umsetzung mehrere Sicherheitsebenen meisten Angriffsvektoren schützen wir uns vorstellen konnten.
Wordpress-Entwickler verdienen Lob für ihre Bemühungen solch komplexer Software in diesem Sicherheitsniveau aufrecht zu erhalten, insbesondere die Anwesenheit des notorisch schießfreudigen Fuß-gun genannt PHP betrachten. Check Point Verwundbarkeit Forscher High-Profile-Plattformen oft Ziel, bemüht, die Sicherheit der gemeinsamen Software zu verbessern. Die Ergebnisse werden an Softwareanbietern vor der Veröffentlichung berichtet, um ein Update so schnell wie möglich zur Verfügung zu stellen, überall auf die Sicherheit der Anwender beitragen. Check Point-Kunden auch präventive Schutz über unsere Produktlinien erhalten (gelegentlich vor ein Anbieter Fix freigegeben wird). Es ist daher keine Überraschung, dass wir Wordpress zu prüfen entschieden, was zu unserer Entdeckung dieser kritischen Fragen.
Wir beabsichtigen, die technische Beschreibung der Sicherheitslücken erst frei, nachdem Wordpress-Fixes für jede Ausgabe freigegeben haben. Die Wordpress-Team hat reagiert, und aufmerksam gewesen; sie arbeiten an alle gemeldeten Probleme zuverlässig fixiert auf die Bereitstellung. Da CVE-2015-5623 in 4.2.3 gepatcht wurde, können präsentieren wir unseren ersten Teil der Trilogie Verwundbarkeit Jagd.
Teil 1 - "Identität"
Wordpress nutzt eine reiche, erweiterbar, wobei jeder Benutzer eine Rolle zugewiesen ist, von der niedrigsten privilegierten Teilnehmer zu dem allmächtigen Super-Administrator.
Unsere Angriffsfläche beginnt mit dem Verständnis, dass auch Teilnehmer, die Wordpress-Administrator-Steuerungsfeld zugreifen kann, befindet sich in der '/ admin' Verzeichnis. Sie haben extrem begrenzte Möglichkeiten im Vergleich zur Kontrolle mit Administratoren zum Beispiel, wie durch ihre jeweiligen Vorrechte bestimmt.
Standardmäßig werden nur Abonnenten die begrenzte 'read_page' und 'read_post Privilegien zugewiesen, so dass sie Seiten und Beiträge zu lesen. Administratoren, auf der anderen Seite, haben jedes Privileg zur Verfügung und bearbeiten / Beiträge erstellen, Dateien hochladen und verwalten Konfiguration.
Wordpress prüft die Berechtigungen des angemeldeten Benutzers, wenn sie versuchen, eine Aktion auszuführen, mit dem 'current_user_can ()' Funktion.
'Current_user_can ()' erhält die Fähigkeit angefordert und ordnet sie dem tatsächlichen Privileg muss der Benutzer, um die Aktion aufzurufen. Es führt, dass durch die "map_meta_cap () 'Funktion mit der Fähigkeit, als Argument aufrufen, die ein Array mit den tatsächlichen Privilegien gibt für diese Fähigkeit benötigt.
Dann 'current_user_can ()' Schleife durch das Array und prüft, ob der Benutzer über diese Rechte verfügt.
Als Angreifer, lassen Sie uns mit der Annahme beginnen wir einen Abonnenten Benutzer haben. Es ist üblich, für Wordpress-Websites kostenlos Benutzer-Registrierung zu ermöglichen ( "jeder kann registrieren '), die neue Benutzerrolle für Abonnenten säumigen. Als Teilnehmer können wir nur Seiten und Beiträge zu lesen, sondern als Angreifer, wir wollen etwas ein wenig interessanter als das zu tun.
Lassen Sie uns einen Auszug aus dem "map_meta_cap () 'beobachten Code zu untersuchen, wie Fähigkeiten in tatsächliche Privilegien abgebildet werden.
Als wir den Beitrag von Prüfung sehen können, bestätigt die "edit_post / edit_page 'Fähigkeit zu überprüfen, ob die Post-ID eingegeben haben wir existieren (hervorgehoben). Der interessante Teil ist, was passiert, wenn es nicht - die Prüfung eingestellt keine Funktionen in $ Kappen und das Array leer zurückgegeben. Da es keine Fähigkeiten gesetzt sind, wirkt sich die Funktion, als ob wir brauchen keine und gibt true zurück.
Das bedeutet, dass in der Theorie können wir Fähigkeitsuntersuchungen mit einem ungültigen Post-ID umgehen. Auszunutzen, die, würden wir Code benötigen, die diese Prüfung ruft und nicht überprüft die Post-ID vor dem Aufruf. Leider gibt es nicht viele Fälle, in denen dies der Fall ist. Ein wichtiger Standort, aber ist die Funktion "edit_post () '.
Diese Funktion ist für einen Beitrag zu aktualisieren. Es analysiert den Eingang für das Update, fügt die gewünschten Metadaten, fügt das Format, und in der Regel macht die ganze schwere Arbeit, bevor sie tatsächlich die Post-Eintrag in der DB zu aktualisieren. Sobald die Funktion die Eingabe beendet das Parsen, ruft er "wp_update_post ()", die für die Aktualisierung der angeforderten Posten in der DB unter anderem kleinere Dinge wie Einstellung Standardwerte für die Eigenschaften verantwortlich ist.
Obwohl 'edit_post ()' überprüft nicht unsere Post-ID "wp_update_post () 'tut. Das bedeutet, dass selbst wenn wir das Privileg überprüfen das erste Mal umgangen wird, wird das zweite Mal scheitern, weil unsere ID nicht in der DB vorhanden sind. Obwohl wir nicht unbedingt der Beiträge im DB bearbeiten können, können wir immer noch über fast den gesamten Code in 'edit_post' get verarbeitet.
Schauen wir uns die interessanten Bits aus diesem Code einen Blick:
Wie man sieht, abgesehen von der Post-Typ zu erkennen, dass durch den austretenden Pfosten gesetzt ist, können wir einen beliebigen Wert innerhalb '$ post_data' steuern. Das bedeutet, dass (wenn auch nicht sichtbar in der eingefügten Code) wir können versuchen, Beiträge Metadaten oder ändern Taxonomien zu aktualisieren, die unsere Angriffsfläche deutlich erweitern würde.
Damit, dass wir zum ersten Mal passieren müssen diese Funktion zu erreichen. Es gibt mehrere Orte, die es nennen, aber diese Orte entweder andere Fähigkeiten überprüfen oder überprüfen, ob die Post wir versuchen, existiert zu bearbeiten. Das lässt uns nur eine Option zu verwenden - die "post.php 'admin-Seite, die den folgenden Code verwendet:
Zunächst scheint dieser Code perfekt für uns - keine Fähigkeiten zu überprüfen, keine Validierung Post-ID, genau das, was wir brauchen. Jedoch Flächen ein anderes Problem mit dem "check_admin_referer () 'Funktionsaufruf. Diese Funktion prüft für einen bestimmten CSRF-Token, das uns durch das System gegeben wurde. Dieses Token verwendet die zufällig erzeugten Hash-Server und die aktuelle Uhrzeit, die offenbar nicht von einem Angreifer erraten oder verändert werden.
Damit wir 'edit_post ()' zugreifen müssen wir zuerst dieses Token zu erhalten. Wir können in den Code zu sehen, dass der Token-Systeme erwartet wie formatiert ist "Add- [POST_TYPE] ', wobei POST_TYPE ist die Art des Postens wir bearbeiten wollen.
Wir versuchen, die Fähigkeiten zu umgehen überprüfen, bedeutet, dass wir einen Beitrag ID verwenden, die nicht vorhanden ist, die ein Token Aktion von "Add" schafft, als nicht vorhandenen Beitrag nicht einen Beitrag Typ hat. Zum Glück für uns, versucht der Code zuerst die Post-ID aus dem 'GET' HTTP Parameter 'post', abzurufen und nur dann, wenn es leer ist, versucht es, um es aus dem Feld "Post" zu bekommen. Das schafft die interessante Möglichkeit, 2 Post-IDs zu senden - eine in dem Parameter 'GET', die eine gültige Post-ID ist, und eine in der "Post" Parameter, der ungültig ist, so dass wir beide die richtige Token-String und umgehen die Fähigkeiten zu nutzen prüfen.
Jetzt, wo wir die 'add-post' token Zeichenfolge verwenden können, brauchen wir nur zugänglich Code zu finden, dass die Token generiert. Obwohl diese Aufgabe einfach scheint, schränkt unser Mangel an Fähigkeiten erheblich den Zugang zu anderen Aktionen. Auch hier war alles, was wir brauchen ein solcher Ort, die in der Tat in der Funktion 'wp_dashboard_quick_press ()' gefunden wurde. Dieser Code, neben anderen Maßnahmen, erzeugt einen gültigen Admin-Token.
Der Aufruf für diese Funktion gefunden wird, nicht weniger, wenn ein Benutzer ohne Fähigkeiten versucht, einen neuen Entwurf zu speichern. Dies kann in den folgenden Code zu sehen:
Wie sich oben, wenn ein Benutzer keine korrekte Token nicht liefert, oder fehlt die Fähigkeit der edit_posts ", wird die Funktion ausgelöst und wir erhalten eine gültige 'add-post' admin Token.
Mit diesem Token können wir jetzt frei bearbeitet bekommen in der "edit_post 'Funktion, solange wir eine ungültige Post-ID angeben.
An dieser Stelle können wir nicht geschützten Metadaten nicht vorhandene Beiträge erstellen und wählen Sie Taxonomien und mehrere andere kleinere Dinge zu schaffen und hinzufügen. Obwohl dies gut klingt, ist es noch weit von unserem Angreifers Ziel - wir wollen tatsächlich in der Lage sein, einen echten Beitrag zu bearbeiten, so dass wir Code zuvor von der 'edit_post' Fähigkeit Check geschützt zugreifen können.
Lassen Sie uns die Möglichkeit, Check-Code erneut zu prüfen:
Beachten Sie den markierten Code - wenn der Benutzer den Autor des Beitrags ist, und die Post ist derzeit als Abfall markiert, werden keine Fähigkeiten erforderlich. Dies markiert einen klaren Weg in Richtung Bearbeitungsrechte. Aber wie können wir sowohl ein Beitrag Autor geworden und setzen Sie den Status auf "Müll"?
Das erste Problem ist einfach - um einen Beitrag des Autors zu werden alles, was wir tun müssen, ist ein erstellen. Damit dies geschehen kann alles, was wir Aufruf "wp_dashboard_quick_press () 'tun müssen, genau wie wir, wenn wir unsere Token erstellt. Neben den Admin-Token erstellen, überprüft die Funktion auch, wenn ein Auto-Entwurf zuvor für den aktuellen Benutzer erstellt wurde. Wenn kein Entwurf erkannt wird, ruft die Funktion die "get_default_post_to_edit () ', die den folgenden Code enthält:
Wie man sehen kann, ruft der Code die Post-Titel, Inhalt und Auszug aus den Anforderungsparametern, und dann, wenn angewiesen, schafft den Posten in der DB. Der Ruf nach "wp_insert_post () 'enthält keinen Beitrag Autor, so dass das System übernimmt der Autor sollte der aktuelle Benutzer sein. Obwohl die Variable als Standard falsch zu sein ist '$ create_in_db' gesetzt, in unserem Fall 'wp_dashboard_quick_press ()' weist ihm den Wert "true" und schafft damit die Auto-Entwurf in der DB.
Nun, da wir einen Beitrag in der DB mit uns als die Post Autoren haben, müssen wir diesen Post-Status zu "Müll" zu ändern. Jetzt müssen wir einige schwarze Magie zu benutzen.
Wenn wir geben 'edit_post ()' die Post-ID wir in der DB vorhanden bearbeiten darf nicht anderweitig die Fähigkeiten überprüfen fehlschlagen und die Skriptausführung enden wird, aber wenn wir in 'wp_update_post ()' (zuständig für die Änderung der Post eingeben die DB) muss die Post-ID gültig und gibt es in der DB sonst die Funktion mit einem zurück Fehler "Post ist nicht vorhanden." Wie können wir diese zwei widersprechende Bedingungen zur gleichen Zeit erfüllen?
Einfach. Wir Zustand fahren.
Wenn wir 'edit_post ()' eingeben werden wir die ID des nächsten Post verwenden, um erstellt werden. Da die IDs automatisch erhöht werden, können wir "erraten" es, leicht leicht gemustert kann die ID des letzten vorhandenen Post gegeben werden. An diesem Punkt unsere ID nicht in der DB vorhanden sind, und wir werden in der Lage Prüfung ohne Probleme passieren. Dann, wenn diese Funktion ausgeführt wird, werden wir sofort eine weitere Anfrage senden einen neuen schnellen Entwurf zu erstellen, wie bereits gezeigt, um diese ID in der DB zu erstellen. Once 'edit_post ()' ruft 'wp_update_post ()', die Post aus der DB holen, wird es existieren und der Code wird weiterhin, nichts zu ahnen. J
Es bleibt die Frage, wie können wir zwei verschiedene Anfragen (edit Post gefolgt von Post-Erstellung) senden, in einer solchen sorgfältigen Timing so, dass diese Taktik funktioniert. Offensichtlich müssen wir die Script-Ausführung verzögern.
Schauen wir uns die 'edit_post ()' aussehen Code wieder:
Wir können sehen, dass die Variable '$ Begriffe ", von uns kontrolliert, in ein Array umgewandelt, indem sie mit einem Komma Aufspaltung (', '), falls es sich um eine Zeichenfolge handelt. Danach springt der Code durch das Array, jedes Element als Taxonomie Namen zu behandeln, und versucht es aus der DB holen mit einer "SELECT" Aussage.
Obwohl jeder "SELECT" Anweisung dauert ein paar Mikrosekunden auf einem gut geführten, leistungsfähigen Server, weil wir eigentlich 16MB (PHP harte Grenze für eine "POST" Parameter) von Begriffen senden können zu holen, können wir tatsächlich ausführen etwa 16 Millionen solcher Abfragen, die sehr viel Zeit ausführen zu nehmen. Auf meinem ziemlich leeren DB an meinem localhost befindet, angetrieben durch 1 GB RAM und einem i7-Prozessor, es dauerte nur etwa 100 Tausend Anfragen eine Verzögerung von 30 Sekunden zu verursachen.
Dies gewährt uns nun eine deterministische, extrem starke Hebel mit unserem Race-Bedingung zu nutzen, doch unsere Aufgabe ist noch nicht vorbei und wir haben noch ein paar Dinge, bevor sie vollständig Ausnutzen dieser Sicherheitslücke in einem deterministischen Herren auf jeder Wordpress-Installation in der Welt zu tun .
Weil wir 'wp_dashboard_quick_press ()', um rufen die Admin-Token abzurufen, die für den Code benötigt wird, um 'edit_post () "zu nennen, schaffen wir tatsächlich einen schnellen Entwurf in den Prozess. Wie ich bereits erwähnt, "wp_dashboard_quick_press () 'erzeugt nur einen Entwurf, wenn man nicht schon, und wie wir die gleiche Funktion wieder aufrufen, um erstellen müssen unseren Beitrag, während' edit_post () 'verzögert wird, wird dieser Prozess treten nicht auf.
Wie können wir einen Entwurf zu erstellen, wenn ein anderer ist bereits vorhanden? Nun, der Entwurf von "wp_dashboard_quick_press () 'erstellt ist kein gewöhnlicher Entwurf, es ist in der Tat ein kurzer Entwurf (auch eine Auto-Save). Als solches wird der Entwurf nur eine vorübergehende Art und Weise der Speicherung der Post Text im Falle eines plötzlichen Datenverlust sein soll. Da diese Entwürfe als temporäre Objekte behandelt werden, bekommen sie automatisch innerhalb einer Woche gelöscht.
Das bedeutet, dass wir eine ganze Woche, um zu warten, müssen unsere Sicherheitsanfälligkeit auszunutzen, da dies der Zeitrahmen, die diesen Entwurf gelöscht werden braucht. Zum Glück für uns, Token in der Regel letzten 24 Stunden, so dass wir das Token einen Tag vor dem erwarteten Löschdatum abzurufen, und es zu erhalten, um in 'edit_post ()' verwenden, nachdem der Entwurf gelöscht wird.
Schließlich, nachdem die Token-Validierung vorbei, die Privilegien-Validierung, die grundlegenden Admin-Validierung und die Post-ID-Validierung, die Änderung der Post-Status zu "Müll" ist so einfach wie einen HTTP-Parameter zu senden. Danke Gott.
Die Kombination zusammen alle diese Bypässe verwenden wir eine Kette von rund ein Dutzend verschiedene Bugs, eine fehlerhafte Berechtigungssystem, und über jede falsche Annahme im System Teil Editor Privilegien zu erreichen. Der Weg zu einer kritischen Sicherheitslücke ist noch lang, aber an seinem Ende fanden wir beide ein SQLI und eine XSS, um in den nächsten Beiträge beschrieben.
POC
Admin Token-Abruf / Post Schöpfung
Race-Bedingung