DDoS-Abwehr mit Lighttpd und mod_magnet

Ob man will oder nicht, als Systemadministrator kommt man in neuerer Zeit kaum und Lighttpd herum. Für mich nicht ganz nachvollziehbar entwickelt sich Lighty mehr und mehr zur Alternative zum alteingesessenen Apache Webserver. Klar, dass Lighty dann mehr und mehr auf Servern zu finden ist, wo ich Zugang habe.

Benötigt man Standardaufgaben, kommt man mit Lighttpd mittlerweile in der Tat gut zurecht, das ändert sich allerdings relativ schnell, wenn man exotischere Anforderungen an den Webserver hat. Dort ist man in der Regel mit Apache besser beraten, für keinen anderen Webserver gibt es einen ähnlich großen Fundus an Modulen und Erweiterungen, auf dem man bei Bedarf zurückgreifen kann. Wird man zum Beispiel mit DDoS geplagt, gibt es dort zwei wunderbare Module: mod_evasive und mod_security. Mit Lighttpd wird das komplizierter, etwas trickreich und zweckentfremdet kommt man aber auch dort zum Ziel. Mit dem Lighty Core-Modul “mod_magnet” kann man auch Lighty zur Abwehr von DDoS benutzen.

Grundlagen und Voraussetzungen

Mit DDoS meint man “Distributed Denial of Service” - auf Deutsch also in etwa “Verteilte Dienstverweigerung”. Darunter fasst der leidgeprüfte Administrator alle Möglichkeiten zusammen, die dazu dienen absichtlich oder unabsichtlich die Erreichbarkeit eines Dienstes zu beeinflussen.

Eine Webseite hat nur einen Nutzen, wenn diese von den potentiellen Besuchern erreichbar ist, hilft jemand externes nach, die Erreichbarkeit der Seite zu beeinflussen spricht man von DoS. Dies ist zum Beispiel der Fall, wenn ein Angreifer speziell präparierte Anfragen an den Webserver schickt und diesen damit zum Absturz bringt. Eine höchst effiziente Methode, eine Seite für alle anderen Besucher ebenfalls mal eben “auszuknipsen”. Dummerweise, oder glücklicherweise - je nach Standpunkt - gibt es aber nicht all zu viele derartig ausnutzbare Lücken in etablierten Daemons.

Dann hilft nur noch die Holzhammermethode, die in etwa so lautet: wenn ich den Dienst schon nicht ausschalten kann, überlaste ich ihn einfach. Das erreicht man am einfachsten dadurch indem man einen Daemon kontinuierlich von vielen Stellen aus gleichzeitig mit Anfragen bombardiert. Jede Hardware hat physikalische Grenzen, sei es an Leistungskapazität oder Bandbreite. Schafft man es aus Angreifersicht an die Grenze von einem dieser beiden Faktoren zu gelangen, hat man gewonnen - der Daemon wird seinen Dienst aufgeben und man hat gewonnen.

Eine sehr einfache und asynchrone Methode dies zu erreichen, ist SYN-Flood. Darüber und die Abwehrmöglichkeiten davon habe ich bereits gesprochen. SYN-Flood attackiert nicht einen spezifischen Daemon, sondern die TCP-Implementierung vom Betriebssystem. Es ist damit unabhängig von verwendeter Software und Protokollen. Ein Angriff auf den Webserver wird genau gleich durchgeführt, wie auf den Mailserver oder den FTP-Server.

SYN-Flood ist unbequem, aber nicht unabwehrbar. Deutlich schlechtere Karten hat man auf L7-Angriffe. L7 meint hier die 7. Schicht im OSI-Referenzmodell - die eigentliche Applikation. Diese Angriffe sind deutlich aufwändiger für den Angreifer, denn anders als bei primitiveren Angriffen, muss hier eine reguläre TCP-Verbindung hergestellt werden und eine ganz normale HTTP-Anfragen an den Webserver geschickt werden, genau wie es jeder Browser eines Besuchers auch tut. Das ist deutlich aufwendiger und benötigt sehr viel mehr Ressourcen als SYN-Flood, ist aber auch deutlich tückischer. Denn aus Sicht des Webservers ist es äußerst schwierig bis unmöglich zu unterschieden, ob eine Anfrage von einem regulären Besucher stammt, oder von einem Angreifer.

