Python3+Scapy安装使用教程

一、说明

之前写DoS程序的时候(见"拒绝服务(DoS)理解、防御与实现"),数据包完全是自己构造的,这其中的难处一是要清楚各层协议的字段、字段长度、字段是数值还是字符、大头还是小头,二是计算校验和。整个过程比较痛苦。

其实构造DoS数据包,我们经常只是想伪造一下源IP等少数字段,而事实上大量时间花在其他大多数不想关心的字段的构造上。

在查找资料过程中发现很多DoS程序直接使用一个“Scapy”的包(开始还以为是Scrapy心想Scrapy什么时候可以用来构造数据包了,后来才注意到少了个“r”)。当时没太在意,现在回头看Scapy确实堪称“神器”,值得记录一番。

本文主要参考官方文档,更多用法也请见:https://scapy.readthedocs.io/en/latest/usage.html

 

二、安装

直接使用pip安装:

pip install scapy

一些扩展功能安装,可选:

pip install matplotlib pyx cryptography

 

三、生成数据包

3.1 启动scapy交互shell

切换到Python的Scripts文件夹下,直接使用scapy命令启动(本质是scapy.bat):

scapy

启动界面如下图(由于我没装PyX所以提示不能使用psdump()和pdfdump(),另外还有一些告警,都无关紧要就不处理了):

 

3.2 生成数据包

在scapy中,应用层之下的数据包,基本使用协议大写对应的方法就可以直接生成。如:

# 使用Ether()方法生成一个以太网层数据包
eth_packet = Ether()
# 使用IP()方法生成一个网络层数据包
ip_packet = IP()
# 使用TCP()方法生成一个tcp数据包
tcp_packet = TCP()
# 使用UDP()方法生成一个udp数据包
udp_packet = UDP()
# 使用ICMP()方法生成一个udp数据包
icmp_packet = ICMP()

 

3.3 查看数据包内容

上一小节中生成数据包,如果就长这样的话完全就是一个黑盒,我们需要一些方法来知道数据包(各字段)是什么内容。

哪个协议的数据包查看都是类似的,我们这里以一个tcp数据包为例,查看其他协议的数据包类似操作即可。

# 使用IP()方法生成一个tcp数据包
ip_packet = IP()

# 方法一、使用raw()方法查看
raw(ip_packet)

# 方法二、使用hexdump()查看。类似Wireshark
hexdump(ip_packet)

# 方法三、raw()配合协议类查看。最佳
# 查看该数据包以太网层内容(下层内容不层示,上层内容不解析只以load形式展示)
Ether(raw(ip_packet))
# 查看该数据包网络层内容(下层内容不层示,上层内容不解析只以load形式展示)
IP(raw(ip_packet))

 

3.4 自定义字段值

上一小节中我们使用raw配合协议方法的方式清楚地看到了数据包中各字段的值,这些值是根据本机信息自动生成的,我们来看如何自定义各字段的值。

定义字段的值有两个种方法,一种是在构造时直接传递参数,另一种是在生成后重新赋值;至于参数名即是上一小节中打出的那些项。

以修改源IP地址和TTL为例,在上一小节中可以看到默认生成的源IP地址叫“src”值为“10.10.6.91”(这是我本机当前的IP地址),TTL叫ttl默认值64。

# 方法一,在构造时直接传递参数
# 给src传值10.10.6.92,ttl传值128;字段为字符的以字符串形式传,字段为数值的以数值形式传
ip_packet = IP(src="10.10.6.92",ttl=128)
# 查看数据包各项值,确认src项是否为10.10.6.92,ttl项是否为128
IP(raw(ip_packet))

# 方法二,在生成后重新赋值
# 给src赋值10.10.6.92,ttl赋值128;字段为字符的以字符串形式赋,字段为数值的以数值形式赋
ip_packet.src = "10.10.6.93"
ip_packet.ttl = 200
# 查看数据包各项值,确认src项是否为10.10.6.93,ttl项是否为200
IP(raw(ip_packet))

 

