RUDY-Angriff: So wirkt er – und so prüfen Sie Ihre Abwehr

Ein langes Band, das einzeln mit leuchtenden Fragmenten gefüttert wird – der byteweise gesendete POST-Body eines RUDY-Angriffs

· 14 Min. Lesezeit

Ein RUDY-Angriff sieht nicht nach einem Angriff aus. Die Anfragezeile ist gültig, der Header-Block sauber abgeschlossen, und Content-Length nennt dem Server genau die Zahl der Byte, die noch folgen. Diese Zahl stimmt sogar. Auffällig ist einzig das Tempo, in dem der Body eintrifft: ein Byte, dann eine lange Pause, dann das nächste.

Damit ist RUDY schwerer zu fassen als Slowloris. Slowloris sendet eine Anfrage, die er nie zu Ende bringt; wer auf eine vollständige Anfrage wartet, merkt also, dass etwas fehlt. RUDY liefert genau den Teil vollständig, den Ihre Schutzmassnahmen prüfen, und hält jenen zurück, den sie nie ansehen. Ihre WAF findet nichts Verdächtiges – nach allem, was ihr vorliegt, ist auch nichts verdächtig.

Das Wichtigste in Kürze

  • Die Anfrage ist gültig, und genau darin liegt das Problem. Vollständige Header, zutreffende Content-Length. Eine WAF sieht einen legitimen POST und keine unfertige Anfrage; der Inspektion fehlt damit jeder Anhaltspunkt.
  • Ein einziger Socket hält einen Worker über Tage besetzt. Ein angekündigter Body von 100’000 Byte braucht bei einem Byte alle zehn Sekunden 1’000’000 Sekunden, also rund 11,6 Tage.
  • Ein Idle-Timeout greift hier nicht. nginx dokumentiert client_body_timeout (Standard 60s) als Grenze zwischen zwei aufeinanderfolgenden Leseoperationen, nicht für den Body als Ganzes. Ein Byte alle zehn Sekunden setzt diese Uhr immer wieder zurück.
  • Entscheidend ist eine Mindestdatenrate beim Lesen des Bodys. Bei Apache leistet das mod_reqtimeout – ein Erweiterungsmodul, das nichts bewirkt, solange es nicht geladen ist.
  • Verfolgen Sie die gehaltenen Verbindungen, nicht die Anfragerate. Jeder Slot öffnet genau einen Socket und behält ihn; die Ratenkurve bleibt deshalb nahe null, während der Angriff wirkt.

Dieser Beitrag gehört zu einer Reihe über alle zehn Simulationstypen, die Obsidio durchführt. Die Typen setzen an ganz unterschiedlichen Stellen an; ein Testprogramm braucht deshalb Abdeckung über alle Kategorien und nicht Volumen in einer einzigen. Wie sie zusammenspielen, steht in unserem Leitfaden dazu, wie Sie Ihren DDoS-Schutz testen.

Die zehn Simulationstypen

Ein Beitrag je Typ, gruppiert wie auf der Plattform.

Angriffe auf der Anwendungsschicht (L7)

Langsame Angriffe

Verbindungserschöpfung

Protokollspezifisch & skriptgesteuert

Was ein RUDY-Angriff tatsächlich macht

RUDY, kurz für R-U-Dead-Yet, öffnet parallel mehrere HTTP-POST-Verbindungen und schickt auf jeder einen vollständigen Anfragekopf: Anfragezeile, Host, einen Content-Type und eine Content-Length mit der exakten Grösse des folgenden Bodys. Diesen Body liefert er anschliessend Byte für Byte.

Der Server verhält sich dabei völlig vernünftig. Er kennt die angekündigte Menge, er hat einen Teil davon erhalten, und der Client meldet sich weiterhin. Also bleibt der zuständige Handler der Verbindung zugewiesen und wartet. Dieser Handler – ein Thread oder ein Worker-Slot – bedient in dieser Zeit niemanden sonst. Bei einigen Hundert gleichzeitigen Verbindungen ist der Pool leer. Echte Nutzer bekommen keine Fehlerseite zu sehen, sondern laufen in ein Timeout.