Einen DDoS-Angriff auf dieser Ebene kann man nicht abwehren, man kann den Schaden lediglich minimieren und eingrenzen. Meistens ist der Administrator nicht machtlos, die zur Verfügung stehenden Mittel sind aber begrenzt und ab einem gewissen Punkt wirkungslos. Im folgenden werde ich zum Beispiel einen Filter vorstellen, der “gute” Anfragen von “bösen” zu unterscheiden versucht. Das impliziert jedoch, dass es ein Filterkriterium gibt, der die beiden Anfragen von einander unterscheidet - meistens gibt es das, aber eben nicht immer.
Doch selbst ein Filter ist noch keine Garantie. Um eine HTTP-Anfrage untersuchen zu können, muss man sie bis zum Webserver durchlassen und dann mehr oder weniger aufwendig filtern. Hier gibt es einen kritischen Punkt an Anfragen, die jede Hardware und jeder Daemon gleichzeitig bewältigen kann. Ist der überschritten, hilft kein Filter mehr, denn dann reicht allein die Behandlung der parallelen Anfragen bereits aus, den Server damit auszulasten. Ist man soweit, hat man Pech gehabt. Dann hilft nur noch abwarten und hoffen, der Angriff möge vorbei gehen.

Zugegeben, das stimmt nicht ganz, es gibt dann noch Möglichkeiten, die setzen aber eine prall gefüllte Geldbörse für einen dedizierten durchsatzstarken Paketfilter auf Hardwareebene voraus - sind also mit einem konventionellen Betriebssystem wie Linux oder Windows oder was auch immer nicht mehr behandelbar, die wenn überhaupt bestenfalls einen softwarebasierten Paketfilter mitbringen. Netfilter (iptables) ist hier unter Linux keine Ausnahme und erreicht ebenfalls schnell Grenzen, wo eine Verwendung sinnlos ist, weil der Filtervorgang an sich bereits die Maschine voll auslastet. Die Chancen stehen übrigens gut, dass diese massiven Bandbreiten der Angreifer dadurch erreicht werden, dass jemand anderes zu sorglos mit seinem Server umgeht.

Umsetzung

Allerdings muss man nicht immer gleich das Handtuch werfen, nur wenige Angriffe die ich miterlebt habe, erreichten jemals diese architekturbedingten Kapazitätsgrenzen. Es macht also durchaus Sinn, sich mit den Möglichkeiten der Filterung von diesen Angriffen zu befassen.

Das Hauptproblem bei einem “intelligenten” DDoS auf die Applikation an sich ist, diesen überhaupt zu erkennen. Das mag banal klingen, aber nicht jeder Huster im Netz ist DDoS und nicht jede ungewöhnliche Lastspitze ein Angriff. In der Tat ist es viel häufiger und wahrscheinlicher, dass man sich selbst in den Lasttod befördert. Häufiger als gemeinhin bekannt, kann irgendeine kleine Codeänderung zu unerwarteten Ergebnissen führen. Oder auch ganz plötzliche Lastzuwächse, bedingt durch die Verlinkung auf einer großen renomierten Seite mit entsprechenden Besucherzahlen (Stichwort “Slashdot-Effekt“), müssen nicht unbedingt böswillige Absicht von einem Missgünstling sein.

Manchmal ist eine überlastete Seite schlicht eine überlastete Seite, ganz ohne Nachhilfe. In dem Fall ist vermutlich die Optimierung von Code und Daemons zielführender, als die Suche nach Gespenstern. Kann man dies alles ausschließen, ist es an der Zeit, sich auf die Suche nach dem DDoS zu begeben. Hier zeigt sich auch gleich, wie voraussehend der Administrator den Server konfiguriert hat. Ein durchdachtes Setup wird nämlich nicht immer mehr und mehr ermöglichen und schließlich ganz umkippen, sondern irgendwann die weiße Fahne schwenken und sagen “ich kann nicht mehr”. Mit anderen Worten: der Webserver muss so konfiguriert sein, dass er unter totaler Auslastung nicht den kompletten Server mit sich reißt. Nichts ist nerviger als eine Shell, die nicht mehr reagiert, weil der Lighttpd 5000 PHP-Prozesse spawnt.

