WordPress: die vergessene mShot DOS Attacke

Alle guten Geschichten beginnen mit „Es war einmal..“ so auch meine heutige Geschichte eines längst vergessenen Dienstes, der zu einem DOS Angriffs mutiert ist. Wer WP betreibt, wird in diesem Artikel einige Denkeanstöße für seine eigene Instanz bekommen.

WordPress: die vergessene mShot DOS Attacke

Es war einmal ein Dienst der Firma AUTOMATTIC, Inc. die Ihres Zeichens nach WordPress.com betreibt. Wir schreiben die Prä-Neulandzeit. Der Dienst konnte Screenshots von Webseiten erzeugen und irgendwo einbasteln. Im Jahre der Merkel 2012 postete jemand eine Anfrage im WordPressforum, wo denn all die komischen Anfragen in seinem Blog herkommen würden, die „WordPress.com mShots“ im Useragent stehen haben.

Es wurde ihm folgendes mitgeteilt:

mShots was a third party extra feature that has been removed > mShots have been deactivated on all WordPress.com blogs, says a Happiness Engineer:
https://en.forums.wordpress.com/topic/does-using-zemanta-disable-mshots?replies=2#post-517481

Damit Ihr wisst um was es geht, hier ein exemplarischer Auszug aus einem Logfiles eines Kundenservers heute morgen, womit wir uns nebenbei +8 Jahre nach „Einstellung des Dienstes“ befinden:

192.0.100.186 – – [20/May/2020:08:51:12 +0200] „GET /trainer/ HTTP/1.1″ 301 20 „-“ „Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/69.0.3494.0 Safari/537.36 WordPress.com mShots
LOCALHOST – – [20/May/2020:08:51:21 +0200] „POST /trainer/wp-cron.php?doing_wp_cron=1589957481.2505230903625488281250 HTTP/1.1″ 200 20 „http://eine.wordpress.seite/trainer/wp-cron.php?doing_wp_cron=1589957481.2505230903625488281250″ „WordPress/5.3.3; https://eine.wordpress.seite/trainer
192.0.100.186 – – [20/May/2020:08:51:22 +0200] „GET /trainer/ HTTP/2.0″ 200 – „-“ „Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/69.0.3494.0 Safari/537.36 WordPress.com mShots

Damit der Spannungsbogen Euch nicht umbringt, hier eine erste Auflösung: der Dienst wurde nicht abgeschaltet 😉

Was sehen wir oben?

Wir haben den Zugriff vom WP Servercluster 192.0.100.186, dann einen Cronjob der von der WP Installation selbst stammt, und danach wieder ein Zugriff vom WP Cluster. Damit haben wir 3x PHP im Spiel, pro Aufruf.

Der Angriff aus dem Nichts

Jetzt gab es um 8:51:xx nicht nur Zugriffe auf diese eine WordPressinstanz, sondern über 100 haben gleichzeitig diese mShots Anfrage bekommen, mit dem Resultat das (am Ende) gleichzeitig hunderte PHP Prozesse liefen.

Jeder der sich mit Hosting auskennt, weiß, daß hunderte von PHP Prozessen jede Menge an Speicher, CPU Last und IO erzeugen, besonders wenn PHP nicht als Modul, sondern im sicheren CGI-Modus läuft. Jetzt wäre auch das nicht das Problem, wenn auf dem nur einige dieser WP Instanzen wären, waren sie aber nicht. Ein einziger Server hat diese Wucht abbekommen und der hatte auch nur 4 Kerne zur Verfügung.

Zufälle gibts, die gibt es gar nicht.

Um dem Ganzen oben noch die Krone aufzusetzen, hatte ein Mitarbeiter der für die WP Instanzen zuständigem Werbeagentur, kurz vorher ein Backup einer Präsenz gestartet. Zu den hunderten von PHP Prozessen lief also auch noch ein TAR/GZ Backup eines nicht kleinen Webdienstes mit 100% Leistung auf einem der vier Kerne.

