Search code examples
pythonlinuxnetwork-programmingtcpscapy

TCP/IP connection with scapy


I'm trying to implement a little netcat-like utility using scapy (where i can do low-level modifications to the IP packets), but I am unable to initiate a proper connection.

I tried to create a simple test-program that connects to a remote host and sends some string over:

#!/usr/bin/env python3
import random
import sys
from scapy.all import *

dst = sys.argv[1]
sport = random.randint(1024, 65535)
dport = int(sys.argv[2])
data = 'hello\r\n'

ip = IP(dst=dst, frag=0)
SYN = TCP(sport=sport, dport=dport, flags='S', seq=1000)
SYNACK = sr1(ip/SYN)
ACK = TCP(sport=sport, dport=dport, flags='A', seq=SYNACK.ack, ack=SYNACK.seq + 1)
INITACK = sr1(ip/ACK)
PUSHACK = TCP(sport=sport, dport=dport, flags='PA', seq=INITACK.ack, ack=INITACK.seq + 1)
RESPONSE = sr1(ip/PUSHACK/Raw(load=data))

On the receiving side i have a nc -l -p 6666 running.

When I invoke the script, i get the following output on the sender:

$ sudo ./test.py REMOTE 6666
Begin emission:
Finished sending 1 packets.
.......*
Received 8 packets, got 1 answers, remaining 0 packets
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets

But the receiving netcat never outputs any data (I did check whether I can send data to the remote with echo foo | nc REMOTE 6666, and it does work nicely).

When running a tcpdump on the receiver, I can see the following output:

23:31:58.205257 IP SENDER.4902 > RECEIVER.6666: Flags [S], seq 1000, win 8192, options [mss 536], length 0
23:31:58.205279 IP RECEIVER.6666 > SENDER.4902: Flags [S.], seq 1928493439, ack 1001, win 29200, options [mss 1460], length 0
23:31:58.344181 IP SENDER.4902 > RECEIVER.6666: Flags [R], seq 1001, win 0, length 0
23:31:58.396581 IP SENDER.4902 > RECEIVER.6666: Flags [.], ack 1, win 8192, length 0
23:31:58.396593 IP RECEIVER.6666 > SENDER.4902: Flags [R], seq 1928493440, win 0, length 0
23:31:58.459286 IP SENDER.4902 > RECEIVER.6666: Flags [P.], seq 4294966296:4294966303, ack 2, win 8192, length 7
23:31:58.459296 IP RECEIVER.6666 > SENDER.4902: Flags [R], seq 1928493441, win 0, length 0

So: what am I doing wrong`


Solution

  • Your kernel is closing the connection when it receives a SYN/ACK from your TCP partner. if you are under linux, you can use IP table to inform the kernel that you do not wish that behaviour. Beware of the security concern if you do that.

    the iptable command is the folowing:

    iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP
    iptables -L
    

    your code also needs a small change.

    
    #!/usr/bin/env python3
    import random
    import sys
    from scapy.all import *
    
    dst = sys.argv[1]
    sport = random.randint(1024, 65535)
    dport = int(sys.argv[2])
    data = 'hello\r\n'
    
    ip = IP(dst=dst, frag=0)
    SYN = TCP(sport=sport, dport=dport, flags='S', seq=1000)
    SYNACK = sr1(ip/SYN)
    ACK = TCP(sport=sport, dport=dport, flags='A', seq=SYNACK.ack, ack=SYNACK.seq + 1)
    send(ip/ACK)
    # at this point, you and your partner are on established state.
    
    
    # you can then start to send things
    cur_seq=SYNACK.ack
    cur_ack=SYNACK.seq + 1
    
    
    PUSHACK = TCP(sport=sport, dport=dport, flags='PA', seq=cur_seq, ack=cur_ack)
    cur_seq += len(data)
    RESPONSE = sr1(ip/PUSHACK/Raw(load=data))