SoFunction
Updated on 2024-11-14

Python Scapy studies the TCP stack as it goes along

1. Preamble

If I only need to study the behavior of Linux's tcp stack, I can satisfy all my needs by just using packetdrill. packetdrill is the one that lets me tease the tcp stack to my heart's content.Simple manual for packetdrill

The tragedy, however, is that in addition to studying the behavior of the TCP stack for Linux, you also need to study the behavior of the tcp stack for Windows, which is not open source and feels like it should have quite a few unknown potholes in it.

In order to be able to reproduce some of the network behavior of the Windows tcp stack, here the use of python's scapy packet construction to tease the Windows tcp stack. scapy in the tcp data message injection will have a little bit of delay, this tool in the requirements of the strict latency of the scenario can not be used (or packetdrill is good to use, awkward). For the current scenarios encountered, can barely be used, and then have been accustomed to jacking python, it is relatively easy to get started.

2. Basic grammar

  • Installing scapy

Use yum install to install it directly on Centos 7.2.

yum install  
  • help solves most of the problems.
[root@localhost ~]# scapy
INFO: Can't import python gnuplot wrapper . Won't be able to plot.
INFO: Can't import PyX. Won't be able to use psdump() or pdfdump().
WARNING: No route found for IPv6 destination :: (no default route?)
Welcome to Scapy (2.2.0)
>>> help(send)

Most of the time, if you see something you don't understand, please use help. followed by the official reference manuals

  • basic grammar

ip/tcp/http packet manipulation

>>> IP()
<IP |>
>>>> IP()/TCP()
<IP frag=0 proto=tcp |<TCP |>>
>>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP >> 
>>>> Ether()/IP()/TCP()
<Ether type=IPv4 |<IP frag=0 proto=tcp |<TCP |>>>
>>>> IP()/TCP()/"GET /HTTP/1.0\r\n\r\n"   The data part can be used directly as a string
<IP frag=0 proto=tcp |<TCP |<Raw load='GET /HTTP/1.0\r\n\r\n' |>>> 
>>>> Ether()/IP()/UDP()
<Ether type=IPv4 |<IP frag=0 proto=udp |<UDP |>>>
>>>> Ether()/IP()/IP()/UDP()
<Ether type=IPv4 |<IP frag=0 proto=ipencap |<IP frag=0 proto=udp |<UDP |>>>>
>>> str(IP())
'E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x01'
>>> IP(_)
<IP version=4L ihl=5L tos=0x0 len=20 id=1 flags= frag=0L ttl=64 proto=hopopt 
chksum=0x7ce7 src=127.0.0.1 dst=127.0.0.1 |>
>>> a=Ether()/IP(dst="")/TCP()/"GET / HTTP/1.0 \n\n"
>>> hexdump(a)
0000  00 03 0F 19 6A 49 08 00 27 FE D8 12 08 00 45 00  ....jI..'.....E.
0010  00 43 00 01 00 00 40 06 70 78 C0 A8 73 C6 B4 61  .C....@.px..s..a
0020  21 6C 00 14 00 50 00 00 00 00 00 00 00 00 50 02  !l...P........P.
0030  20 00 B3 75 00 00 47 45 54 20 2F 69 6E 64 65 78  ..u..GET /index
0040  2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A  .html HTTP/1.0 .
0050  0A                         .
>>> b=str(a)
>>> b
"\x00\x03\x0f\x19jI\x08\x00'\xfe\xd8\x12\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06px
\xc0\xa8s\xc6\xb4a!l\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xb3u
\x00\x00GET / HTTP/1.0 \n\n"

1. Packet sending

The sending of packets mainly consists of the following functions send/sendp/sr/sr1/srp The main differences are:

The send function works at the third level

send(IP(dst="192.168.115.188")/ICMP())

The sendp function works at layer 2, where you can select the NIC and protocol

sendp(Ether()/IP(dst="192.168.115.188",ttl=(1,4)),iface="eth0")

The role of the fuzz function: you can change some of the default value can not be calculated (such as checksums and checksums), change the value is random, but the type is consistent with the value of the field.

send(IP(dst="")/UDP()/NTP(version=4),loop=2) # fuzz() not used
send(IP(dst=" ")/fuzz(UDP()/NTP(version=4)),loop=2) #utilizationfuzz() 

The SR() function is used to send packets and receive responses. This function returns the packets with and without responses; this function is also considered the core of scapy, and it returns two lists of data, an answer list and an unanswered list.

>>> sr(IP(dst="192.168.115.1")/TCP(dport=[21,22,23]))
Begin emission:
Finished to send 3 packets.
***
Received 3 packets, got 3 answers, remaining 0 packets
Results: TCP:3 UDP:0 ICMP:0 Other:0>, Unanswered: TCP:0 UDP:0 ICMP:0 Other:0
>>> ans,unans=_  It's alsoscapyIt's at the heart of the
>>> ()
0000 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ftp S ==> IP / TCP 192.168.115.1:ftp > 192.168.115.198:ftp_data RA / Padding
0001 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:ssh S ==> IP / TCP 192.168.115.1:ssh > 192.168.115.198:ftp_data RA / Padding
0002 IP / TCP 192.168.115.198:ftp_data > 192.168.115.1:telnet S ==> IP / TCP 192.168.115.1:telnet > 192.168.115.198:ftp_data SA / Padding 
>>>sr(IP(dst="192.168.115.1")/TCP(dport=[21,22,23]),inter=0.5,retry=-2,timeout=1) When the network environment is bad,You can also addinter retry timeoutand other additional information,