Viel sinnvoller ist hier ein realistisches Limit zu setzen und darüber hinaus aufzugeben und gar nicht mehr erst versuchen, Seiten auszuliefern. Auf moderner Hardware und einem dedizierten Webserver kann man es schon mal mit 400 PHP-Prozessen und mehr versuchen. In der Praxis würde das bei voller Auslastung zwar eine Systemlast (”Load Average”) in dreistelliger Höhe erzeugen, den Server und Shell aber nicht völlig auslasten, sodass eine Reaktion vom Administrator zumindest noch möglich ist. Der erste Schritt zur DDoS Abwehr auf einem Lighttpd mit PHP ist also ein vernünftige Limit an PHP-Prozessen in der lighttpd.conf zu setzen (max-procs * PHP_FCGI_CHILDREN = 10 * 40 = 400)

fastcgi.server             = ( ".php" => ( "localhost" =>
                                (
                                        "socket" => "/tmp/php-fastcgi.socket",
                                        "bin-path" => "/usr/bin/php-cgi",
                                        "max-load-per-proc" => 8,
                                        "min-procs" => 1,
                                        "max-procs" => 10,
                                        "bin-environment" =>
                                        (
                                                   "PHP_FCGI_CHILDREN" => "40",
                                                   "PHP_FCGI_MAX_REQUESTS" => "10000"
                                        ),
                                        "broken-scriptfilename" => "enable"
)))

Erste Anlaufstelle ist dann das Log des Daemons, im Falle des Webservers Access- und Error-Log. Dort gibt Lighttpd Aufschluss darüber, ob das Limit an PHP-Prozessen erreicht wird. Das sieht dann so aus:

2008-03-12 18:50:00: (server.c.1253) NOTE: a request for /index.php timed out after writing 35040 bytes. We waited 5 seconds. If this a problem increase server.max-write-idle
2008-03-12 18:50:13: (mod_fastcgi.c.2855) backend is overloaded; we'll disable it for 2 seconds and send the request to another backend instead: reconnects: 0 load: 344
2008-03-12 18:50:14: (mod_fastcgi.c.2855) backend is overloaded; we'll disable it for 2 seconds and send the request to another backend instead: reconnects: 0 load: 373
2008-03-12 18:50:14: (mod_fastcgi.c.2633) fcgi-server re-enabled:  0 /tmp/php-fastcgi.socket
2008-03-12 18:50:14: (mod_fastcgi.c.2855) backend is overloaded; we'll disable it for 2 seconds and send the request to another backend instead: reconnects: 0 load: 391
2008-03-12 18:50:14: (mod_fastcgi.c.2855) backend is overloaded; we'll disable it for 2 seconds and send the request to another backend instead: reconnects: 0 load: 394
2008-03-12 18:50:14: (mod_fastcgi.c.3496) all handlers for  /index.php on .php are down.

In dem Fall endet das also damit, dass Lighttpd aufgibt und gar nicht mehr erst versucht, HTTP-Anfragen an PHP weiter zu geben (”all handlers for /index.php on .php are down“). Besucher der Webseite erhalten ab diesem Zeitpunkt einen 500-Statuscode (”Internal Server Error”) im Browser, die Seite ist down, der DDoS damit erfolgreich. Die Zeitspanne in diesem Ausschnitt von einer einzigen Sekunde in dem gleich mehrere Handler aufgeben, also voll ausgelastet mit jeweils 40 PHP-Prozessen sind, ist deutliches Anzeichen für einen massiven DDoS, kein regulärer Besucheransturm würde das so kurzfristig schaffen.

Mit dem Wissen, das viele Tausend Anfragen gleichzeitig den Server bombardieren, geht es nun auf Mustersuche. Es gilt nun herauszufinden, ob es etwas gibt, was die Angreifer von einem regulären Besucher unterscheidet. Eine Filterung nach IP-Adresse hingegen macht keinen Sinn. Diese sind zu weit gestreut, als dass sich auf dieser Grundlage ein Filter bauen ließe. Interessanter ist also die Suche nach einem besonderen Merkmal der HTTP-Anfragen, ein Muster das sich bei jeder “bösen” Anfrage wiederholt.

Wir alle hinterlassen beim Besuch von Webseiten Spuren, besondere Merkmale die unser Browser und unser Betriebssystem dem angefragten Webserver übermittelt. Bei jeder HTTP-Anfrage an den Webserver übergeben wir besondere HTTP-Header. Das sieht dann zum Beispiel so aus, wenn ich mit meinem Browser die Seite “http://burnachurch.com/index.php” aufrufe:

