SYN-Flood - Der Kampf gegen das Böse
SYN-Flood - Der Kampf gegen das Böse
Das Wesen eines SYN-Flood-Angriffs (Angriff mit halboffenen Verbindungen) besteht in der gezielten Erschöpfung der Netzwerkressourcen eines Servers durch den Missbrauch des Standardmechanismus für den Verbindungsaufbau im TCP-Protokoll (Three-Way-Handshake).
Wie eine legitime Verbindung funktioniert:
- SYN: Der Client sendet ein Paket mit dem SYN-Flag an den Server und fordert damit den Aufbau einer Verbindung an.
- SYN-ACK: Der Server empfängt eine Anfrage, reserviert im Arbeitsspeicher Platz in einer speziellen Warteschlange (SYN-Backlog), versetzt den Socket in den Zustand SYN-RECV (SYN empfangen) und sendet ein SYN-ACK-Antwortpaket an den Client.
- ACK: Der Client erhält die Bestätigung und sendet das abschließende ACK. Danach wechselt die Verbindung in den Status ESTABLISHED, und es wird ein vollwertiger Arbeitssocket für die Datenübertragung bereitgestellt.
Wozu das führt:
- Überlastung der Kernel-Tabelle: Sockets bleiben im Zwischenzustand SYN-RECV hängen.
- Warteschlangenüberlauf (Backlog): Die für unvollständige Handshakes vorgesehene Warteschlange (tcp_max_syn_backlog) füllt sich rasch bis zur Kapazitätsgrenze.
- Denial of Service (DoS): Wenn die Warteschlange überlastet ist, beginnt der Linux-Kernel einfach damit, neue eingehende Anfragen zu verwerfen. Infolgedessen können legitime Nutzer die Website nicht aufrufen, da der Server physisch nicht in der Lage ist, die Flut gefälschter Verbindungsaufbauversuche (Handshakes) zu bewältigen.
Tatsächliche Leben
Es ist Abend, du hast gerade eine Flasche Bier geöffnet, und plötzlich klingelt das Telefon: „Was soll ich tun? Die Website ist ständig nicht erreichbar – alle fünf Minuten!“ – genau hier beginnt der Kampf gegen das Böse!
uptime && free -h
ss -ant state syn-recv '( sport = :80 or sport = :443 )' | wc -l
3743 - Stimmung ist sofort ruiniert (((
1. Beginn des Kampfes
In aller Ruhe ein Bierchen genießen und eine Zigarette rauchen.
2. Überprüfung des Waffenzustands
iptables -L INPUT -v -n
cat /etc/sysctl.conf
Völlig unbewaffnet
3. Wir beginnen uns zu bewaffnen.
Verhindert einen Serverabsturz.
sysctl -w net.ipv4.tcp_syncookies=1
echo "net.ipv4.tcp_syncookies = 1" | tee -a /etc/sysctl.conf
sysctl -p
4. Wie man es benutzt
Um diese Flut dauerhaft auf Kernebene zu unterbinden, noch bevor sie halb offene Sockets erzeugt, muss das Modul `hashlimit` verwendet werden. Es ermöglicht die Begrenzung der Anzahl eingehender Verbindungen pro einzelner externer IP-Adresse, anstatt den gesamten Datenverkehr als Ganzes zu beschränken.
iptables -A INPUT -p tcp --syn -m hashlimit --hashlimit-above 3/sec --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name syn_flood -j DROP
netfilter-persistent save
Wenn ein Bot oder Scanner von seiner IP-Adresse aus häufiger als dreimal pro Sekunde Anfragen sendet, werden alle nachfolgenden SYN-Pakete sofort verworfen (DROP) – und zwar bereits auf Netzwerkebene, noch bevor es zur Erstellung eines SYN_RECV-Zustands kommt.
5. Mal sehen, wie es geworden ist
Höchstwahrscheinlich sind noch einige Vorab-Eröffnete Sockets übrig.
netstat aux
Hier haben wir zwei Möglichkeiten.
5.1 Mal sehen, wie es geworden ist
Sie mit den Händen schließen
iptables -L INPUT --line-numbers -v
iptables -I INPUT 1 -p tcp --syn -s x.x.x.0/24 -j DROP
iptables -I INPUT 2 -p tcp --syn -s y.y.y.0/24 -j DROP
5.2 Mal automatisieren
Wir werden gezielt Subnetze blockieren, da gefälschte IP-Adressen verwendet werden und kein vollständiger Verbindungsaufbau vorgesehen ist.
apt install ipset
cat << 'EOF' > /usr/local/bin/block-guard.sh
#!/bin/bash
IPSET_NAME="blocked_ips"
TEMP_SET="temp_$IPSET_NAME"
IP_FILE="/etc/iptables/blacklisted_ips.txt"
SERVER_IP="xxx.xxx.xxx.xxx"
mkdir -p "$(dirname "$IP_FILE")"
touch "$IP_FILE"
echo "[*] Wir erfassen SYN-RECV-Verbindungen..."
ATTACKERS=$(ss -H -ant state syn-recv 2>/dev/null | awk '{print $4}' | cut -d: -f1 | grep -vE "^(127\.|10\.|192\.168\.|${SERVER_IP})" | sed -E 's/[0-9]+$/0\/24/' | sort -u)
if [ -n "$ATTACKERS" ]; then
for subnet in $ATTACKERS; do
if ! grep -qxF "$subnet" "$IP_FILE"; then
echo "[+] Hinzufügen eines Subnetzes: $subnet"
echo "$subnet" >> "$IP_FILE"
fi
done
fi
echo "[*] Wir aktualisieren ipset..."
ipset create "$TEMP_SET" hash:net -exist
ipset flush "$TEMP_SET"
if [ -f "$IP_FILE" ]; then
while read -r entry; do
[[ -z "$entry" || "$entry" =~ ^# ]] && continue
if [[ "$entry" =~ [a-zA-Z] ]]; then
resolved_ip=$(getent hosts "$entry" | awk '{print $1}' | head -n 1)
if [ -n "$resolved_ip" ]; then
echo "[+] Auflösen der Domain $entry -> $resolved_ip"
ipset add "$TEMP_SET" "$resolved_ip" 2>/dev/null
else
echo "[-] Domain konnte nicht aufgelöst werden: $entry"
fi
else
ipset add "$TEMP_SET" "$entry" 2>/dev/null
fi
done < "$IP_FILE"
fi
ipset create "$IPSET_NAME" hash:net -exist
ipset swap "$TEMP_SET" "$IPSET_NAME"
ipset destroy "$TEMP_SET"
if ! iptables -C INPUT -m set --match-set "$IPSET_NAME" src -j DROP 2>/dev/null; then
echo "[+] Добавляем правило в iptables"
iptables -I INPUT 1 -m set --match-set "$IPSET_NAME" src -j DROP
fi
echo "[✓] Готово. Элементов в сетке: $(ipset list $IPSET_NAME | grep -c '^[0-9]')"
EOF
chmod +x /usr/local/bin/block-guard.sh
/usr/local/bin/block-guard.sh
# iptables -v -L INPUT -n --line-numbers | head -n 5
# Wir müssen dafür sorgen, dass unsere Regel an erster Stelle steht!!!
# Wenn hier an der ersten Stelle schon etwas steht, verschieben wir es manuell.: iptables -I INPUT 1 -m set --match-set blocked_ips src -j DROP
cat /etc/iptables/blacklisted_ips.txt
ipset list blocked_ips
crontab -e
@reboot /usr/local/bin/block-guard.sh
*/5 * * * * /usr/local/bin/block-guard.sh >/dev/null 2>&1
6. Wir genießen den Abend weiter.
netstat aux
Wir sehen dort nur: ESTABLISHED
Und dann machen wir uns endlich noch ein Bier auf und schalten den Computer aus.