Member of the official account: Wanger

What is a scapy

Scapy is a powerful interactive packet handler. It can forge or decode packets of various protocols, send online, capture, match requests and responses, etc. It can easily handle most classic tasks such as scanning, tracing routing, probing, unit testing, attack or network discovery, and it can replace some parts of Hping, ARpspoof, ARP-SK, ARping, P0F and even Nmap, tcpdump and Tshark. It also does well at many other specific tasks that other tools can’t handle, such as sending invalid frames, combination techniques (VLAN jump + ARP cache poisoning, VOIP decoding over WEP encrypted channels, etc.)

Install scapy

Just install PIP. I’m using python3

pip3 install scapy
Copy the code

Basic use of SCAPY

You can use ls() to view the protocols supported by SCAPy by typing scapy into the shellUse LSC () to see the supported functions of SCAPyYou can also use ls() to get the parameters contained in the protocol

Sending and receiving packets

send

– Sends packets at layer 3 (Scapy creates layer 2 headers) without receiving any packets.

  • loopThe default parameter is 0, and if it has a value other than 0, packets will be sent in a loop until Ctrl-c is pressed.
  • countCan be used to set the exact number of packets to send.
  • interCan be used to set the number of seconds between each packet.
> > > send (DST = '8.8.8.8') (IP/TCP (dport = 53, flags = 'S')). 1 packets Sent. > > > > > > send (DST = '8.8.8.8') (IP/TCP (dport = 53, flags='S'), count=10) .......... 10 packets Sent. > > > > > > send (IP/TCP (DST = '8.8.8.8') (dport = 53, flags = 'S'), loop = 1)... [... snipped ...]  Sent 1503 packets.Copy the code

sendp

  • Same as send (), but sends packets at layer 2 (the layer 2 header must be supplied) and receives no packets.
  • useifaceSend packets to the Settings screen. (If not set, it will be usedconf.iface The value of the)
> > > sendp (Mr (s)/IP (DST = "2", TTL = (1, 4)), iface = "eth0")... Sent packets. >>> Sendp ("I'm travelling on Ethernet", iface="eth0", loop=1, Intel = 0.2) > > > sendp (rdpcap ("/TMP/pcapfile ") # tcpreplay... Sent 11 packets.Copy the code

sr

  • Send the packet and receive the response.
  • Sr () returns two lists, the first containing those that responded and the second containing those that did not.
>>> sr(IP(DST ="60.205.177.168")/TCP(dport=[21,22,23])) Begin emission: Finished sending 3 packets.... * *... ^C Received 36 packets, got 2 answers, remaining 1 packets (<Results: TCP:2 UDP:0 ICMP:0 Other:0>, <Unanswered: TCP:1 UDP:0 ICMP:0 Other:0>) >>> ANS,unans=_ >>> Unans. summary() IP/TCP 172.17.51.80: ftP_data > 60.205.177.168: Telnet S > > > ans [0] (< IP frag = 0 proto = TCP DST = 60.205.177.168 | < TCP dport = FTP | > >, <IP version=4 IHL =5 tos=0x0 Len =40 ID =53978 FLAGS =DF FRAg =0 TTL =64 proto= TCP chksum= 0x9A1e SRC =60.205.177.168 DST = 172.17.51.80 | < TCP sport = FTP dport = ftp_data seq = 0 ack = 1 dataofs = 5 reserved window = 0 = 0 flags = RA chksum xe1cf = 0 Urgptr | = 0 > >) > > > ans [0] [0] < IP frag = 0 proto = TCP DST = 60.205.177.168 | < TCP dport = FTP | > >Copy the code

sr1

  • Send all packets and log only the first response.
>>> p=sr1(IP(dst="www.baidu.com")/ICMP()/"asdqwe")
Begin emission:
Finished sending 1 packets.
.*
Received 2 packets, got 1 answers, remaining 0 packets
Copy the code

srloop

  • Send in a loop, receive and display the response.
  • This function returns several packets and responses, as well as none.
>>> Packet = IP(DST ='60.205.177.168')/ICMP() >>> SRloop (packet) RECV 1: IP/ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0 RECV 1: IP/ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0 RECV 1: IP/ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0 RECV 1: IP/ICMP 60.205.177.168 > 172.17.51.80 echo-reply 0 ^C Sent 4 packets, received 4 packets. 100.0% hits. TCP:0 UDP:0 ICMP:9 Other:0>, <PacketList: TCP:0 UDP:0 ICMP:0 Other:0>)Copy the code