Zum Vergleich: Zwanzig Leute füllen am Schalter ein langes Formular aus und schreiben alle zehn Sekunden einen Buchstaben. Der Sachbearbeiter muss warten. Weiter kommt er erst, wenn das Formular fertig ist – und ausgefüllt wird es ja, nur nicht in diesem Jahr.

Eine kurze Rechnung zeigt, warum kein Slot wieder frei wird. Voreingestellt sind eine Content-Length von 100’000 Byte und ein Abstand von 10 Sekunden zwischen zwei Byte. Der Body braucht damit 1’000’000 Sekunden, also rund 11,6 Tage; so lange dauert kein realistischer Durchlauf. Jeder Slot hält seinen Socket, bis der Server ihn abbaut oder der Durchlauf endet. Bei 20 Sockets pro Worker liegt die Zahl der festhängenden Anfragen somit beim Zwanzigfachen der Worker-Zahl – und dort bleibt sie.

Welche Ihrer Schutzmassnahmen hier greifen müssten

Es lohnt sich, die ganze Kette abzugehen, die eine Anfrage durchläuft, denn die Antwort liegt selten bei der Massnahme, die man zuerst vermutet. Drei Bereiche zählen: was vorgelagert ist, was die durchgelassene Last auffängt, und ob Ihnen überhaupt jemand meldet, dass etwas passiert ist.

Zone 1

Was fängt sie auf?

  • DDoS-Schutz und Scrubbing. Warten auf einen Ausschlag im Datenverkehr. Ein Byte alle zehn Sekunden ist keiner.
  • Firewall und WAF. Der heikle Punkt. Die Header sind vollständig und die angekündigte Länge trifft zu, also sieht die Inspektion einen gültigen POST und lässt ihn passieren. Hilfreich ist sie nur, wenn sie den kompletten Body puffert, bevor sie ihn weitergibt; viele Installationen streamen ihn stattdessen durch.
  • Rate Limiting. Zählt Anfragen. Jede Quelle schickt eine Handvoll und verhält sich danach still.
  • Bot-Erkennung und Challenges. Es wird nie eine Seite geladen; eine Challenge findet keinen Ansatzpunkt.
  • CDN-Cache. Ein POST lässt sich nicht cachen, der Cache liegt also gar nicht im Anfragepfad.

Zone 2

Was bekommt die Last ab?

  • Load Balancer oder Reverse Proxy. Fängt den ganzen Angriff ab, sofern er die Bodys eingehender Anfragen puffert und die Verbindungslast selbst übernimmt. Prüfen Sie, ob Ihrer das tut.
  • Verbindungsschicht. Füllt sich mit Sockets, die aktiv sind und nicht untätig.
  • Webserver und Applikationsserver. Hier entsteht der Schaden. Die Handler hängen im Warten auf einen Body fest, solange keine Mindestdatenrate beim Lesen die Verbindung kappt.
  • Applikation und Datenbank. Werden nie erreicht. Der Handler steckt davor fest und wartet auf einen Body, der nie vollständig wird.
  • Auto-Scaling. Sieht keinen Lastausschlag und skaliert deshalb nie.

Zone 3

Würden Sie davon erfahren?

  • Dashboards. Die Anfragen pro Sekunde sehen völlig normal aus.
  • Eine Prüfung von ausserhalb Ihres Netzes. Das Einzige, was so etwas zuverlässig bemerkt – sofern Sie eine solche Prüfung überhaupt betreiben.
  • Logging und Ihr SIEM. Eine Anfrage landet erst im Access-Log, wenn sie beendet ist; danach sieht sie aus wie ein Client mit schlechter Leitung, der in ein Timeout gelaufen ist.
  • Alarmierung. Nichts überschreitet einen Schwellenwert.
  • Pikettdienst. Niemand wird aufgeboten. Der Dienst ist nicht erreichbar, und kein Alarm geht los.

Violett markiert, was sich nur mit einem Test auf Ihrer eigenen Infrastruktur klären lässt. Alles Übrige folgt aus der Funktionsweise des Angriffs und nicht daraus, wie sorgfältig Ihr Team konfiguriert hat.

