01 · Entdeckung
Aus einzelnen auffälligen Requests wurde innerhalb weniger Tage ein Massenangriff
Ausgangspunkt waren ungewöhnlich viele HTTP-Anfragen auf die Produktübersicht eines WooCommerce-Shops. Angegriffen wurde dabei nicht primär die Startseite, der WordPress-Login oder die bekannte XML-RPC-Schnittstelle. Stattdessen konzentrierten sich die Requests auf die Filterfunktion des Shops.
Die angeforderten URLs enthielten WooCommerce-Filterparameter wie
filter_farbe, filter_material,
filter_laenge oder dazugehörige
query_type_...-Parameter. Die genaue Domain und die realen
URL-Strukturen des betroffenen Kunden veröffentlichen wir bewusst nicht.
GET /shop/?filter_farbe=schwarz,silber&query_type_farbe=or HTTP/1.1
Host: shop.example
User-Agent: Mozilla/5.0 (...) Chrome/...
Referer: -
Solche URLs sind funktional völlig legitim. Ein echter Kunde kann mehrere Produktmerkmale auswählen und damit genau solche Requests erzeugen. Problematisch wurde das Muster durch Frequenz, Verteilung und Kombination der Anfragen: Innerhalb kurzer Zeit kamen immer neue Filterkombinationen von immer neuen IPv4- und IPv6-Adressen.
Genau das macht diese Angriffsklasse unangenehm. Ein einzelner Request sieht zunächst nicht gefährlich aus. In sehr hoher Zahl können solche Aufrufe aber PHP, Datenbank und WooCommerce erheblich stärker belasten als der Abruf einer statischen Datei.
02 · Angriffsmuster
Hunderttausende Adressen statt weniger wiederkehrender Angreifer
Das entscheidende Merkmal war die extreme Verteilung. Klassische Webangriffe stammen häufig von einer überschaubaren Anzahl von Servern oder IP-Netzen. Hier war das Gegenteil der Fall: Die Zahl unterschiedlicher beobachteter Quell-IP-Adressen stieg zeitweise schneller als die Zahl sinnvoll lokal verwaltbarer Firewall-Einträge.
Wichtig ist die richtige Interpretation dieser Zahlen: 609.972 verschiedene Quell-IP-Adressen bedeuten nicht automatisch 609.972 verschiedene Angreifer oder kompromittierte Geräte. Hinter den Adressen können unter anderem Proxies, VPN-Endpunkte, kompromittierte Systeme, wechselnde Anschlüsse oder andere automatisiert nutzbare Infrastruktur stehen.
Belastbar ist lediglich die Aussage aus den Serverlogs: Die entsprechenden HTTP-Anfragen erreichten den Server unter mindestens 609.972 unterschiedlichen sichtbaren Quell-IP-Adressen.
Auch diese Zahl ist eher konservativ. Sie basiert auf den ausgewerteten Requests, die mit HTTP 403 blockiert wurden. Während der Angreifer seine Requests im Verlauf anpasste, konnten zeitweise einzelne Varianten die damalige Erkennungsregel umgehen und wurden mit HTTP 200 beantwortet. Diese Zugriffe sind in der genannten 403-basierten Zahl nicht enthalten.
03 · Entwicklung
Von 39 auf mehr als 400.000 Quell-IP-Adressen pro Tag
Besonders deutlich wird die Dynamik in der täglichen Auswertung. Gezählt wurde jede Quell-IP-Adresse pro Kalendertag nur einmal, sofern sie mindestens einen passenden Filter-Request erzeugte, der mit HTTP 403 beantwortet wurde.
Datum Unique Quell-IP-Adressen
17.08.2026 39
18.08.2026 14.467
19.08.2026 35.334
20.08.2026 52.177
21.08.2026 43.156
22.08.2026 14.311
23.08.2026 194
24.08.2026 4.240
25.08.2026 47.944
26.08.2026 75.534
27.08.2026 406.232
28.08.2026 ≥103.278 *
* Der Wert vom 28. August wurde während des laufenden Tages ermittelt und ist deshalb als Mindestwert zu verstehen.
Der 27. August war der auffälligste Tag: Nach 75.534 unterschiedlichen Adressen am Vortag wurden innerhalb eines Tages 406.232 unterschiedliche Quell-IP-Adressen registriert. Die Anzahl hatte sich damit gegenüber dem 26. August mehr als verfünffacht.
Die Werte zeigen gleichzeitig, warum die Summe der Tageswerte nicht mit der Zahl unterschiedlicher Adressen über den Gesamtzeitraum gleichgesetzt werden darf. Eine Adresse kann an mehreren Tagen auftreten und wird dann in jeder Tagesstatistik erneut gezählt. Für den Gesamtzeitraum wurden die Adressen deshalb zusätzlich über alle ausgewerteten Logs hinweg dedupliziert. Daraus ergaben sich mindestens 609.972 verschiedene Quell-IP-Adressen.
04 · Webserver-Abwehr
Der wichtigste Schutz fand vor WordPress und WooCommerce statt
Bei einem solchen Angriff ist entscheidend, an welcher Stelle ein Request verworfen wird. Wird die Anfrage erst innerhalb von WordPress erkannt, sind PHP, WordPress und möglicherweise bereits Teile der WooCommerce-Logik aktiv geworden. Ein großer Teil der gewünschten Entlastung wäre damit verloren.
Deshalb wurden eindeutig verdächtige Requests über Apache-Rewrite-Regeln bereits vor der regulären WordPress-Verarbeitung mit HTTP 403 Forbidden beantwortet.
RewriteCond %{REQUEST_URI} ^/shop/ [NC]
RewriteCond %{QUERY_STRING} (^|&)filter_[^=]+= [NC]
...
RewriteRule ^ - [F,L]
Der entscheidende Vorteil: Für einen geblockten Request musste WooCommerce die angeforderte Produktfilterung nicht mehr ausführen. Die Webserver-Regel war deshalb die eigentliche Schutzschicht. Fail2Ban wurde ergänzend für Erkennung, Korrelation und Abuse-Reporting eingesetzt.
Diese Unterscheidung wurde im weiteren Verlauf noch wichtig: Ein Fail2Ban-„Ban“ bedeutete bei diesem speziellen Jail nicht automatisch, dass eine zusätzliche iptables-Regel angelegt wurde. Die eigentliche Abweisung der Filter-Requests erfolgte bereits durch Apache.
05 · Anpassung des Angriffs
Die Bots änderten ihr Verhalten
Anfangs war ein zusätzliches Merkmal auffällig: Viele der automatisierten Filter-Requests wurden ohne HTTP-Referer gesendet. Das ließ sich zunächst als zusätzliches Signal nutzen.
Im weiteren Verlauf änderte sich das Muster. Neue Requests übermittelten plötzlich einen plausibel wirkenden Referer der angegriffenen Website. Anfragen, die zuvor anhand des fehlenden Referers blockiert worden wären, erhielten dadurch wieder HTTP 200.
GET /shop/?filter_farbe=... HTTP/1.1
Host: shop.example
Referer: https://shop.example/
User-Agent: Mozilla/5.0 (...) Chrome/...
Das ist ein wichtiger Punkt bei der Entwicklung eigener Webserver-Regeln:
Header wie Referer oder User-Agent sind keine
vertrauenswürdigen Identitätsmerkmale. Ein Bot kann beide Werte beliebig
setzen.
Eine kurzfristig verschärfte Referer-Regel zeigte außerdem unmittelbar, warum False Positives berücksichtigt werden müssen. Auch ein echter Browser erzeugte bei einer legitimen Filterauswahl denselben Basis-Referer wie die angepassten Bots und wurde deshalb mit HTTP 403 abgewiesen.
Die Regel wurde daraufhin wieder verfeinert. Für die Abwehr ist nicht ein einzelner Header entscheidend, sondern die Kombination aus URL-Muster, Request-Verhalten und dem vorherigen Ablauf einer normalen Browser-Sitzung.
06 · Fail2Ban
Die Erkennung funktionierte – die Aktionsverarbeitung konnte nicht mehr mithalten
Parallel zur Webserver-Abwehr wurden die 403-Ereignisse von Fail2Ban
ausgewertet. Um zu prüfen, ob der verwendete Filter selbst das Problem war,
wurde ein kompletter Tagesausschnitt separat mit
fail2ban-regex getestet.
Damit war klar: Das Problem lag nicht primär in der regulären Expression. Der Filter erkannte praktisch alle relevanten Logzeilen.
Der Engpass entstand bei den Aktionen
Das Jail war so konfiguriert, dass bereits ein einzelner passender Filter-Request eine Aktion auslöste. Zusätzlich wurden erkannte Quell-IP-Adressen automatisiert an externe Abuse-Dienste gemeldet.
Solche HTTP-API-Aufrufe benötigen Zeit. Ein manueller Test der damals konfigurierten beiden externen Reporting-Aufrufe benötigte zusammen rund 1,13 Sekunden. Unter normalen Bedingungen ist das unproblematisch. Bei zehntausenden neuen Adressen in kurzer Zeit entsteht daraus jedoch eine Warteschlange.
Ein konkreter Logeintrag zeigte die Auswirkung besonders deutlich:
07:03:36 [woocommerce-filter] Found [anonymisierte IP]
07:13:21 [woocommerce-filter] Ban [anonymisierte IP]
07:13:33 [woocommerce-filter] Unban [anonymisierte IP]
Zwischen Erkennung und ausgeführter Ban-Aktion lagen in diesem Beispiel ungefähr 9 Minuten und 46 Sekunden. Rund zwölf Sekunden nach der tatsächlichen Ban-Aktion folgte bereits der Unban.
Das ist ein klassisches Skalierungsproblem: Eine synchrone Aktion, die bei einigen Ereignissen pro Minute hervorragend funktioniert, kann bei tausenden neuen Ereignissen pro Minute zum Flaschenhals werden.
Für den Schutz der Website war dieser Rückstand nicht unmittelbar entscheidend, weil Apache die Requests bereits vorher mit HTTP 403 abwies. Für zeitnahes Abuse-Reporting war die Verzögerung dagegen deutlich sichtbar.
07 · OpenVZ und recidive
Aus dem Bot-Angriff wurde zusätzlich ein Firewall-Ressourcenproblem
Die technisch interessanteste Nebenwirkung entstand durch das
Fail2Ban-Jail recidive. Dieses Jail verfolgt wiederholte
Fail2Ban-Bans und sperrt mehrfach auffällige Adressen für einen längeren
Zeitraum.
Normalerweise ist das sinnvoll: Wer beispielsweise wiederholt bei SSH, WordPress oder einem Maildienst auffällt, kann längerfristig geblockt werden.
In diesem Fall erzeugte das massenhaft auslösende WooCommerce-Jail jedoch
eine enorme Zahl von Fail2Ban-Ban-Ereignissen. Das allgemeine
recidive-Jail sah diese Ereignisse ebenfalls und begann,
entsprechende Adressen über iptables zu sperren.
Der Server läuft in einem OpenVZ-Container. Für iptables-Einträge existiert
dort ein vom Host vorgegebenes Ressourcenlimit. Das relevante
numiptent-Limit lag bei 3.000 Einträgen.
numiptent 3000 3000 3000 3000 ...
Das Limit war vollständig ausgeschöpft. Neue Firewall-Regeln konnten nicht mehr zuverlässig angelegt werden. In den Logs erschien unter anderem:
iptables: Memory allocation problem.
Das ist in diesem Zusammenhang keine klassische RAM-Fehlermeldung. Die Ursache war die ausgeschöpfte OpenVZ-Ressource für iptables-Einträge.
Die Zahlen machten die Ursache eindeutig
Vor dem Stoppen von recidive enthielt
iptables-save rund 2.920 Zeilen.
Davon waren 2.761 Fail2Ban-bezogen.
Gleichzeitig meldete Fail2Ban intern für recidive zeitweise
mehr als 16.000 aktuell gebannte Adressen. Tatsächlich
konnten aufgrund des OpenVZ-Limits jedoch nur ungefähr 2.700 entsprechende
Firewall-Einträge existieren.
Damit waren Fail2Bans interner Zustand und die tatsächlich programmierte Firewall nicht mehr deckungsgleich.
Nach dem Stoppen des recidive-Jails war der Effekt sofort
messbar:
Vorher:
iptables-save: ca. 2.920 Zeilen
numiptent: 3.000 / 3.000
Nach Stoppen von recidive:
iptables-save: ca. 172 Zeilen
numiptent: 239 / 3.000
Dieser Vergleich war der eindeutige Nachweis dafür, dass nicht der
Webserver-Block selbst, sondern die sekundäre Verarbeitung durch
recidive das OpenVZ-Firewall-Limit ausgeschöpft hatte.
Für dieses Szenario wurde recidive deshalb aus der
massenhaften Verarbeitung herausgenommen beziehungsweise deaktiviert.
Eine Firewall mit einem Limit von 3.000 Einträgen kann ohnehin nicht die
richtige Ebene sein, um einen Angriff mit mehreren hunderttausend
wechselnden Quell-IP-Adressen einzeln zu beantworten.
08 · Erkenntnisse
Was sich aus diesem Vorfall für die Bot-Abwehr ableiten lässt
- So früh wie möglich blockieren: Teure WooCommerce-Requests sollten nach Möglichkeit vor PHP, WordPress und Datenbankverarbeitung verworfen werden.
- IP-Adressen nicht mit Angreifern gleichsetzen: Hunderttausende beobachtete Quell-IP-Adressen belegen eine stark verteilte Infrastruktur, aber nicht automatisch ebenso viele kompromittierte Geräte oder Personen.
- Referer und User-Agent sind nur Signale: Beide HTTP-Header können von Angreifern frei gesetzt werden und dürfen nicht als alleiniger Vertrauensnachweis dienen.
- False Positives aktiv testen: Eine Regel, die den Bot zuverlässig blockiert, ist wertlos, wenn gleichzeitig echte Kunden die Produktfilter nicht mehr verwenden können.
- Fail2Ban-Filter und Fail2Ban-Aktionen getrennt betrachten: Eine Erkennungsrate von 99,93 Prozent bedeutet nicht, dass nachgelagerte Aktionen mit derselben Geschwindigkeit verarbeitet werden können.
- Externe API-Aufrufe skalieren anders als lokale Regeln: Synchrone Abuse-Reports können bei extremen Ereignisraten eine erhebliche Warteschlange erzeugen.
- recidive nicht blind auf jedes Massenevent anwenden: Ein Reporting-Jail mit hunderttausenden Treffern kann ein allgemeines recidive-Jail mit Ereignissen fluten, obwohl eine langfristige lokale Firewall-Sperre für diese Angriffsklasse keinen praktischen Nutzen hat.
-
Container-Limits berücksichtigen:
In OpenVZ sind Ressourcen wie
numiptentbegrenzt. Eine Konfiguration, die auf einem dedizierten Server problemlos funktioniert, kann in einem Container an harte Host-Limits stoßen. - Hochgradig verteilte Angriffe gehören langfristig vor den Server: Wenn hunderttausende verschiedene Quell-Adressen beteiligt sind, werden Provider-, Reverse-Proxy- oder andere vorgelagerte Schutzmechanismen wichtiger als eine immer längere lokale IP-Sperrliste.
Technische Einordnung
War das ein DDoS-Angriff?
Der beobachtete Traffic hatte wesentliche Merkmale eines stark verteilten applikationsnahen Angriffs: sehr viele unterschiedliche Quell-IP-Adressen, automatisierte HTTP-Requests und die gezielte Nutzung einer Funktion, deren Verarbeitung deutlich aufwendiger ist als der Abruf statischer Inhalte.
Aus den Webserverlogs allein lässt sich jedoch nicht belastbar bestimmen, wem die beteiligten Systeme gehörten oder ob sämtliche sichtbaren Quell-Adressen Teil eines klassischen Botnetzes waren. Deshalb sprechen wir bewusst von einem hochgradig verteilten Bot- beziehungsweise HTTP-Angriff und nicht von Hunderttausenden eindeutig kompromittierten Geräten.
Für die technische Abwehr ist diese Unterscheidung ohnehin zweitrangig. Entscheidend ist, dass eine Strategie nach dem Muster „eine auffällige IP erkennen und anschließend langfristig sperren“ bei einer derartigen Quellenrotation nicht ausreichend skaliert.
Fazit
Die beste Sperrliste war in diesem Fall gar keine Sperrliste
Der Vorfall begann mit scheinbar gewöhnlichen WooCommerce-Filteranfragen und entwickelte sich innerhalb weniger Tage zu einem Angriff mit hunderttausenden unterschiedlichen sichtbaren Quell-IP-Adressen. Am 27. August 2026 wurden allein 406.232 unterschiedliche Adressen registriert. Über die ausgewerteten geblockten Logs hinweg ließen sich mindestens 609.972 verschiedene Quell-IP-Adressen nachweisen.
Die wirksamste Maßnahme bestand nicht darin, all diese Adressen einzeln in eine Firewall zu schreiben. Entscheidend war, die charakteristischen Requests bereits auf Webserver-Ebene zu erkennen und vor der Ausführung von WordPress und WooCommerce mit HTTP 403 abzuweisen.
Gleichzeitig zeigte der Vorfall eine zweite wichtige Lektion:
Sicherheitsmechanismen müssen auch unter Extrembedingungen betrachtet
werden. Das für normale Angriffe sinnvolle Fail2Ban-recidive
wurde durch die enorme Zahl an Ereignissen selbst zum Ressourcenproblem
und schöpfte das OpenVZ-Limit von 3.000 iptables-Einträgen vollständig aus.
Nach dem Stoppen des Jails sank die Belegung auf nur noch 239 Einträge.
Gute Abwehr bedeutet deshalb nicht, möglichst viele Sperren zu sammeln. Sie bedeutet, den Angriff möglichst früh, möglichst günstig und auf der richtigen technischen Ebene zu stoppen.
Sie beobachten ungewöhnlich viele Requests, hohe PHP-Last oder automatisierte Zugriffe auf WordPress- und WooCommerce-Systeme? FD-IX unterstützt bei der technischen Analyse von Webserverlogs, Fail2Ban-Regeln und der Entwicklung möglichst zielgerichteter Schutzmaßnahmen.
Cybersecurity-Vorfall mit FD-IX prüfen