Create packets using Scapy

  • The creation of Scapy packets is consistent with the hierarchical approach in the network.
  • The basic building blocks of a packet are one layer, while the entire packet is built by stacking the layers on top of each other.
  • Scapy constructs packets by defining data packet headers for each protocol on different layers of TCP/IP and then stacking these layers in sequence.

Create a packet in a row

> > > packet = Mr (S)/IP/TCP (DST = '8.8.8.8') (dport = 53, flags = 'S')Copy the code

Create each layer separately and stack them using the ‘/’ operator

> > > l2 = Mr () > > > l3 = IP (DST = '8.8.8.8/30') > > > l4 = TCP (dport = 53, flags = 'S') > > > packet = l2 / l3 / l4Copy the code

Scapy IP notation

Scapy accepts normal IP representation, CIDR representation, and host name.

> > > IP packet = (DST = '8.8.8.8') > > > IP packet = (DST = 'scanme.nmap.org') > > > IP packet = (DST = '8.8.8.8/30') > > > [for a A packet in] [< IP DST = 8.8.8.8 | >, < IP DST = 8.8.8.9 | >, < IP DST = 8.8.8.10 | >, < IP DST = 8.8.8.11 | >] > > > IP packet = (DST = 'egadz.metasploit.com/30')Copy the code

Create a set of packets

We can use Scapy to create a set of packets

> > > PKTS = IP (TTL = [1,3,5, (7, 10)])/TCP () > > > [PKT for PKT PKTS] in [< IP frag = 0 TTL = 1 proto = TCP | < TCP | > >, <IP frag=0 ttl=3 proto=tcp |<TCP |>>, <IP frag=0 ttl=5 proto=tcp |<TCP |>>, <IP frag=0 ttl=7 proto=tcp |<TCP |>>, <IP frag=0 ttl=8 proto=tcp |<TCP |>>, <IP frag=0 ttl=9 proto=tcp |<TCP |>>, IP frag = 0 < TTL = 10 proto = TCP | < TCP | > >] > > > IP packet = (DST = "192.168. *. 1-10")/TCP (dport = (0100)) > > > [for a packet in a] [< IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 0 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = tcpmux | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = compressnet | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 3 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport | = 4 > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = rje | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 6 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = echo | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 8 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = the discard | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | | < TCP dport = 10 > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = systat | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 12 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = the daytime | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 14 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = netstat | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 16 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = qotd | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = MSP | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = chargen | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = ftp_data | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = FTP | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = SSH | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = Telnet | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = LMTP | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = SMTP | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 26 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = nsw_fe | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 28 | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = msg_icp | > >, < IP frag = 0 proto = TCP DST = 192.168.1.1 | < TCP dport = 30 | > >, .Copy the code

Checking packets

Gets a detailed description of the packet and the data type

>>> packet = IP()/TCP() >>> ls(packet) version : BitField = 4 (4) ihl : BitField = None (None) tos : XByteField = 0 (0) len : ShortField = None (None) id : ShortField = 1 (1) flags : FlagsField = 0 (0) frag : BitField = 0 (0) ttl : ByteField = 64 (64) proto : ByteEnumField = 6 (0) chksum : XShortField = None (None) src : Emph = '127.0.0.1 (None) DST: Emph =' 127.0.0.1 '(' 127.0.0.1) options: PacketListField = [] ([]) / - snipped -Copy the code

show

Display detailed baotou

>>> packet.show() ###[ IP ]### version= 4 ihl= None tos= 0x0 len= None id= 1 flags= frag= 0 ttl= 64 proto= tcp chksum= None SRC = 127.0.0.1 DST = 127.0.0.1 \options\ ###[TCP]### sport= ftp_data dport= HTTP seq= 0 ACK = 0 dataofs= None reserved= 0 flags= S window= 8192 chksum= None urgptr= 0 options= []Copy the code

