Firewallscript: Automatische Erkennung und Blockierung von Flooding-Angriffen und Portscans auf (Web)servern
Dieser Artikel ist eine Fortsetzung zu meinem vorherigen Artikel der sich ebenfalls mit Angriffen auf Webserver auseinandergesetzt hat. Der nachfolgende Artikel zeigt auf wie ein Angriff erkannt und blockiert werden kann – und das vollständig ohne kostenpflichtige Tools.
Das Script schützt nicht nur gegen Flooding-Angriffe sondern aufgrund seiner Funktionsweise auch gegen größere Portscans.
Um unsere wichtigen und echten Besucher allerdings nicht zu behindern, führen wir zusätzlich eine Prüfung durch aus welchem Land unsere Besucher tatsächlich kommen.
Demgemäß werden z. B. Angriffe aus Deutschland in den Standardeinstellungen absichtlich nicht blockiert (siehe weiter unten). Im Gegensatz hierzu werden Nutzer aus verdächtigeren Staaten wie z. B. Russland schneller blockiert als Nutzer anderer Staaten.
Schnellstart – Fertiges Firewallscript von lautenbacher.io
Das ist Euch alles zu kompliziert? Ihr könnt das Firewall-Script samt Cronjob auch mit diesem Script installieren oder mich über mein Kontaktformular zu günstigen Stundensätzen buchen.
Das Script zum Installieren importiert zusätzlich eine CIDR Blockliste und aktualisiert diese täglich (Cronjob). Das Firewallscript selbst wird minütlich als Cronjob ausgeführt.
Im Installationsprozess werdet Ihr nach Eurer E-Mail-Adresse gefragt. Die E-Mail-Adresse wird im Script verwendet um Euch automatisch eine Benachrichtigung zu einem Vorfall zu senden (sofern Euer Server zum versenden von E-Mail richtig konfiguriert ist).
Die Logdatei wird per Cronjob am Anfang vom Monat gelöscht.
Ich übernehme selbstverständlich keine Garantie oder Haftung für das nachfolgende Script. Bitte prüft die Dateien vor jedem Download selbst und testet die funktionsweise auf einer Testmaschine bzw. in einer Testumgebung.
Das Script funktioniert neben Debian natürlich auch auf dem Raspberry Pi und neben der Plesk Firewall.
Bei Fehlern oder Problemen könnt Ihr gerne einen Kommentar hinterlassen.
Automatische Installation (Debian)
apt-get update && apt-get install -y wget && wget -O /root/install.sh https://www.lautenbacher.io/firewallscript/install.sh && chmod +x /root/install.sh && /root/install.sh
Tutorial
Es werden die Pakete iptables, netstat und geoip-bin zwingend vorausgesetzt, diese werden installiert mit
apt-get update
apt-get install -y sudo
apt-get install -y geoip-bin
apt-get install -y iptables
apt-get install -y whois
apt-get install -y iptables-persistent
apt-get install -y net-tools #insbesondere auf Raspbian nicht installiert
Unser Testscript test.sh legen wir wie gewohnt per
touch /root/test.sh
touch /root/test.log
touch /root/test.txt
chmod 775 /root/test.log
chmod 775 /root/test.txt
chmod +x /root/test.sh
nano /root/test.sh
an. Das Skript prüft hier hauptsächlich anhand der Ausgabe von netstat die Anzahl der etablierten Verbindungen pro IP-Adresse:
Das Shellskript hat den nachfolgenden Inhalt:
#!/bin/bash
echo Shellscript powered by lautenbacher.io
echo Block more than 200 Connections
netstat -ant | egrep '(:80|:443) .*:.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > test.txt
sed 's/^[ \t]*//' -i test.txt
sed '/^$/d' -i test.txt
while read a b; do
if [[ $a > "200" ]]; then
bGF1dGVuYmFjaGVyLmlv=$(geoiplookup $b | awk -v ip="$b" '{FS=" "} {if($4 != "AT," && $4 != "US," && $4 != "DE,") {print "1";}}')
if [[ $bGF1dGVuYmFjaGVyLmlv = "1" ]]; then
echo checking ip $b
geoiplookup $b
echo add ip $b to iptables blocklist
sudo iptables -I INPUT -s $b -j DROP
#mail -s 'Alert Message regarding '$b [email protected] <<< $b' exceeded the connection limit of 200'
fi
fi
done < test.txt
In diesem Beispiel werden alle IPs mit mehr als 200 Verbindungen, welche nicht aus Deutschland, Österreich oder den Vereinigten Staaten sind automatisch blockiert.
Natürlich lässt sich das auch umdrehen und wir können ein zusätzliches Script erstellen, welches alle Verbindungen aus Russland, Indien und China automatisch blockiert sobald mehr als 10 Verbindungen gleichzeitig bestehen.
Die beiden Skripte lassen sich natürlich auch kombinieren!
#!/bin/bash
echo "Shellscript powered by lautenbacher.io"
#bad countries RU CN IND IDN HKG TH VN UKR BLR VEN - limit 20
netstat -ant | egrep ':.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > testcc.txt
sed 's/^[ \t]*//' -i testcc.txt
sed '/^$/d' -i testcc.txt
while read c d; do
if [[ $c > "20" ]]; then
bGF1dGVuYmFjaGVyLmlv=$(geoiplookup $d | awk -v ip="$d" '{FS=" "} {if($4 == "RU," || $4 == "CN," || $4 == "IND," || $4 == "IDN," || $4 == "HKG," || $4 == "TH," || $4 == "VN," || $4 == "UKR," || $4 == "BLR," || $4 == "VEN,") {print 1}}')
if [[ $bGF1dGVuYmFjaGVyLmlv = "1" ]]; then
echo "running part 4"
bGF1dGVuYmFjaGVyLmlX=$(whois $d)
echo checking ip $d
geoiplookup $d
echo try to add ip $d to blocklist
whoisvar=0
if [[ "$bGF1dGVuYmFjaGVyLmlX" == *"CLOUDFLARE"* ]]; then
whoisvar=1
echo Cloudflare detected
fi
if [[ "$whoisvar" != 1 ]]; then
sudo iptables -I INPUT -s $d -j DROP
whois=$(whois $d)
hostvar=$(hostname)
mail -s 'Warning Message regarding '$d [email protected] <<< $d' bad country host exceeded the connection limit of 20'$whois
echo blocking $d
fi
fi
fi
done < testcc.txt
Mit unseren beiden Shellskripten haben wir unsere Firewall bereits intelligent automatisiert. Es fehlt natürlich noch an der regelmäßigen Ausführung. Hierzu legen wir am einfachsten einen Cronjob mit
crontab -e
an und erweitern die Datei beispielhaft um folgenden Inhalt:
*/1 * * * * /root/test.sh >> /root/test.log 2>&1
In diesem Beispiel wird das Skript innerhalb der Datei test.sh jede Minute ausgeführt. Demnach prüft unser Script ab jetzt jede Minute die Verbindungen auf Auffälligkeiten und blockiert diese.
Als Alternative zum sofortigen blockieren könntet Ihr Euch Angreifer IPs auch einfach per E-Mail senden lassen:
mail -s 'Warning Message regarding '$b [email protected] <<< $b' exceeded the connection limit of 100'
Das ist insbesondere eine gute Idee um die Einstellungen zu testen ohne die IP sofort zu blockieren.
Finale Version – Teil 1: Connection-Flooding Erkennung mit Analyse per Countrycode und whois-Daten
Anbei noch eine umfangreichere kombinierte Version des Scripts, welches auch versucht Cloudflare auszuschließen, jedoch benötigt die whois Abfrage das whois Paket
apt-get install whois
und einiges an Zeit bei der Abfrage. Selbstverständlich können auch andere Netze anhand der whoisdaten von Sperren ausgeschlossen werden.
#!/bin/bash
#powered by lautenbacher.io
#all hosts except DE AT CH US IE CA UK FR ES - limit 75
roundvar1=$(date +"%s")
datevar=$(date)
echo $datevar
echo starting round $roundvar1
echo "running part 1"
netstat -ant | egrep '(:80|:443) .*:.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > test.txt
sed 's/^[ \t]*//' -i test.txt
sed '/^$/d' -i test.txt
while read a b; do
if [[ $a > "75" ]]; then
bGF1dGVuYmFjaGVyLmlvA=$(geoiplookup $b | awk -v ip="$b" '{FS=" "} {if($4 != "AT," && $4 != "US," && $4 != "DE," && $4 != "CH," && $4 != "IE," && $4 != "CA," && $4 != "UK," && $4 != "FR," && $4 != "ES,") {print "1";}}')
bGF1dGVuYmFjaGVyLmlvc=$(geoiplookup $b)
if [[ $bGF1dGVuYmFjaGVyLmlvA = "1" ]]; then
echo "running part 2"
echo checking ip $b
geoiplookup $b
echo try to add ip $b to blocklist
whois=$(whois $b)
whoisvar=0
#echo whoisvar 0
if [[ "$whois" == *"CLOUDFLARE"* ]]; then
whoisvar=1
echo Cloudflare detected
fi
if [[ "$whoisvar" != 1 ]]; then
hostvar=$(hostname)
mail -s 'Warning Message regarding '$b [email protected] <<< $b' exceeded the connection limit of 75'$whois
sudo iptables -I INPUT -s $b -j DROP
echo blocking $b
echo $b/32 >> /root/blockedcidr.txt
fi
fi
fi
done < test.txt
echo "running part 3"
#bad countries RU CN IND IDN HKG TH VN UKR BLR VEN - limit 30
netstat -ant | egrep ':.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > testcc.txt
sed 's/^[ \t]*//' -i testcc.txt
sed '/^$/d' -i testcc.txt
while read c d; do
if [[ $c > "30" ]]; then
bGF1dGVuYmFjaGVyLmlv=$(geoiplookup $d | awk -v ip="$d" '{FS=" "} {if($4 == "RU," || $4 == "CN," || $4 == "IND," || $4 == "IDN," || $4 == "HKG," || $4 == "TH," || $4 == "VN," || $4 == "UKR," || $4 == "BLR," || $4 == "VEN,") {print 1}}')
if [[ $bGF1dGVuYmFjaGVyLmlv = "1" ]]; then
echo "running part 4"
bGF1dGVuYmFjaGVyLmlX=$(whois $d)
echo checking ip $d
geoiplookup $d
echo try to add ip $d to blocklist
whoisvar=0
if [[ "$bGF1dGVuYmFjaGVyLmlX" == *"CLOUDFLARE"* ]]; then
whoisvar=1
echo Cloudflare detected
fi
if [[ "$whoisvar" != 1 ]]; then
whois=$(whois $d)
hostvar=$(hostname)
mail -s 'Warning Message regarding '$d [email protected] <<< $d' bad country host exceeded the connection limit of 30'$whois
echo blocking $d
sudo iptables -I INPUT -s $d -j DROP
echo $d/32 >> /root/blockedcidr.txt
fi
fi
fi
done < testcc.txt
echo finishing $roundvar1
Zur Übersichtlichkeit schreiben wir noch nach jeder Ausführung das aktuelle Datum mit Uhrzeit und die aktiven iptables Regeln in die Logdatei bzw. geben diese aus mit:
rulevar=$(sudo iptables -n --list --line-numbers | sed '/^num\|^$\|^Chain/d' | wc -l)
echo There are $rulevar rules active
Ihr benötigt Hilfe bei Eurem Server? Schreibt mir einfach über mein Kontaktformular.
Finale Version – Teil 2: Import einer CIDR-Blockliste von lautenbacher.io
Hier empfiehlt es sich nicht jede Minute ein Update durchzuführen, sondern nur jeden Tag! Das Script prüft zusätzlich ob bereits eine andere Regel zum CIDR-Block existiert und fügt die Regel nur hinzu wenn keine andere Regel existiert.
0 0 * * * /root/block.sh >> /root/block.log 2>&1
Der Code des Scripts unter /root/block.sh lautet:
#!/bin/bash
wgetb=$(wget -O /root/cidr.txt https://www.lautenbacher.io/firewallscript/cidr.txt)
whois 1.1.1.1
while read a; do
checkvar=$(sudo iptables -S | grep -- $a)
blockit=0
if [[ "$checkvar" == *$a* ]]; then
blockit=1
echo skipping existing rule
fi
if [[ "$blockit" != 1 ]]; then
sudo iptables -I INPUT -s $a -j DROP ;
echo adding rule $a
fi
done < cidr.txt
while read a; do
In der Vergangenheit geblockte IPs landen automatisch in der Datei „/root/blockedcidr.txt“, solltet Ihr diese also automatisch blockieren wollen (z. B. nach einem Neustart) so könntet Ihr die „block.sh“ entsprechend erweitern.
while read b; do
checkvar=$(sudo iptables -S | grep -- $b)
blockit=0
if [[ "$checkvar" == *$b* ]]; then
blockit=1
echo skipping existing rule
fi
if [[ "$blockit" != 1 ]]; then
iptables -I INPUT -s $b -j DROP ;
echo adding rule $b
fi
done < blockedcidr.txt
Anhang – SSH und Telnet Verbindungen in ein CIDR Log schreiben
netstat -ant | egrep '(:22|:23) .*:.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sed 's/^[ \t]*//' | sed '/^$/d' | while read a b; do echo $b/32 >> /root/ssh.txt; done;
Eine Antwort zu “Firewallscript: Automatische Erkennung und Blockierung von Flooding-Angriffen und Portscans auf (Web)servern”
interessanter und hilfreicher beitrag … vielen dank dafür …
einige provider scheinen zwar schon eigene regeln vorgeschaltet zu haben
bei strato allerdings habe ich jeweils über 700 warnmeldungen erhalten bevor die gegenseite offenbar die lust verlor