Jetzt könnte man glauben, daß wäre ja schon Zufall genug, aber da lege ich jetzt noch einen drauf 🙂 Ich war nämlich heute morgen auch zufällig auf dem Server und wollte einer Meldung von letzter Nacht nachgehen, als ich aus Routine, aber wiederum zufällig, in TOP geschaut hatte, ob alles rund läuft. Dabei habe ich dann die ganzen PHP Prozesse im Aufbau eines Totalausfalls bemerkt und konnte gerade noch rechtzeitig „killall php-cgi“ eingeben, bevor es zum Kaskadenversagen durch CPU/IO/SWAP kam. Die Load war bereits auf dem Weg gen 75 😉

Die Suche nach der Ursache

Gefahr gebannt, aber was konnte das ausgelöst haben? So einen ähnlichen Vorfall hatten wir vor einigen Jahren auch mal, als ein Möchtegern-Hacker parallel allen WP-Instanzen ein paar unsinnige Anfragen geschickt hatte und das WP diese nicht beantwortbare Anfrage auch fleißig allen WP Plugins anbot, nur um dann doch 404 Seiten auszugeben, die wiederum im WP gelandet sind ( fast wärs eine Endloss-404-Schleife geworden ). Weil auch die 404 Seiten wiederum durch PHP liefen, hatte sich die Load auch unfreiwillig verdoppelt. Das haben wir damals dann geändert, so das 404 jetzt nur noch statische Webseiten sind, was die Performance des Servers stark verbessert hat.

Kein Hacker…

Umso mehr hatte mich dann gewundert, daß es wieder zu so einer DOSartigen Situation kam. Also schaute ich in die Logs und wurde schnell mit einer Reihe von IPs aus dem gleichen Block belohnt: Denen von WordPress.com.

192.0.100.186 – – [20/May/2020:08:51:12 +0200] „GET /trainer/ HTTP/1.1″ 301 20 „-“ „Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/69.0.3494.0 Safari/537.36 WordPress.com mShots

Da dort merkwürdigerweise immer mShots stand habe ich dann Tante Google gefragt, aber die meinte ja, siehe oben, daß es das gar nicht mehr geben würde. Also habe ich vergleichende Forensik betrieben und danach auf anderen bekannten WP Instanzen in unserem Cluster gesucht. Fündig wurde ich aber nicht.

„Wie das gibt es doch nicht..“

Das Gespräch mit dem Kunden, der sein Server da gerade gedost worden war, war dann nach einer Weile des Rätselns doch von Erfolg gekrönt. Im Ausschlussverfahren haben wir dann ein Plugin identifiziert, daß dafür indirekt verantwortlich war: der Elementor!

Elementor ist ein Plugin-System mit dem man „schneller“ (haha) komplizierte Layouts in WordPress umsetzen kann, als wenn man an den Themes rumspielt. Es ist also eine Art Homepagebaukasten innerhalb von WordPress. Jetzt sind meine Ansprüche an eine Webseite nicht so hoch, daß ich da Elementor einsetzen würde, wenn ich schon WP habe, aber das sehen Werbeagenturen naturgemäß anders 😉

Die Auflösung

Jetzt hatten wir einen Verdacht, also gruben wir noch etwas tiefer und schauten uns die Zeiten an, als den Server die mShots in der Vergangenheit getroffen hatten. Dabei stellte sich ein unregelmäßiges Muster ein, anhand dessen der Kunden dann eingrenzen konnte, daß wann immer er selbst in der Elementor-Zentralinstanz bei Elementor eingeloggt war, so ein DOS Angriff statt gefunden hatte. Das hat er selbst nicht gemerkt, weil er ja anderswo beschäftigt gewesen war. Meistens gab es da auch keine laufenden Backupprozesse, so das die mShot Anfragen bislang unbemerkt geblieben waren. Elementor fragt nämlich beim Login WordPress.com:mShots von allen verbundenen Webseiten (>100 Stück) einen aktuellen Screenshot zu besorgen.