In Zone 1 liegt der Unterschied zwischen diesem Angriff und Slowloris. Eine WAF, die auf eine vollständige Anfrage wartet, hat bei Slowloris einen guten Grund, den Verkehr zurückzuhalten: Die Anfrage ist unfertig. Genau diesen Grund nimmt RUDY ihr weg. Eine Massnahme, die entscheiden soll, ob diese Anfrage legitim ist, wird sie für legitim erklären – und liegt damit richtig. Als Signal bleibt allein, wie schnell der Body eintrifft, und diese Grösse werten die meisten Produkte zur Anfrageinspektion nicht aus.

Was RUDY von Slowloris unterscheidet

Fünf Unterschiede zählen. Jeder betrifft eine andere Schutzmassnahme.

  • Wo die Anfrage unvollständig bleibt. Das klassische Slowloris hält die Leerzeile zurück, die den Header-Block abschliesst; der Server kommt also über das Lesen der Header nie hinaus. RUDY sendet diesen Block korrekt und hält stattdessen den Body zurück. Ein Timeout für das Lesen der Header fängt den ersten Fall ab und hat mit dem zweiten nichts zu tun.
  • Ob das Ende des Bodys angekündigt ist. Slowloris kennt eine Variante mit langsamem Body; sie nutzt aber Chunked Transfer Encoding und sendet den abschliessenden Chunk der Länge null nie, sodass der Body kein angekündigtes Ende hat. RUDY nennt eine exakte Länge und hält sich daran, nur eben langsam. Hier fehlt kein Abschluss.
  • Welche Ressource zuerst ausgeht. Slowloris zielt auf den Verbindungspool vor Ihrer Applikation, RUDY auf die Handler des Webservers – denn der Server hat die Anfrage angenommen und ihr einen Worker fest zugewiesen.
  • Welches Timeout entscheidet. Bei Slowloris ist es ein Timeout für das Lesen der Header, bei RUDY eines für das Lesen des Bodys – und auch das nur, wenn es eine Mindestdatenrate durchsetzt.
  • Wie es im Log aussieht. Eine unfertige Slowloris-Anfrage erzeugt oft gar keinen Eintrag. Eine RUDY-Anfrage sieht aus wie ein gewöhnlicher POST von einem Client mit schlechter Leitung.

Viel einzustellen gibt es nicht. Die Sockets pro Worker stehen standardmässig auf 20 und reichen von 1 bis 100; damit legen Sie fest, wie viele Handler Sie besetzen wollen. Der Abstand zwischen zwei Body-Byte steht standardmässig auf 10 Sekunden und reicht von 1 bis 60: Ein kürzeres Intervall baut Sockets häufiger neu auf; ein längeres erschwert es, den einzelnen Socket per Timeout loszuwerden, riskiert aber, dass der Server ihn wegen Inaktivität schliesst. Die angekündigte Content-Length steht standardmässig auf 100’000 Byte und reicht von 1’000 bis 10’000’000; zusammen mit dem Intervall bestimmt sie die Lebensdauer jedes Sockets.

Host, Content-Type und Content-Length sind fest vorgegeben und lassen sich nicht überschreiben. Die zutreffend angekündigte Länge ist der Kern des Angriffs; liesse man sie verändern, wäre es eine andere Simulation.

Wie Sie sich gegen einen RUDY-Angriff schützen