The function sr1() is a variant of sr() that returns only the packet (or set of packets) sent in response. The packets sent by these two functions must be Layer 3 packets (IP, ARP, etc.). The function SRP(), on the other hand, is located at layer 2 (Ethernet, 802.3, etc.).

>>> p=sr1(IP(dst="192.168.115.188")/ICMP()/"test")
Begin emission:
.....Finished to send 1 packets.
.*
Received 7 packets, got 1 answers, remaining 0 packets
>>> p
<IP version=4L ihl=5L tos=0x0 len=32 id=26000 flags= frag=0L ttl=128 proto=icmp chksum=0x6c79 src=192.168.115.188 dst=192.168.115.198 options=[] |<ICMP type=echo-reply code=0 chksum=0x1826 id=0x0 seq=0x0 |<Raw load='test' |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>>
>>> ()
###[ IP ]###
 version= 4L
 ihl= 5L
 tos= 0x0
 len= 32
 id= 26000
 flags= 
 frag= 0L
 ttl= 128
 proto= icmp
 chksum= 0x6c79
 src= 192.168.115.188
 dst= 192.168.115.198
 \options\
###[ ICMP ]###
   type= echo-reply
   code= 0
   chksum= 0x1826
   id= 0x0
   seq= 0x0
###[ Raw ]###
    load= 'test'
###[ Padding ]###
      load= '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

1. Packet sniff

a=sniff(count=1,filter="tcp and host 192.168.1.1 and port 80")

The use of sniff is mainly used for packet reception, according to the conditions set by the filter, the packet that meets the conditions will be received back.

3. Scene construction

The disadvantage of scapy is that he is only responsible for constructing packets, which is one-way. Unlike packetdrill which is so perfect, packetdrill not only constructs packets, but also implements system calls to construct different scenarios, and also helps you check whether the packets sent out by the stack meet expectations. The process of ruffling the tcp stack is not limited to two ends, one end of the system call to simulate the behavior of the stack, and the other end is the packet we construct. Common scenarios are mainly: server scenarios, client scenarios.

  • Server Scene:

The server scenario uses system calls (i.e., userland programs), while the client is a package constructed by scapy.

Construct a simple three times handshake here after sending data to the server side. To prevent Linux client rst.

iptables -A OUTPUT -p tcp --tcp-flags RST RST -s 192.168.56.1 -j DROP
#!/usr/local/bin/python
from  import *
# VARIABLES
src = [1]
dst = [2]
sport = (1024,65535)
dport = int([3])
# SYN
ip=IP(src=src,dst=dst)
SYN=TCP(sport=sport,dport=dport,flags='S',seq=1000)
SYNACK=sr1(ip/SYN)
# ACK
ACK=TCP(sport=sport, dport=dport, flags='A', seq=, ack= + 1)
send(ip/ACK)

Here you can install a nginx to verify.

  • Client Scenario:

The client-side scenario uses system calls (i.e., user-state programs), while the server-side is a scapy constructor package.

A simple http server is constructed here using scapy. To prevent the stack from sending RSTs, iptables needs to be set up.

iptables -A OUTPUT -p tcp --tcp-flags RST RST --sport 80 -j DROP
#!/usr/bin/python
from  import *
# Interacts with a client by going through the three-way handshake.
# Shuts down the connection immediately after the connection has been established.
# Akaljed Dec 2010, 
# Wait for client to connect.
a=sniff(count=1,filter="tcp and host 192.168.1.1 and port 80")
# some variables for later use.
ValueOfPort=a[0].sport
SeqNr=a[0].seq
AckNr=a[0].seq+1
# Generating the IP layer:
ip=IP(src="192.168.1.1", dst="192.168.1.2")
# Generating TCP layer:
TCP_SYNACK=TCP(sport=80, dport=ValueOfPort, flags="SA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)])
#send SYNACK to remote host AND receive ACK.
ANSWER=sr1(ip/TCP_SYNACK)
# Capture next TCP packets with dport 80. (contains http GET request)
GEThttp = sniff(filter="tcp and port 80",count=1,prn=lambda x:("{IP:%%: %%}"))
AckNr=AckNr+len(GEThttp[0].load)
SeqNr=a[0].seq+1
# Print the GET request
# (Sanity check: size of data should be greater than 1.)
if len(GEThttp[0].load)>1: print GEThttp[0].load
# Generate custom http file content.
html1="HTTP/1.1 200 OK\x0d\x0aDate: Wed, 29 Sep 2010 20:19:05 GMT\x0d\x0aServer: Testserver\x0d\x0aConnection: Keep-Alive\x0d\x0aContent-Type: text/html; charset=UTF-8\x0d\x0aContent-Length: 291\x0d\x0a\x0d\x0a<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\"><html><head><title>Testserver</title></head><body bgcolor=\"black\" text=\"white\" link=\"blue\" vlink=\"purple\" alink=\"red\"><p><font face=\"Courier\" color=\"blue\">-Welcome to test server-------------------------------</font></p></body></html>"
# Generate TCP data
data1=TCP(sport=80, dport=ValueOfPort, flags="PA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)])
# Construct whole network packet, send it and fetch the returning ack.
ackdata1=sr1(ip/data1/html1)
# Store new sequence number.
SeqNr=
# Generate RST-ACK packet
Bye=TCP(sport=80, dport=ValueOfPort, flags="FA", seq=SeqNr, ack=AckNr, options=[('MSS', 1460)])
send(ip/Bye)
# The End

This server only needs to use wget or curl for authentication.

4. References

/projects/scapy/doc/#starting-scapy

/2010/12/12/scapy-as-webserver/

/2012/12/

summarize

Above is the entire content of this article, I hope the content of this article for your study or work has a certain reference learning value, thank you for your support. If you want to know more about the content please check the following related links