GET /index.php HTTP/1.1
Host: burnachurch.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.12) Gecko/20080129 Iceweasel/2.0.0.12 (Debian-2.0.0.12-1)
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

So wie ich das tue, tut dies auch jeder reguläre Besucher und jede bösartige Drohne die eine protokoll-konforme Anfrage an einen Webserver schickt. Hier gibt es für gewöhnlich eine breite Streuung an möglichen Headern die gesendet und gesetzt werden. Ein Firefox Browser unter Windows sieht schon anders aus, ein Besucher mit Internet Explorer sowieso. Es ist damit noch nichts darüber ausgesagt, was ich mit diesen Informationen anfange oder sie speichere, sie sind aber mein Filterkriterium, denn eben diese breite Streuung, die es unter normalen Besuchern in diesen Headern gibt, seien es Werte von Headern oder die bloße Existenz von bestimmten Headern, gibt es unter Drohnen in der Regel nicht.

Anders als reguläre Besucher mit ihrem Browser, ist es nämlich bei einer DDoS-Drohne nicht wirklich ein Mensch an einem Rechner, der in seinem Browser eine Adresse in der Eingabezeile vom Browser eintippt. Es ist vielmehr ein Skript, ein ausführbares Programm, das dies völlig automatisiert übernimmt. Das ist noch nicht einmal eine besondere Schwierigkeit. Folgende drei Zeilen Perl übernehmen bereits voll funktional und zweckerfüllend diese Aufgabe:

#! /usr/bin/perl
use LWP::Simple;
while (1) { get 'http://foo.com/index.php'; }

Die zugehörige Anfrage sieht so aus:

GET /index.php HTTP/1.0
Host: foo.com
User-Agent: lwp-trivial/1.41

Die nächste wird identisch aussehen. Die übernächste auch. Und die überübernächste. Und die danach. Und die danach …

Wir kommen der Sache also näher, was ich mit Muster meine. Nun ist es nicht immer ganz so einfach wie hier - hier würde es reichen einfach nach dem “User-Agent” zu filtern, aber es zeigt deutlich, worauf ich hinaus will. Eben weil ein DDoS scriptgesteuert ist, gibt es keine große Streuung, es wird immer nach ein und dem selben Muster angefragt. Es gilt also nur dieses Muster zu finden und auszuschließen.

Im einfachsten Fall reicht bereits in Blick in das Zugriffslog. Dort stehen in der Regel bereits wichtige Unterscheidungskriterien für Besucher (Referer, User-Agent und so weiter). Kann man dort keine Regelmäßigkeit ausmachen hilft allerdings nur ein böses Hackerprogramm wie ein Sniffer, mit dem man den Netzwerkverkehr analysieren und ansehen kann. Ich verwende dazu am liebsten Wireshark (früher “Ethereal”), weil die grafische Oberfläche dazu deutlich bequemer ist, wer es archaisch mag, kann sich auch an “tcpdump” direkt auf dem Server versuchen. Das macht allerdings bei starkem Verkehr, der nun einmal für DDoS charakteristisch ist, nicht wirklich Spaß. Ich ziehe diesen Vorgang wie gesagt in bunt vor. Das ist auch gar nicht kompliziert:

apt-get install tshark
cd /tmp
tshark -o dump
<warten>
^C
</warten>

Und dann “dump” vom Server herunterladen und lokal bequem analysieren. Im konkreten Fall hatte ich aber Glück. Ein Blick in das Zugriffslog vom Webserver genügt. Ein kleiner Ausschnitt:

90.48.103.163 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
80.202.121.34 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
81.31.237.17 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
217.215.55.0 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
217.215.55.0 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
217.215.55.0 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
217.215.55.0 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
217.215.55.0 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"
217.215.55.0 - - [12/Mar/2008:18:48:20 +0100] "GET /index.php HTTP/1.1" 369 500 "-" "-"

Das eingestellte Log-Format ist

accesslog.format = "%h %l %u %t \"%r\" %b %>s \"%{Referer}i\" \"%{User-Agent}i\""

Oder mit anderen Worten: der Programmierer der Drohnen war zu faul irgendeinen Referer oder User-Agenten mit zu schicken, diese beiden Felder bleiben konstant leer. Ein ziemlich deutliches Muster, wonach gefiltert werden kann. Es bleibt also nur über dem Lighttpd mitzuteilen, dass Anfragen ohne Referer und User-Agent Header auf die Datei “index.php” böse sind und nicht beachtet werden müssen.