Entscheidend ist eine Regel dafür, wie langsam ein Client einen Body liefern darf, den er bereits angekündigt hat. Drei Massnahmen leisten das, zwei häufig genannte nicht.

  • Eine Mindestdatenrate beim Lesen des Bodys. Bei Apache ist das mod_reqtimeout; sein dokumentierter Standard lautet RequestReadTimeout handshake=0 header=20-40,MinRate=500 body=20,MinRate=500. Der Body-Wert räumt mindestens 20 Sekunden ein, und laut Dokumentation verlängert jeder Dateneingang das Timeout entsprechend der Mindestdatenrate: 500 Byte bringen eine Sekunde mehr. Ein Byte alle zehn Sekunden bringt eine Fünfhundertstelsekunde, das Zeitfenster wächst also kaum, und die Verbindung wird geschlossen. Zwei Einschränkungen: Das Modul hat den Status einer Erweiterung und bleibt untätig, solange es nicht geladen ist; und der Standardwert für den Body kennt keine Obergrenze, sodass ein Client, der tatsächlich 500 Byte pro Sekunde durchhält, sein Timeout beliebig weiter verlängert.
  • Verlassen Sie sich nicht auf ein Idle-Timeout. nginx liefert client_body_timeout 60s aus, und die Dokumentation ist eindeutig: Der Wert gilt nur für die Spanne zwischen zwei aufeinanderfolgenden Leseoperationen, nicht für den gesamten Body. Ein Byte alle zehn Sekunden setzt ihn endlos zurück, und weil der Angreifer das Intervall wählt, gibt es keinen Wert, der echte Nutzer verschont und den Angriff trotzdem stoppt. Das Problem ist nicht die gewählte Zahl, sondern der Mechanismus: Er misst die falsche Grösse.
  • Ein Reverse Proxy, der Bodys vollständig puffert. Bei nginx ist proxy_request_buffering on der Standard; laut Dokumentation liest er damit den kompletten Body vom Client, bevor er die Anfrage an den Backend-Server weitergibt. Ihr Upstream wird also erst kontaktiert, wenn der Body vollständig vorliegt. Das schützt wirksam, unter zwei Bedingungen: Der Ursprungsserver darf nicht direkt erreichbar sein, und der Proxy muss viele offene Verbindungen mit geringem Aufwand halten können.
  • Grenzen für gleichzeitige Verbindungen je Quelle. Sie beenden einen Versuch aus einer einzelnen Quelle sofort, richten gegen Last aus Tausenden von Adressen aber wenig aus.
  • Obergrenzen für die Body-Grösse helfen nicht. Apaches LimitRequestBody steht in aktuellen 2.4-Releases standardmässig auf 1’073’741’824 Byte und lag in 2.4.53 und früher bei 0, also unbegrenzt. nginx setzt client_max_body_size auf 1m. Angekündigte 100’000 Byte passieren beide Grenzen; eine strengere Grenze sorgt nur dafür, dass Sockets etwas früher wieder frei werden.

Was Sie selbst prüfen können – und wo die Prüfung täuscht

Einen Teil davon klären Sie heute ohne fremde Hilfe. Wichtig ist zu wissen, welchen Teil – und an welcher Stelle eine schnelle Prüfung in die Irre führt.

Lesen Sie die Konfiguration. Prüfen Sie, ob es ein Timeout für das Lesen des Bodys gibt, ob es eine Mindestdatenrate durchsetzt oder bloss eine Lücke zwischen zwei Lesevorgängen begrenzt, ob das Modul geladen und nicht nur vorhanden ist, und ob Ihr Proxy Bodys puffert. Das belegt, dass die Einstellung existiert – nicht, dass sie standhält, wenn Hunderte Verbindungen gleichzeitig offen sind.

Prüfen Sie die Alarmierungswege für sich. Lösen Sie einen synthetischen Alarm aus und verfolgen Sie, ob er beim richtigen Pikettdienst ankommt und ob jemand reagiert. Das prüft die Mechanik und kommt ohne Angriffsverkehr aus.

Führen Sie einen Test aus einer Quelle gegen eine Staging-Umgebung durch, mit Freigabe aus dem Change-Management und auf Infrastruktur, die Ihnen gehört. Das ist zulässig und nützlich – und genau hier liegt die Falle.

Ein Test von einer einzigen Maschine lässt die Fragen aus Zone 1 nicht nur offen. Er beantwortet mehrere davon falsch, und zwar in die beruhigende Richtung. Ihre Begrenzung der Verbindungen je Quelle erwischt eine Adresse mit zwanzig Sockets fast sofort, und mit einem einzelnen unbekannten Client wird die Reputationsprüfung ebenfalls fertig. Jede Massnahme in der vorderen Zone scheint zu greifen, also halten Sie sich für geschützt.

Dann kommt die verteilte Variante: Tausende Adressen aus Privathaushalten, jede mit ein paar Sockets. Dieselben Massnahmen verhalten sich nun anders, denn sie setzen an der Konzentration der Quellen an und nicht an dem Verhalten, das den Schaden anrichtet. Gerade die Massnahmen, denen Sie am meisten vertrauen müssen, bestehen die schnelle Prüfung zu Unrecht.

Wie Obsidio einen RUDY-Angriff testet

