Hand-crafting TCP/IP handshake with Scapy

The following video explains TCP/IP 3-way handshake - and later we are going to hand-craft the packets used in TCP/IP handshake with Scapy.



First lets define the server and the client,

Server : 192.168.2.1
Client : 192.168.2.11

First I will start Scapy at the client side, to track the packets flowing in between client and the server
$ sudo scapy

>>> a=sniff(filter="tcp")
Now lets open up another console in the client end and start Scapy again..
$ sudo scapy
Welcome to Scapy (2.1.0)
>>>
Step - 1

Now, first create an IP packet - you may notice the src is set to the client IP and the dst been set to the server IP.
>>> ip=IP(src="192.168.2.11", dst="192.168.2.1")
Then, we need to create a TCP packet with SYN - see the flags been set to "S". And we are also setting a sequence number...

Step - 2
>>> SYN=TCP(sport=1500, dport=80, flags="S", seq=100)
Then we need to send the crafted packet. With this we are expecting SYN ACK from the server.

Step - 3
>>> SYNACK=sr1(ip/SYN)
But, if you press Ctrl+C and then a.nsummary() on the other console we are running Scapy, you will see an RST been sent from the client after the SYN.
$ sudo scapy
>>> a=sniff(filter="tcp")
Ctrl+C
>>>a.nsummary()
0000 Ether / IP / TCP 192.168.2.11:1500 > 192.168.2.1:www S
0001 Ether / IP / TCP 192.168.2.11:1500 > 192.168.2.1:www R
Linux kernel automatically sets appropriate header values and knows how to complete a TCP 3 way handshake.

Scapy does not use these kernel services. It creates a raw socket.

In the previous case, as soon as the kernel sees the SYN/ACK it responded with a RST - because it did not send the SYN [it was through Scapy].

So, we need to avoid this behavior and this is how we do it. We can use iptables on our host to suppress outbound RSTs to the destination we are working with.

sudo iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.2.11 -dport 1500 -j DROP

Once the above done performs steps 1 to 3 and you won't see an RST been sent from the client.

Step - 4

Now the client needs to send ACK for the server's SYN.

Here you will see the sequence number is increased by one and the the sequence number from the SYN ACK form the server been set as the ack.
>>> ACK=TCP(sport=1500, dport=80, flags="S", seq=101 ack=SYNACK.seq)
Step - 5

Send the client ACK to the server
>>>send(ip/ACK)
Step - 6

Let's go back to the first console window and view the flow between client and the server
$ sudo scapy
>>> a=sniff(filter="tcp")
Ctrl+C
>>>a.nsummary()
0000 Ether / IP / TCP 192.168.2.11:1500 > 192.168.2.1:www S
0001 Ether / IP / TCP 192.168.2.1:www > 192.168.2.11:1500 SA
0002 Ether / IP / TCP 192.168.2.11:1500 > 192.168.2.1:www A