Fazit: Der Kunde hatte sich mit dem Login bei Elementor,  und dem laufenden Backup unwissentlich selbst gedost. Das erlebt man auch nicht alle Tage 🙂

Die Empfehlung

Jetzt meine Empfehlung an Euch:

Auch wenn etwas bei der Anzahl 1, 2 oder 3 zügig reagiert, ist das bei 100+ nicht mehr der Fall.

Wenn Ihr also irgendein Programm baut, geht nicht davon aus, daß es ja nur die paar Testfälle verkraften muß, die Ihr hattet, sondern überlegt immer, was passieren kann, wenn hundert, tausend oder gar Millionen Abfragen involviert sind 🙂

Unser Kunde fragt derzeit bei Elementor an, ob man die Screenshots abschalten kann, das solltet Ihr auch abschalten, wenn Ihr so viele Instanzen auf einem einzigen Server habt. Glücklicherweise kam das Plugin nur bei den knapp über 100 WP Instanzen zum Einsatz, auf dem Server sind aber noch hunderte andere Instanzen untergebracht 😉

Wie wichtig das mit dem Einplanen nur „Millionen“ Anfragen sein kann, würde Euch ein anderer Feuerwehr-Fall zeigen, aber leider reden wir nicht über Kundenfälle, außer wir haben die Erlaubnis dazu, was aber hier der Fall ist.

 

Tracking über Browser API des Batteriestatuses

Wie die Webseite TheHackernews.com heute berichtet, ist es Forschern der Standford University bereits in 2015 gelungen, einen Super-Super-Cookie zu nutzen, in dem sie über die Browser API der mobilen Versionen von Chrome, Opera und Firefox den Batteriestatus abgefragt haben. Durch die Kombination von angezeigter „verbleibender Zeit in Sekunden“ und dem Prozentwert der Ladung, ergeben sich bis zu 14 Millionen Kombinationen, die man Geräten zu ordnen kann.

Steve Engelhard and Arvind Narayanan von der Princeton University, konnten nun in einem Forschungsbericht  zeigen, daß diese Technik bereits von Webseiten zum aktiven Tracken von Benutzern eingesetzt wird.

Zusammen mit anderen Techniken wird es damit immer schwerer dem Online-Tracking zu entgehen. Aber natürlich kann man etwas dagegen tun, denn auch für FireFox Mobile gibt es Noscript!  Ohne Javascript kann man Browser-Api’s nicht abfragen, was dazu führt, daß man nur ohne Javascript surfen muß.

Sollte man jetzt glauben, den Webseitenbetreibern ginge nur ums das reine Tracking dabei, weit gefehlt, daß ist nur zur Verbesserung der Identifikationsrate da, denn Tracking geht über sehr viele Browsermerkmale bereits gut ( mit Javascript).

Den Batteriestatus zu kennen, verleitet Verkäufer jetzt aber dazu, abhängig vom Stand die Preise zu ändern. Der Gedanke: „Der User ist unter Stress, weil seine Batterie bald schlapp macht und daher kauft er jetzt sofort das Erstbeste zum erstbesten Preis. Suchen bei der Konkurrenz kommen wegen des Batteriestandes nicht mehr in Frage. “

Damit könnte der Verkäufer sogar recht haben. Also, was heißt das ? Bei FireFox Javascript abschalten und gleichzeitig eine neue Kampagne starten, diese API zu begraben! Das man Chrome dazu bewegen kann, ist eher unwahrscheinlich. Google lebt ja vom Tracking anderer Leute 😉

Referenzen:

INRIA Privatics Forschungsbericht
Lukas Olejnik Blog
Random Walker – OpenWPM

Quelle: thehackernews.com

Jersey, Pydio & the next Big thing – Part II

Ja, es hat länger gedauert als erwartet. Nicht nur Jersey steckt voller Ungereimtheiten, auch Pydio hat tolle Bugs auf Lager. Kombiniert man das, verschwendet man richtig viel Zeit.

Status: Es geht.

Update der verwendeten Tools: Jersey 1.18 ( jsr311-api-1.1.jar, asm-3.1.jar, jersey-bundle-1.18.jar, NEU: jersey-multipart-1.18.jar)