Ob Ihr Handler-Pool standhält, hängt davon ab, wie Proxy, Webserver, Applikationsserver und Verbindungsgrenzen bei echter Parallelität zusammenspielen, und das steht in keiner einzelnen Konfigurationsdatei. Obsidio führt RUDY als kontrollierte, autorisierte Simulation gegen Infrastruktur durch, die Ihnen gehört. Die Domain-Inhaberschaft wird über einen DNS-TXT-Eintrag geprüft, bevor überhaupt Datenverkehr fliesst; die Durchläufe werden schrittweise hochgefahren, und jeder Durchlauf lässt sich im laufenden Betrieb abbrechen. Sie legen die Sockets pro Worker, das Intervall zwischen den Byte und die angekündigte Content-Length fest und beobachten dabei Ihren Stack. Weil die Last von über 100’000 weltweit verteilten echten Geräten kommt und nicht von einer Handvoll Instanzen im Rechenzentrum, wird eine Verbindungsgrenze je Quelle so geprüft, wie ein verteilter Angriff sie prüfen würde.

Achten Sie auf die richtige Kennzahl. Bei RUDY sind das die aktiven und die maximal gehaltenen Verbindungen je Bucket, denn sie zeigen, wie viele Handler zu einem Zeitpunkt besetzt sind. Die Anfragerate zählt, wie oft ein Socket geöffnet wird; jeder Slot öffnet genau einen und behält ihn, also liegt die Rate nahe null. Ein Team, das auf die Ratenkurve schaut, hält den Test für wirkungslos, während der Handler-Pool längst leerläuft.

Klären Sie vorab, wer welche Nachweise liefert. Obsidio berichtet, wie viele Verbindungen gehalten wurden und wie die Systeme an Ihrem Netzrand reagiert haben, weil beides von aussen sichtbar ist. Ob Ihr SIEM etwas aufgezeichnet hat, ob ein Dashboard ausgeschlagen ist und ob jemand aufgeboten wurde, steht nur auf Ihren eigenen Konsolen. Lassen Sie also während des Zeitfensters jemanden mitschauen.

Stärke wird bewiesen, nicht versprochen. RUDY prüft nicht Ihre Bandbreite. Er prüft, ob irgendetwas in Ihrem Stack eine Regel dafür kennt, wie langsam ein Client liefern darf, was er bereits angekündigt hat.

Wo das in ein Testprogramm gehört

RUDY und Slowloris sind die beiden Hälften der Kategorie der langsamen Angriffe; wer nur den einen prüft, hat den anderen nicht abgedeckt. Gegen Slowloris hilft ein Timeout für das Lesen der Header, weil dort ein Header-Block offen bleibt. Gegen RUDY hilft eine Mindestdatenrate beim Lesen des Bodys, weil dort ein angekündigter Body offen bleibt. Das sind unterschiedliche Einstellungen, meist an anderer Stelle und oft in der Verantwortung anderer Teams. Ein Flood-Test auf der Anwendungsschicht prüft keine von beiden; ein Programm, das ausschliesslich HTTP-Floods fährt, lässt diese Klasse deshalb ungeprüft.

Die zehn Simulationstypen setzen an ganz unterschiedlichen Stellen an. Ein HTTP-Flood dreht fast alles bisher Beschriebene um: Die vorderen Abwehrmassnahmen haben endlich etwas, worauf sie reagieren können, der Schaden erreicht Ihren Datenbank-Verbindungspool, und das Erkennungsproblem kehrt sich um – statt völliger Stille gibt es eine Alarmflut, in der das Wesentliche untergeht. Entscheidend ist Abdeckung über alle Kategorien, nicht Volumen in einer einzigen.

Für regulierte Institute muss ein Test zudem einen Nachweis hinterlassen. Obsidio erstellt kryptografisch attestierte, manipulationssichere Berichte, die FINMA, DORA und NIS2 zugeordnet sind und in Trusted Execution Environments erzeugt werden. Ein Durchlauf hinterlässt damit einen Beleg, den Sie ablegen können, und nicht einen Screenshot, für den Sie bürgen müssen.

Um eine autorisierte RUDY-Simulation gegen Ihre eigene Infrastruktur zu planen, sehen Sie sich die Obsidio-Plattform an oder nehmen Sie Kontakt auf. Unabhängig, neutral, überprüfbar: Resilienz, die Sie belegen können.

← Zurück zum Blog