show2

Similar to show (), but you can assemble packets and calculate checksums and IHL(header length, minimum 5).

>>> packet.show2() ###[ IP ]### version= 4 ihl= 5 tos= 0x0 len= 40 id= 1 flags= frag= 0 ttl= 64 proto= tcp chksum= 0x7CCD SRC = 127.0.0.1 DST = 127.0.0.1 \options\ ###[TCP]### sport= ftp_data dport= HTTP seq= 0 ACK = 0 dataofs= 5 reserved= 0 flags= S window= 8192 chksum= 0x917c urgptr= 0 options= []Copy the code

summary

Displays a short summary of the packet

>>> packet. Summary () 'IP/TCP 127.0.0.1:ftp_data > 127.0.0.1: HTTP S'Copy the code

Interacts with fields inside the packet

> > > Mr (DST = "d8:55: a3: fe: 80-78")/IP (DST = "8.8.8.8") < Mr DST = d8:55: a3: fe: 80-78 type = IPv4 | < IP DST = 8.8.8.8 | > > > > > Packet = _ > > > packet. DST 'd8:55: a3: fe: 80:78' > > > packet [IP]. DST '8.8.8.8'Copy the code

Check whether there are layers in the packet

Haslayer method

>>> if packet.haslayer(IP): ... : print (packet[IP].dst) ... : 8.8.8.8Copy the code

Using the in construct

>>> pkt = IP()/TCP()/DNS()
>>> DNS in pkt
True
Copy the code

The sprintf Scapy

  • sprintf()Methods are one of the most powerful features of Scapy and come in handy when writing custom tools.
  • sprintfThe format string is populated with values from the packet, just like sprintf in the C library, except that the format string is populated with field values from the packet.
>>> packet.sprintf("Ethernet source is %Ether.src% and IP proto is %IP.proto%") 'Ethernet source is 00:16:3e:0c:d1:ad And IP proto is TCP '>>> A.printf ("% DST % % ip.dst % vlan=% dot1q.vlan %") '00:00: D4: AE :3f:71 192.168.0.1 VLAN =42' >>> >>>a.sprintf(" %TCP.flags% | %5s,TCP.flags% | %#05xr,TCP.flags%") ' RA | RA | 0x014'Copy the code

Packet handler

We can use lambda functions to write packet handlers that handle TCP packets, but this functionality only applies to TCP packets.