Dazu bietet sich unter Lighttpd das Modul mod_magnet an, das an sich dazu da ist das “Query Handling” zu kontrollieren. Zum Beispiel User-Tracking oder komplexes URL-Rewriting - oder DDoS Abwehr. Denn glücklicherweise erlaubt es mod_magnet völlig frei mittels der Scriptsprache “LUA” Scripte zu schreiben und darüber Informationen über die HTTP-Anfrage zu verarbeiten und entsprechende Lighty-Statuscodes zurück zu geben.

Die Installation von mod_magnet ist nicht ganz einfach, wenn man das Modul selbst kompilieren will. Benutzer von Lighttpd aus der Debian/Ubuntu Distribution können allerdings auch ganz einfach

apt-get install lighttpd-mod-magnet

machen. Wer mod_magnet selbst kompilieren will, benötigt zumindest die Pakete liblua5.1-0, liblua5.1-0-dev, pkg-config und noch einiges mehr. Kompiliert wird Lighty dann zum Beispiel mit “./configure –prefix=/usr/local/lighttpd –with-lua=lua5.1“. Im Detail will ich gar nicht darauf eingehen, ich gehe davon aus, dass jemand der Lighty trotz Paket selbst kompiliert schon wissen wird, was er tut. Glücklicherweise wird es direkt mit dem Lighttpd Quellcode mitgeliefert.

Danach genügt es zwei weitere Zeilen in die lighttpd.conf hinzuzufügen:

server.modules                            += ( "mod_magnet" )
magnet.attract-physical-path-to    = ( "/usr/local/lighttpd/lighty.lua" )

Also schlicht die Aufforderung mod_magnet zu laden und für jede HTTP-Anfrage das Script “/usr/local/lighttpd/lighty.lua” auszuführen. Dieses macht die eigentliche Zauberei. Automatisch zugänglich ist dort das Feld “lighty.env[]” über das die HTTP-Request Header zugänglich sind.
Der Rückgabewert von diesem Script wird als Statuscode von Lighttpd verstanden.

Es bleibt also nicht viel zu tun, außer in dieser ominösen Sprache lua eine Bedingung zu formulieren, die dem obigen Muster entsprechen und als Statuscode 403 (”Forbidden”) zurück geben. Das sieht so aus und ist gleichzeitig das ganze Script:

if (lighty.env["request.uri"] == "/index.php" and lighty.request["User-Agent"] == nil) then
        return 403
end

Da hier tatsächlich eine vollständige Scriptsprache und über lighty.env[] auch tatsächlich alle greifbaren Informationen zur Verfügung stehen, kann man dieses Modul in der Tat ganz gut zur DDoS Abwehr gebrauchen. Funktioniert sogar gut und sehr zufriedenstellend - bis ein hartnäckiger Angreifer sein Muster ändert zumindest.

Einschränkungen

In der Theorie gibt es in der Kombination von mod_magnet zwischen Lighttpd und der Einbindung in den HTTP-Prozess keine Grenzen und eine sehr große Flexibilität. Möglich wäre zum Beispiel auch “böse” Anfragen direkt an einen Paketfilter (iptables) zu übergeben und in der Firewall zu blockieren. In der Praxis gibt es mit Verwendung von mod_magnet aber einige Einschränkungen, zum Beispiel ist das Modul kaum dokumentiert. Es gibt zum Beispiel keine vollständige List von verfügbaren HTTP-Headern und der Benennung in lighty.env[]. Denn alle verfügbaren Header, die man in CGI/PHP-Scripten kennt, sind offensichtlich auch nicht verfügbar (ich suchte verzzweifelt lighty.env["REMOTE-ADDR"] und lighty.env["HTTP-REFERER"] in welcher Schreibweise auch immer …) und traversieren lässt sich dieses Feld gegenwärtig auch nicht. Ebenso ist es wenig erfreulich für jede Anfrage ein weiteres Script ausführen zu müssen, das geht in meinem Anwendungsfall zusätzlich sehr auf den Aufwand eine Anfrage zu bewältigen.

So leidet dieser Versuch der DDoS-Abwehr also noch an einigen Kinderkrankheiten (wie so oft bei Lighttpd), eigentlich schade.