Der Fileupload:

Der FileUpload stellt sich in Jersey schwieriger dar, als man annehmen sollte, denn die spärlichen Beispiele sind einfach mal falsch, solange man nicht die Suchbegriffe benutzt,
die einen ohnehin schon auf die richtige Fährte gebracht haben : MultiPart.

Aber auch da gibt es Fallstricke die es zu umschiffen geht und weil das einfach nur nervt, gibts hier gleich die Lösung der Probleme:

Schritt 1:

                FormDataMultiPart form = new FormDataMultiPart();
                FormDataBodyPart p = new FormDataBodyPart(
                            FormDataContentDisposition
                                .name("userfile_0")
                                .fileName("Dateiname")
                                .build()
                            , new File("Dateiname")
                            , MediaType.MULTIPART_FORM_DATA_TYPE);
                form.bodyPart(p);

Damit man FormDataMultiPart benutzen kann, muß oben erwähntes JAR-File zum Projekt hinzugefügt werden. Danach ist es aber ganz einfach das File dann wirklich per REST hochzuladen. Wobei REST hier wohl der falsche Ausdruck ist, denn es ist ein simples MultiPart-Form, daß per POST hochgeladen wird. Das macht jeder Webbrowser genauso.

Schritt 2:

                response = resource.queryParam("get_action","upload")
                           .queryParam("dir","/")
                           .queryParam("secure_token", securetoken )
                           .header("Cookie", cookieheader )
                           .accept(MediaType.APPLICATION_XML)
                           .type(MediaType.MULTIPART_FORM_DATA)
                           .post(ClientResponse.class, form);

Jetzt muß man natürlich noch den Share Call per API iniziieren werden, damit ein Downloadlink für die Datei erzeugt wird. Das sagt sich jetzt so leicht, denn Pydio 5.2.0 und 5.2.1 sind an der Stelle einfach mal defekt. Da wir mit der REST API arbeiten, erwartet unser Client zurecht auch eine korrekt formulierte Antwort und dazu gehört auch die korrekte Länge der Antwort vom Server. Die Entwickler von Pydio haben es nun geschafft diesen Teil der API erfolgreich zu entschärfen. Statt der korrekten Länge des Links, kommt ein

Content-Length:  0

und damit kann Jersey nicht umgehen. Daher darf man nun erstmal das Pydio Quickfixen.Von der Isolation des Fehlers bis zum funktionierenden Fix der PHP Anwendung, vergingen rund 80 Minuten.

Ich hege ja die Hoffnung, daß mein Bugreport gelesen und bearbeitet wird. Zur Sicherheitslücke die ich letzte Woche an das Team von Charles geschickt habe, kam nur ein : „Wir schicken Dir Deine Mail zurück-kam also an“ Nachricht zurück. Ein Umgang mit Securityproblemen muß sich wohl erst noch entwickeln. Was übrigens für den an sich sicheren Code von Pydio spricht. „Gut“ ist allerdings was anderes. Kommentare fehlen da fast vollständig 🙂

Nachdem nun diese Klippen umschifft sind, kann die eigentliche Arbeit an der Anwendung beginnen.

JAXB XML Parsing kann man übrigens getrost vergessen, der XML Code der von Pydio kommt überfordert den Parser, so daß Elemente einfach verloren gehen. Ob da der Fehler bei Pydio liegt, oder der Parser Bugs hat, mag ich nicht beurteilen. Ich habe mir dann flugs einen eigenen SimpleXML-Parser mit XML-zu-Objekt Komponente geschrieben. Reflektion ist ne schöne Sache in Java.

Wenn Sie also vorhaben sollten, für Pydio in Java zu entwickeln, kommt einiges auf Sie zu. Sie dürfen sich aber gern melden, wenn Sie Fragen haben. Aufgrund der Bots die mein Blog zum Abladen von Schrott missbrauchen wollen, kann ich leider keine Kommentarfunktion freischalten 🙁