> > > f = lambda x: x.s printf (" % IP. The DST % : % TCP. The dport % ") > > > f (DST = "8.8.8.8") (IP/TCP () '8.8.8.8: HTTP' > > > F (DST = "8.8.8.8") (IP/UDP () '8.8.8.8:?? 'Copy the code

You can also use the conditional substring in sprintf() for the purpose of processing other layers. The conditional substring is fired only if a layer exists in the packet, otherwise it is ignored. Still can! Used to check for missing layers. Conditional substring format: {[!] Layer: substring}

>>> f=lambda x: x.sprintf("=> {IP:ip=%IP.dst% {UDP:dport=%UDP.dport%}\ ... :... {TCP:%TCP.dport%/%TCP.flags%}{ICMP:type=%r,ICMP.type%}}\ ... :... {! IP: not an IP packet} ") > > > f (IP/TCP () () '= > IP = 127.0.0.1 HTTP/S' > > > f (IP/UDP () () '= = > IP 127.0.0.1 dport = domain' > > > F (IP () ()/ICMP) '= = > IP 127.0.0.1 type = 8' > > > f (Mr)/ARP () '= > not an IP packetCopy the code

Import and export data

PCAP format

Import packets from PCAP files.

pkts = rdpcap("temp.cap")
pkts = sniff(offline="temp.cap")
Copy the code

Export the packet to a PCAP file.

wrpcap("temp.cap",pkts)
Copy the code

Dump format is hexadecimal

  • Scapy allows you to export packets in a variety of hexadecimal formats.
  • Use the hexdump () function to display one or more packets using the hexdump format:
>>> hexdump(s) 0000 D8 55 A3 FE 80 78 00 16 3E 0C D1 AD 08 00 45 00 .U... x.. >... E. 0010 00 28 00 01 00 00 40 06 8B 5E AC 11 33 50 08 08 .(.... @.. ^.. 3P.. 0020 08 08 00 14 00 50 00 00 00 00 00 00 00 00 00 00 50 02..... P........ P. 0030 20 00 A0 0D 00 00Copy the code

A hexadecimal character string

You can also use the STR () function to convert the entire packet to a hexadecimal string

> > > s < Mr DST = d8:55: a3: fe: 80-78 type = IPv4 | < IP frag = 0 proto = TCP DST = 8.8.8.8 | | < TCP dport = HTTP > > > > > > STR WARNING (s) :  Calling str(pkt) on Python 3 makes no sense! "b'\\xd8U\\xa3\\xfe\\x80x\\x00\\x16>\\x0c\\xd1\\xad\\x08\\x00E\\x00\\x00(\\x00\\x01\\x00\\x00@\\x06\\x8b^\\xac\\x113P\\x 08\\x08\\x08\\x08\\x00\\x14 \\x00P\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00P\\x02 \\x00\\xa0\\r\\x00\\x00'"Copy the code

Base64

  • Scapy can export base64 encoded data for packets using the export_object() function.
>>> export_object(s) b'eNprYEouTk4sqNTLSaxMLSrWyzHici3JSC3iKmTQDCpk1EiOT85PSU0u5krNAzG4Cpki7BkYGA7PCD20+PC+Qw0VDGJ2PIcnHlrLweDKwKDBwMjA4MB2qD vu0BpB4wAOIGAQYQhggIIAJgWGQwt4GRgKmSPYgPycxJLMPMNClrZC1qBCNnfHGxoeDcsdkv2AoKSQPUkPALURLMU=' >>> new_pkt = import_objectCopy the code

sniffer

Sniff()

  • Sniff () functionHelps us capture all traffic:
  • Including the count.filter.iface.lfilter.prn.timeoutOptions.
>>> sniff(count=4, iface='eth0')
<Sniffed: TCP:1 UDP:3 ICMP:0 Other:0>
Copy the code

Filters can be added to capture the desired packets, using the standard tcpdump/libpcap syntax:

>>> pkts = sniff(count=1,filter="tcp and host 60.205.177.168 and port 80")
>>> pkts.summary()
Ether / IP / TCP 172.17.51.80:54578 > 60.205.177.168:http S
Copy the code
  • You can do a simple traffic analyzer like tcpdump
>>> PKTS = sniff(count=5,filter="host 60.205.177.168", PRN =lambda x:x.summary()) 60.205.177.168: HTTP S Ether/IP/TCP 60.205.177.168:54624 > 172.17.51.80: HTTP S Ether/IP/TCP 172.17.51.80: HTTP 60.205.177.168:54624 SA Ether/IP/TCP 60.205.177.168: HTTP > 172.17.51.80:54624 SA Ether/IP/TCP 172.17.51.80:54624 A > 60.205.177.168: HTTPCopy the code
  • Packets can also be sniffed from pCAP files.
PKTS = sniff(offline='test.pcap') >>> PKts.nsummary () 0000 Ether/IP/TCP 172.16.16.124:1606 > 74.125.95.104: HTTP S 0001 Ether/IP/TCP 74.125.95.104: HTTP > 172.16.16.128-1606 SA 0002 74.125.95.104: HTTP A 0003 Ether/IP/TCP 172.16.16.124:1606 > 74.125.95.104: HTTP PA/Raw 0004 Ether/IP/TCP 74.125.95.104: HTTP > 172.16.16.124:1606 A/Padding >>> (offline='test.pcap', lfilter = lambda s: S [TCP].flags == 18, PRN = lambda x: x[IP].dst) 192.168.1.1 <Sniffed: TCP:1 UDP:0 ICMP:0 Other:0>Copy the code