Kategorien

Eingeordnet unter: , ,

Verwandte Artikel

20 Antworten auf »DDoS-Abwehr mit Lighttpd und mod_magnet«

  1. Dieser Artikel interessiert mich nicht!

    Tsafor - 30. März 2008 um 03:01

  2. Blöd, dass ich damit schon ausgesperrt werden würde. Nur weil ich zufällig meinen User-Agent nicht senden mag. Referer sende ich sowieso nicht.

    Wäre eine Filterung nach “Accept: */*” hier möglich?

    anon - 30. März 2008 um 07:56

  3. Der Großteil der Besucher verhält sich nicht wie du - natürlich ist es immer möglich, dass ein Filter nach einem Kriterium auch einige falschen Benutzer trifft (”false positives”). Das ist dann Kollateralschaden und damit kann man in der Situation leben, wenn es lediglich einen geringen Anteil an Besuchern (also dich und alle drei weiteren, die den User-Agent löschen) trifft.

    Wonach du filterst steht dir in der Tat frei, wenn du lieber nach Accept-Header filterst, funktioniert das (in der Theorie) genauso:

    if (lighty.env["request.uri"] == "/index.php" and string.find(lighty.env["Accept"], "*/*") ~= nil) then ...

    Wobei das so in der Tat alle Besucher träfe. Ob der Accept Header aber wirklich über das lighty.env[] Feld verfügbar ist, weiß niemand so genau.

    Arno - 30. März 2008 um 14:13

  4. *ahem* Ich muß Anon mal zur Seite springen: Auch ich sende weder Referer noch User-Agent.

    Kolateralschaden - 31. März 2008 um 19:04

  5. Vorsicht, ich sagte nicht, dass ein Filter auf diese beiden Header pauschal einen Schutz bedeutet - in meinem Fall tat er dies und dann ist der ok. Das ist keine Dauerlösung und auch keine Pauschallösung, die in allen Fällen gilt - aber das sagte ich bereits ausführlicher.

    Arno - 31. März 2008 um 23:47

  6. Also das ist echt klasse, dass Du so einen langen Artikel zu dem Thema schreibst, wirlich Hut ab und ich hoffe, Du bleibst den/m Lighty-Entwickler(n) im Nacken. Und genau deshalb,, weil sich hier einer echt Mühe gegeben hat, will ich mir jetzt auch Mühe geben.

    Das, was Du da schreibst, ist alles sachlich ok und durchaus brauchbar. Allerdings halte ich es wirklich für notwendig, hier einiges klarzustellen. Vor allem deshalb, weil es bei der Idee “DDOS auf dem eigenen Server blocken” ein ganz grundsätzliches Problem gibt: Deine Site bleibt vielleicht erreichbar mit allerlei Notfall-Massnahmen, aber der Traffic, der auf Deinen Server einströmt, ist dennoch vorhanden - und den darfst Du dann bezahlen. DAS ist die eigentliche Katastrophe bei DDOS-Attacken.

    Ich vermute mal, das soll jetzt nicht arrogant klingen, dass Du einen richtigen DDOS noch nicht nicht erlebt hast - das, was Du beschreibst, ist geeignet, um Leute und Robots abzuwehren, die sowas wie “wget -m” machen oder irgendeinen spider auf Diene Site loslassen - aber ein echter harter DDOS ist schon ne Nummer grösser - da strömen dann hunderte GB je Stunde auf Deine Kiste ein - und das KOSTET EIN VERMÖGEN, wenn Du nicht die RICHTIGEN Gegenmassnahen ergreifen kannst.

    Aber diese gegenmassnahmen kannst Du gar nicht ergreifen - das kann nur der Provider - und das beschissene ist, es gibt viele Provider, die können das eben nicht selbst. Was notwenidig ist, ist ein Eingriff an der Border-Routern und am besten gleich an den Core-Routern des europäuischen Backbones, um den Traffic, der sich auf Deine IP richtet, gegen Null zu leiten, ihn also zu verwerfen, und zwar BEVOR er Dich Geld kostet.

    Blöderweise sind die meisten kleinen Provider gar nicht in der Lage, solche Angriffe vorzunehmen - das ist aber das einzige, was hilft.

    Daher besteht die beste Vorsichtsmassnahme darin, sich einen provider zu suchen, der

    1. über entsprechende Infrastruktur verfügt
    2. diese auch bedienen kann (ist nicht immer gegeben)
    3. persönlcih erreichbar ist und schnell reagiert

    Es ist nicht gut, wenn man eine DDOS-gefährdete Site hostet, sich auf einen kleinen VServer-Hoster irgendwo ganz weit unten in der Katte zu verlassen - der kann gar nix anderes tun, als Dir den Traffic in rechnung zu stellen, den er nämlich schon selber bezahlen muss, wenn er bei ihm und bei Dir ankommt. Und bis der reagiert und seinen Upstream kontaktiert hat, kann bei einem grossen DDOS schon ein kleines Vermögen verbraten sein und Du hast KEINE CHANCE, da raus zu kommen, Du musst zahlen.

    Dieses Thema ist leider immer noch völlig unterbewertet, dabei ist es wirklich eine riesige Gefahr und wir müssen das bei den Providern und bei Admins hochbringen - das sind ganz andere Kriterien, die bei sowas die Qualität eines Providers ausmachen - ist er in der Lage, Dich vor dem totalen Ruin zu bewahren, oder nicht?

    Fragt Euren provider mal und bewertet siene Antwort - Ihr werdet Euch wundern, dass viele gar nicht in der Lage sind, das angemessen zu handeln.

    Onkel Willi - 26. April 2008 um 21:29

  7. Also meine Schreibfehler sind echt unerträglich, sorry, den einen muss ich aber inhaltlich klarstellen, sollte natürlich heissen:

    Blöderweise sind die meisten kleinen Provider gar nicht in der Lage, solche EINgriffe vorzunehmen - das ist aber das einzige, was hilft.

    (nicht ANgriffe, sondern EINgriffe).

    Onkel Willi - 26. April 2008 um 21:34

  8. Sollte heissen:

    Blöderweise sind die meisten kleinen Provider gar nicht in der Lage, solche EINngriffe vorzunehmen - das ist aber das einzige, was hilft.

    Onkel Willi - 26. April 2008 um 21:38

  9. EIn Hinweis noch: ein tracert auf die IP Deines Servers kann Dir Hinweise geben auf die Anbindung Deines Providers - es ist generell keine schlechte Idee, das Kriterium “Netzanbindung” bei der Auswahl des Providers recht hoch anzusetzen - an Nummer 1 steht natürlich ganz klar: SERVICE! Also Erreichbarkeit, schnelle Reaktion, hohes Fachwissen. Wenn Du Deine IP oder Dein Netz nicht selber managen kannst oder willst, müssen die Leute, die es tun, die besten sein, die Du bekommen kannst!

    Onkel Willi - 26. April 2008 um 22:59

  10. Einfacher ist es den UA wie folgt zu filtern:

    lighttpd.conf:

    $HTTP["useragent"] =~ “libwww-perl” {
    url.access-deny = ( “” )
    }

    Gefunden auf:
    http://www.cyberciti.biz/tips/the-rise-of-bots-spammers-crack-attacks-and-libwww-perl.html

    Claus - 19. Mai 2008 um 09:29

  11. Mittels Perl kann man, soweit ich das mittlerweile weiß, so ziemlich jeden User-Agent übermitteln. Das dann noch ständig zufallsbedingt zu wechseln, ist auch kein Problem. Habe ich dann noch einen Berg Rechner, auf denen mein Perl-Script läuft und Dir ständig was anderes schickt, was tust Du dann? Ist echt jemand so blöd und wechselt die “Browserinfos” nicht, wenn er einen solchen Angriff ausführt? Jeder, der sowas tut, weiß doch wohl sicher, daß das schlichtweg zu auffällig wäre und schreibt halt ein paar Zeilen mehr ins Script. Das kann ja wirklich jeder Depp. ;)

    Flo - 15. August 2008 um 04:32

  12. Du weißt aber schon, wofür das erste “D” in DDoS steht oder? Ein DoS mit nur einem D langweilt den durchschnittlichen Server eher. Und eben jenes “D” zusätzlich macht einen gewaltigen Unterschied zur Verfügbarkeit von Perl beispielsweise.

    Arno - 15. August 2008 um 18:11

  13. Ja, sicherlich weiß ich das. Also bitte… ;)
    Außerdem schrob ich ja “einen Berg Rechner”. :p

    Ich gehe allerdings davon aus, daß jemand, der einen Haufen Rechner unter seine Kontrolle hat, dort auch so ziemlich alles tun und lassen kann, wie es ihm beliebt. Man muß Perl ja nicht in C:\Perl installieren, sodaß es gleich auffällt.

    Und jetzt stell Dich meiner grandiosen Uralt-Möglichkeit, weil ich wüßte da so auf Anhieb keine Lösung. ;)

    Man kann ja spaßeshalber auch das Verhalten der Anfragen nochmals variabel halten, indem sie nicht immer im gleichen Rythmus von den Angriffsrechnern kommen, indem man zufällige Verzögerungen mit ins Spiel bringt. Dann kommt man mit dem Filtern anhand von Verhalten erst recht ins Schwitzen.

    Flo - 15. August 2008 um 19:10

  14. Du hast vollkommen recht und ein guter (bzw. schlechter - je nach Standpunkt) DDoS-Angriff wird auch genügend Entropie in den Anfragen haben, sodass ein statischer Filter nutzlos ist.

    Meiner Erfahrung nach, ist das jedoch kaum bis nie der Fall. Die allermeisten Angriffe waren zwar wirkungsvoll aber plump und lassen sich relativ einfach filtern. Eine kleine Auswahl:
    -) Stetige Suchanfragen vier zufällig generierten Buchstaben
    -) Anfragen an ein und die selbe Seite
    -) Anfragen mit ein und demselben (User-Agent|Referer|Cookie) etc.
    -) Anfragen mit immer dem selben Klickpfad
    -) Fehler/Bugs im Script der Drohne, die immer die selben Fehler im Log erzeugen

    Du überschätzt die Intelligenz der meisten Angreifer. Überhaupt will ich den Artikel nicht als Allheilmittel verstanden wissen, ich wollte nur exemplarisch (von einem realen DDoS ausgehend) darlegen, wie sich diese beispielsweise filtern lassen.

    Arno - 17. August 2008 um 21:32

  15. Oh, danke Dir für die Antwort.

    Nein, daß Du ein Allheilmittel präsentieren wolltest, so kam das zumindest bei mir auch gar nicht rüber. Ich hab eh nicht alles davon verstanden. Da ich nie mit solchen Angriffen zu tun hatte und mich eben seit kurzer Zeit mit den verdammt tollen Möglichkeiten von Perl beschäftige, dachte ich mir halt, ich frag mal, wenn man schon einen Fachmann “zur Hand” hat.

    Es wundert mich bei Deiner Darstellung aber wirklich, daß man einen Angriff dann derart stümpferhaft ausführt. Gut, wahrscheinlich erreicht er auch so schon meist größtenteils seinen Zweck, aber es wäre derartig einfach, das auch noch zu tarnen, daß es mich wunderte und interessierte.

    Nun gut, dann bin ich soweit auf jeden Fall zufrieden und danke für die Aufmerksamkeit. Einen schönen Tag Dir noch und wenig Ärger mit solcherlei und anderen Problemen wünsche ich mal.

    Flo - 18. August 2008 um 06:17

  16. Ich weiß, wie toll Perl ist. ;)

    Arno - 19. August 2008 um 12:08

  17. Man kann auch einfach ein ulimit setzen
    ulimit -a

    blah - 13. Oktober 2008 um 14:58

  18. Du kannst auch einfach lighttpd ausmachen:

    killall lighttpd

    Arno - 13. Oktober 2008 um 15:39

  19. Grad mit dem Tip Server hochgejagt. Erst Speicher total voll (bash: fork: Cannot allocate memory) und dann hat er sich verabschiedet…
    (

    Alexander - 12. Mai 2010 um 22:30

  20. Nunja, dass der Speicherverbrauch steigt ist logisch, für jeden Request entsteht zusätlicher Overhead durch den Lua-Interpreter (auch wenn das Programm nur einmal tatsächlich geparsed wird).
    Aber fürs fork kann ich hingegen nichts, wie du in meinem Beispiel oben zweifellos siehst, wird da an keiner Stelle eine Shell gespawnt und auch nirgendwo ein externes Programm gestartet. Such lieber an anderer Stelle, wo dein Lighty und/oder Script ein externes Programm startet.

    Arno - 13. Mai 2010 um 14:18

Einen Kommentar schreiben