3.5 同时自定义多层协议的字段

在上一小节中我们自定义了源IP地址,但有一个问题:如果此时我想自定义源MAC地址该如何操作呢。想在构造时直接传递参数使用的是IP()又不是Ether();想在生成后重新赋值,上一小节已试验过了src改的是源ip,源mac没法通过src项改。

构造多层协议,构造函数可使用“/”隔开,低层函数在前高层函数在后;最后使用构造函数中的最低层函数即可查看数据包内容。

# 构造一个IP数据包,源mac设置为"00:00:00:00:00:11",源ip设置为"10.10.6.92"
ip_packet = Ether(src="00:00:00:00:00:11")/IP(src="10.10.6.92")
# 当前构造函中最低层为Ether
Ether(raw(ip_packet))

# 定义一个TCP数据包,源mac设置为"00:00:00:00:00:11",源ip设置为"10.10.6.92",源端口设置为1234
tcp_packet = Ether(src="00:00:00:00:00:11")/IP(src="10.10.6.92")/TCP(sport=1234)
# 当前构造函中最低层为Ether
Ether(raw(tcp_packet))

# 定义一个应用层数据包,应用层内容为"GET / HTTP/1.0\r\n\r\n"
app_packet = IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
# 当前构造函中最低层为IP
IP(raw(app_packet))

 

四、发送和接收数据包

4.1 只发送数据包不接收数据包

send()函数允许自定义网络层,sendp()函数允许自定义以太网层。

不管TCP还是UDP都一样直接使用send()等函数即可,scapy会自己选择socket类型,不我们关心。

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

sendp(Ether()/IP(dst="10.10.6.92")/ICMP())

 

4.2 发送并接收响应数据包

sr1()函数参许自定义网络层,srp()函数允许自定层数据链路层

rec_packet = sr1(IP(dst="10.10.6.92")/ICMP()/"abcdefg")
rec_packet
# 直接读取某项值
rec_packet.src
# 使用show()方法格式化输出
rec_packet.show()

 

4.3 syn扫描

所谓syn扫描就是把Flags字段明确指定为SYN

rec_packet = sr1(IP(dst="10.10.6.92")/TCP(dport=80,flags="S"))
rec_packet.show()

可运行代码如下:

# install scapy by pip install scapy
from scapy.all import *


def is_open(ip, port):
    # refer: https://nmap.org/book/synscan.html
    # send syc packet, and get response
    response = sr1(IP(dst=ip) / TCP(dport=port, flags="S"), timeout=10)
    
    # filtered, No response received (even after retransmissions)
    if not response:
        print("filtered")
    # open, TCP SYN/ACK response, <Flag 18 (SA)>
    elif response.getlayer(TCP).flags == 18:
        print("open")
    # closed, TCP RST response, <Flag 20 (RA)>
    elif response.getlayer(TCP).flags == 20:
        print("closed")
    # filtered, ICMP unreachable error (type 3, code 1, 2, 3, 9, 10, or 13)
    else:
        print("filtered")

if __name__ == "__main__":
    ip = "192.168.220.128"
    port = 22
    is_open(ip, port)
View Code

 

五、在代码中使用

前面我们都是基于交互shell进行了,如果是在文件中该如何使用scapy呢。

交互shell和文件在代码书写上没有区别,唯一的区别就是交互shell导入好了scapy的所有类,而到文件上导入scapy所有类最简单的方式就是:

from scapy.all import *

(实践发现,这种写法在Pycharm中还是会提示“Unresloved reference”但运行是不报错的;实在不行使用“Alt+Enter”键把使用到的类逐个导入即可。)

 

参考:

https://scapy.readthedocs.io/en/latest/usage.html

https://github.com/secdev/scapy/

posted on 2019-03-08 16:57  诸子流  阅读(29638)  评论(0编辑  收藏  举报