赞
踩
本文参考了文章:
弈心:网络工程师的Python之路---Scapy基础篇zhuanlan.zhihu.com根据scapy官方的定义:
Scapy is a Python program that enables the user to send, sniff and dissect and forge network packets. This capability allows construction of tools that can probe, scan or attack networks.
In other words, Scapy is a powerful interactive packet manipulation program. It is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. Scapy can easily handle most classical tasks like scanning, tracerouting, probing, unit tests, attacks or network discovery. It can replace hping, arpspoof, arp-sk, arping, p0f and even some parts of Nmap, tcpdump, and tshark).
大意就是:Scapy是一个强大的,用Python编写的交互式数据包处理程序,它能让用户发送、嗅探、解析,以及伪造网络报文,从而用来侦测、扫描和向网络发动攻击。Scapy可以轻松地处理扫描(scanning)、路由跟踪(tracerouting)、探测(probing)、单元测试(unit tests)、攻击(attacks)和发现网络(network discorvery)之类的传统任务。它可以代替hping
,arpspoof
,arp-sk
,arping
,p0f
甚至是部分的Nmap
,tcpdump
和tshark
的功能。
Scapy实验运行环境和拓扑:
网络环境同前几篇:
几台交换机的管理ip地址为:
用户名: python
密 码: 123
scapy运行在win7或ubuntu上,安装很简单,网上有很多教程。
https://www.cnblogs.com/qingkongwuyun/p/8508733.html
ubuntu下:
win7下:
用ls()函数来查看scapy支持的网络协议, (由于输出内容太长,只截取部分以供参考)。
可以看到网工们耳熟能详的ARP, BOOTP, Dot1Q, DHCP, DNS, GRE, HSRP, ICMP, IP, NTP, RIP, SNMP, STP, PPPoE, TCP, TFTP, UDP等等统统都支持。
除了ls()外,还可以用lsc()函数来查看scapy的指令集(函数)。比较常用的函数包括arpcachepoison(用于arp毒化攻击,也叫arp欺骗攻击),arping(用于构造一个ARP的who-has包) ,send(用于发3层报文),sendp(用于发2层报文), sniff(用于网络嗅探,类似Wireshark和tcpdump), sr(发送+接收3层报文),srp(发送+接收2层报文)等等
这里还可以用使用ls()的携带参数模式,比如ls(IP)来查看IP包的各种默认参数。
实验目的:使用IP()函数构造一个目的地址为192.168.12.101(即拓扑中的PC2)的IP报文,然后用send()函数将该IP报文发送给PC2,在PC2上开启抓包软件以验证是否收到该报文。
a. 首先用IP()函数构造一个目的地址为192.168.12.101的IP报文,将它实例化给ip这个变量。
ip = IP(dst='192.168.192.168.12.101')
b. 用ls(ip)查看该IP报文的内容,可以发现src已经变为192.168.56.1(本机的IP),dst变为了192.168.12.101。 一个最基本的IP报文就构造好了。
ls(ip)
c. 构造好了IP报文(src=192.168.56.1, dst=192.168.12.101)后,我们就可以用send()这个函数来把它发送给PC2了。
为了验证PC2确实接收到了我们发送的报文,在PC2上开启抓包功能。
在scapy上输入 send(ip,iface='VirtualBox Host-Only Network')将该报文发出去,注意后面的iface参数用来指定端口,该参数可选。
抓包结果:
这时可以看到我们已经抓到了从192.168.56.1发来的IP报文,注意Protocol: IPv6 Hop-by-Hop Option (0),这是因为该包的proto位为0, 不代表任何协议。
实验目的:除了send()外,scapy还有个sendp()函数,两者的区别是前者是发送三层报文,后者则是发送二层报文,实验2将演示如何用sendp()来构造二层报文。
a. 用sendp()配合Ether()和arp()函数来构造一个ARP报文,命令如下
sendp(Ether(dst='ff:ff:ff:ff:ff:ff') / ARP(hwsrc = '01:23:45:67:89:01', psrc = '192.168.56.1', hwdst = 'ff:ff:ff:ff:ff:ff', pdst = '192.168.12.101') / 'abc', iface='VirtualBox Host-Only Network')
这里我们构造了一个源MAC地址为01:23:45:67:89:01, 源IP地址为192.168.56.1, 目标MAC地址为ff:ff:ff:ff:ff:ff,目标IP地址为192.168.12.101,payload为abc的ARP报文。
b. 可以另开一个控制台,启用sniff()来抓包,并将抓包的内容实例化到data这个变量上。
>>> data = sniff()
使用show()命令监控本地的收发包情报
>>> data.show()
注意是arp包,所以不能跨网段,需要在56段监听才行:
可以看到该报文ARP部分的内容和ARP报文的结构完全一致
hardware type(HTPYE)为0x0001的时候,表示Ethernet
protocol type(PTPYE)为0x0800的时候,表示IPv4
hardware length (HLEN)为0x06的时候,表示MAC地址长度为6byte
protocol length(PLEN)为0x04的时候,表示IP地址长度为4byte
ARP包有request和response之分,request包的OPER(Opcode)位为0x0001 (也就是这里的who has), response包的OPER位为0x0002。
最后的payload位(padding)即为我们自己定制的内容'abc'。
实验目的:从实验1和实验2的例子可以看出:send()和sendp()函数只能发送报文,不能接收返回的报文。如果要想查看返回的3层报文,需要用到sr()函数,实验3将演示如何使用sr()函数。
a. 用sr()向PC2发一个ICMP包,可以看到返回的结果是一个tuple(元组),该元组里的元素是两个列表,其中一个列表叫Results(响应),另一个叫Unanswered(未响应)。
>>> sr(IP(dst = '192.168.43.1') / ICMP())
这里可以看到192.168.43.1响应了这个ICMP包,所以在Results后面的ICMP:显示1。
b. 如果向一个不存在的IP,比如192.168.43.2发ICMP包,那么这时会看到scapy在找不到该IP的MAC地址(因为目标IP 192.168.43.2和我们的主机192.168.43.1在同一个网段下,这里要触发ARP寻找目标IP对应的MAC地址)的时候,转用广播。当然广播也找不到目标IP,这里可以Ctrl+C强行终止。
sr(IP(dst = '192.168.43.2') / ICMP())
c. 我们可以将sr()函数返回的元组里的两个元素分别赋值给两个变量,第一个变量叫ans,对应Results(响应)这个元素,第二个变量叫unans,对应Unanswered(未响应)这个元素。
ans, unans = sr(IP(dst = '192.168.43.2') / ICMP())
d. 这里还可以进一步用show(), summary(), nsummary()等方法来查看ans的内容,这里可以看到192.168.43.114向192.168.43.1发送了echo-request的ICMP包,192.168.43.1向192.168.43.114回了一个echo-reply的ICMP包。
e. 如果想要查看该ICMP包更多的信息,还可以用ans[0](ans本身是个列表)来查看,因为这里我们只向192.168.2.11发送了一个echo-request包,所以用[0]来查看列表里的第一个元素。
ans[0]
可以看到ans[0]本身又是一个包含了两个元素的元组,我们可以继续用ans[0][0]和ans[0][1]查看这两个元素。
- ans[0][0]
- ans[0][1]
实验目的:实验3讲到了sr(),它是用来接收返回的3层报文。实验4将使用srp()来接收返回的2层报文。
a. 用srp()配合Ether()和ARP()构造一个arp报文,二层目的地址为ff:ff:ff:ff:ff:ff,三层目的地址为192.168.56.0/24, 因为我们是向整个/24网络发送arp, 耗时会很长,所以这里用timeout = 5,表示将整个过程限制在5秒钟之内完成,最后的iface参数前面讲过就不解释了。
ans, unans = srp(Ether(dst = "ff:ff:ff:ff:ff:ff") / ARP(pdst = "192.168.56.0/24"), timeout = 5, iface = "VirtualBox Host-Only Network")
b. 实验环境56段有5台设备,从上图可以看到我们收到了5个answers,符合我们的实验环境,下面用ans.summary()来具体看看到底是哪5个IP响应了我们的'who has'类型的arp报文。
ans.summary()
这里可以看到192.168.56.1, 192.168.56.100, 192.168.56.101, 192.168.56.10, 192.168.56.253响应了我们的'who has'类型的arp报文,并且能看到它们各自对应的MAC地址。
c. 用unans.summary()来查看那些没有回复'who has'类型arp报文的IP地址
unans.summary()
实验目的:使用tcp()函数构造四层报文,理解和应用RandShort(),RandNum()和Fuzz()函数。
a. 实验开始前,首先对外网络接口进行抓包。
b. 在scapy上使用ip()和tcp()函数来构造一个目的地IP为http://www.baidu.com,源端口为30,目的端口为80的TCP SYN报文。
>>> ans, unans = sr(IP(dst = "www.baidu.com") / TCP(sport = 30, dport = 80, flags = "S"))
c. TCP SYN报文发送后,监听网卡的抓包软件上发现了发出的报文
d. 在scapy上输入ans[0]继续验证从主机发出的包,以及远端收到的包。
ans[0]
e. TCP端口号除了手动指定外,还可以使用RandShort(), RandNum()和Fuzz()这几个函数来让scapy帮你自动生成一个随机的端口号,通常可以用作sport(源端口号)。
首先来看RandShort(),RandShort()会在1-65535的范围内随机生成一个TCP端口号,将上面的sport = 30 替换成 sport = RandShort()即可使用。
>>> ans, unans = sr(IP(dst = "www.baidu.com") / TCP(sport = RandShort(), dport = 80, flags = "S"))
这里可以看到RandShort()替我们随机生成了13116这个TCP源端口号
f. 如果你想指定scapy生成端口号的范围,可以使用RandNum(),比如你只想在1000-1500这个范围内生成端口号,可以使用RandNum(1000,1500)来指定,举例如下:
ans, unans = sr(IP(dst = "www.bing.com") / TCP(sport = RandNum(1000,1500), dport = 80, flags = "S"))
这里RandNum()帮我们生成了1246这个源端口号
由于我们指定的范围是1000-1500,很有可能和一些知名的端口号重复,这个时候会出现sport显示的不是端口号,而是具体的网络协议名字的情况。
g. 最后来讲下fuzz()函数,前面的RandShort()和RandNum()都是写在sport后面的(当然也可以写在dport后面用来随机生成目的端口号),用fuzz()的话则可以省略sport这部分,fuzz()会帮你检测到你漏写了sport,然后帮你随机生成一个sport也就是源端口号。
使用fuzz()的命令如下:
ans, unans = sr(IP(dst = "www.163.com") / fuzz(TCP(dport = 80, flags = "S")))
这里看到fuzz()函数已经替我们随机生成了7673这个源端口号
此后的内容为Scapy的实际应用,包括怎么使用Scapy进行TCP的SYN扫描、ACK扫描、FIN扫描、Xmas扫描, Null扫描,怎么使用Scapy执行TCP SYN flooding攻击,ARP欺骗攻击,DHCP饥饿攻击,怎么用Scapy探测rogue DHCP服务器等等。
实验目的:使用TCP SYN扫描交换机L2-1(192.168.11.101)的53(DNS), 80 (HTTP), 23 (FTP)端口,知道如何判断端口是被关闭了(closed)还是被过滤了(filtered),两者各自有什么特征。
实验原理:TCP三次握手的原理和过程相信大家都知道。根据RFC 793,当发送端的TCP SYN包发出后,大致会有下面四种情况发生:
知道实验原理后来看代码:
- #!/usr/bin/env python
- # _*_ coding: utf-8 _*_
- """
- @author: antenna
- @license: (C) Copyright 2019, Antenna.
- @contact: lilyef2000@gmail.com
- @software:
- @file: synscan.py
- @time: 2019/3/30 3:11
- @desc:
- """
- from scapy.all import *
-
- target = 'www.cnblog.com'
-
- ans, unans = sr(IP(dst = target) / TCP(sport = RandShort(), dport = [21, 80, 53], flags = "S"), timeout = 5)
-
- for sent, received in ans:
- if received.haslayer(TCP) and str(received[TCP].flags) == "SA":
- print("Port " + str(sent[TCP].dport) + " of " + target + " is OPEN!")
- elif received.haslayer(TCP) and str(received[TCP].flags) == "RA":
- print("Port " + str(sent[TCP].dport) + " of " + target + " is closed!")
- elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
- print("Port " + str(sent[TCP].dport) + " of " + target + " is filtered!")
-
- for sent in unans:
- print(str(sent[TCP].dport) + " is filtered!")
ans, unans = sr(IP(dst = target) / TCP(sport = RandShort(), dport = [21, 80, 123], flags = "S"), timeout = 5)
- >>> target = 'www.cnblog.com'
- >>> ans, unans = sr(IP(dst = target) / TCP(sport = RandShort(), dport = [21, 80, 53], flags = "S"),
- timeout = 5)
- Begin emission:
- Finished sending 3 packets.
- .....***
- Received 8 packets, got 3 answers, remaining 0 packets
- >>> ans[0][0] # (第一个包里发出的包)
- <IP frag=0 proto=tcp dst=150.129.42.39 |<TCP sport=32179 dport=ftp flags=S |>>
- >>> ans[0][1] # (第一个包里接收到的包)
- <IP version=4 ihl=5 tos=0x0 len=72 id=6115 flags= frag=0 ttl=47 proto=icmp chksum=0xc70f src=150.12
- 9.42.39 dst=192.168.43.114 |<ICMP type=dest-unreach code=host-prohibited chksum=0x1dc6 reserved=0 l
- ength=0 nexthopmtu=0 |<IPerror version=4 ihl=5 tos=0x0 len=44 id=1 flags= frag=0 ttl=46 proto=tcp c
- hksum=0xe008 src=192.168.43.114 dst=150.129.42.39 |<TCPerror sport=32179 dport=ftp seq=0 ack=0 data
- ofs=6 reserved=0 flags=S window=8192 chksum=0xdd48 urgptr=0 options=[('MSS', 536)] |>>>>
- >>>
for sent, received in ans:
- if received.haslayer(TCP) and str(received[TCP].flags) == "SA":
- print("Port " + str(sent[TCP].dport) + " of " + target + " is OPEN!")
- elif received.haslayer(TCP) and str(received[TCP].flags) == "RA":
- print("Port " + str(sent[TCP].dport) + " of " + target + " is closed!")
- elif received.haslayer(ICMP) and str(received[ICMP].type) == "3":
- print("Port " + str(sent[TCP].dport) + " of " + target + " is filtered!")
- for sent in unans:
- print(str(sent[TCP].dport) + " is filtered!")
执行代码看效果:
- antenna@pythonmanager:~$ sudo python3 synscan.py
- Begin emission:
- .Finished sending 3 packets.
- ***
- Received 4 packets, got 3 answers, remaining 0 packets
- Port 21 of www.cnblog.com is OPEN!
- Port 80 of www.cnblog.com is OPEN!
- Port 53 of www.cnblog.com is OPEN!
可以尝试搭建环境,添加acl或防火墙来验证更多的效果。
不说废话,直接上代码:
- import os,sys,time,subprocess
- import warnings,logging
-
- warnings.filterwarnings("ignore", category=DeprecationWarning)
- logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
- from scapy.all import traceroute
- domains = "113.108.238.121 180.96.12.11" # raw_input('Please input one or more IP/domain: ')
- target = domains.split(' ')
- dport = [80]
- if len(target) >= 1 and target[0]!='':
- res,unans = traceroute(target,dport=dport,retry=-2)
- res.graph(target="> test.svg", type="svg")
- time.sleep(1)
- subprocess.Popen(r"C:ImageMagickconvert test.svg test.png", shell=True)
- else:
- print("IP/domain number of errors,exit")
代码说明:
需要下载ImageMagick转换生成的svg格式的路由图到png格式。
代码执行结果:
- Begin emission:
- *********.*******.........*********Finished sending 60 packets.
- *******.Begin emission:
- Finished sending 28 packets.
- Begin emission:
- Finished sending 28 packets.
-
- Received 43 packets, got 32 answers, remaining 26 packets
- 113.108.238.121:tcp80 180.96.12.11:tcp80
- 1 192.168.43.1 11 192.168.43.1 11
- 4 114.247.23.185 11 114.247.23.185 11
- 5 - 221.219.202.213 11
- 6 202.96.12.21 11 202.96.12.5 11
- 7 - 219.158.4.158 11
- 8 219.158.9.38 11 -
- 9 202.97.17.153 11 202.97.88.253 11
- 10 202.97.63.213 11 -
- 11 - 202.102.69.14 11
- 12 - 180.96.35.46 11
- 13 - 180.96.65.162 11
- 14 - 180.96.65.157 11
- 15 - 180.96.65.10 11
- 16 - 180.96.65.9 11
- 17 - 180.96.65.10 11
- 18 - 180.96.65.9 11
- 19 - 180.96.65.10 11
- 20 - 180.96.65.161 11
- 21 - 180.96.65.10 11
- 22 - 180.96.65.157 11
- 23 - 180.96.65.162 11
- 24 - 180.96.65.141 11
- 25 - 180.96.65.162 11
- 26 - 180.96.65.9 11
- 27 - 180.96.65.10 11
- 28 - 180.96.65.157 11
- 29 - 180.96.65.10 11
- 30 - 180.96.65.161 11
-
- Process finished with exit code 0
怎么早没发现scapy还有这功能,太牛了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。