Python之渗透测试笔记(三)——Scapy模块

Scapy模块

    • 简介
    • 基本用法
    • Scapy的基本操作
    • Scapy中的函数
    • Scapy常用简单实例

简介

  • scapy可以实现对网络数据包的发送、监听和解析等。

基本用法

  • 在kali中启动Scapy:scapy
    Python之渗透测试笔记(三)——Scapy模块_第1张图片

Scapy的基本操作

  • 在Scapy中,每一个协议就是一个类,只需要实例化一个协议类,就可以创建一个该协议的数据包。
  • 创建一个IP类型的数据包(IP数据包最重要的就是源地址和目标地址,这两个属性可以使用sec和dst来设置):
>>> ip = IP(dst= "192.168.1.255")
>>> ip
<IP  dst=192.168.1.255 |>
#这个目标dst的值可以是一个IP地址,也可以是一个IP范围,会产生256个数据包。
>>> target = "192.168.1.0/24"
>>> ip = IP(dst = target)
>>> ip
<IP  dst=Net('192.168.1.0/24') |>
  • 查看其中的数据包,
>>> [p for p in ip]
  • Scapy采用分层形式来构造数据包,通常最下面的一个协议为Ether,然后是IP,再之后是TCP或UDP。IP()函数无法用来构造ARP请求和应答数据包,此时可以使用Ether(),这个函数可以设置发送方和接收方的MAC得地址。例如:
>>> Ether(dst = "ff:ff:ff:ff:ff:ff")  #广播数据包
<Ether  dst=ff:ff:ff:ff:ff:ff |>
  • Scapy中的分层通过符合“ / ”,实现,一个数据包是由多层次协议组成,按照协议自下而上的顺序从左向右排列。
>>> Ether()/IP()/TCP()		#构造TCP数据包
<Ether  type=IPv4 |<IP  frag=0 proto=tcp |<TCP  |>>>
>>> IP()/TCP()/"GET/HTTP/1.0\r\n\r\n"	#HTTP数据包
<IP  frag=0 proto=tcp |<TCP  |<Raw  load='GET/HTTP/1.0\r\n\r\n' |>>>
  • Ether类的属性有:源地址、目的地址和类型;IP类的属性有源地址、目的地址、版本、长度、协议类型、校验和等;TCP类有源端口和目的端口。可以使用ls()函数来查看一个类的属性,例如:
>>> ls(IP())
version    : BitField (4 bits)                   = 4               (4)
ihl        : BitField (4 bits)                   = None            (None)
tos        : XByteField                          = 0               (0)
len        : ShortField                          = None            (None)
id         : ShortField                          = 1               (1)
flags      : FlagsField (3 bits)                 = <Flag 0 ()>     (<Flag 0 ()>)
frag       : BitField (13 bits)                  = 0               (0)
ttl        : ByteField                           = 64              (64)
proto      : ByteEnumField                       = 0               (0)
chksum     : XShortField                         = None            (None)
src        : SourceIPField                       = '127.0.0.1'     (None)
dst        : DestIPField                         = '127.0.0.1'     (None)
options    : PacketListField                     = []              ([])
  • 可以对属性进行设置。例如:
IP(src = "192.168.1.10",dst = "192.168.1.125", ttl = 32)

Scapy中的函数

  • 发送报文但不处理回应包的函数(刚刚使用的IP()作用是产生一个IP数据包,并未将其发送),send()是用来发送IP的数据包(第三层),sendp()是用来发送Ether()数据包的(第二层)。如:
>>> send(IP(dst = "192.168.1.10")/ICMP())	#发送目的地址为"192.168.1.10"的ICMP数据包。
.
Sent 1 packets.		#发送成功的标志
>>> sendp(Ether(dst = "ff:ff:ff:ff:ff:ff"))
.
Sent 1 packets.
  • 发送随机填充数据包,并保证这个数据包的正确性:函数fuzz(),如
>>> IP(dst = "192.168.0.10")/fuzz(TCP())
<IP  frag=0 proto=tcp dst=192.168.0.10 |<TCP  |>>
  • 发送和接收数据包的函数,sr()和sr1()主要作用于第三层,例如IP和ARP等,srp()用于第二层。
>>> sr(IP(dst = "192.168.1.10")/ICMP())		#向192.168.1.10发送一个ICMP数据包
Begin emission:
.Finished sending 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets		#Rceeived表示接收的数据包个数,answers表示对应的应答数据包。
(<Results: TCP:0 UDP:0 ICMP:1 Other:0>, <Unanswered: TCP:0 UDP:0 ICMP:0 Other:0>)
  • sr()函数是Scapy的核心,返回值是两个列表,第一个列表是收到了应答的包和对应的应答,第二个列表是未收到应答的包。
>>> ans,unans = sr(IP(dst = "192.168.1.10")/ICMP())
Begin emission:
.Finished sending 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
  • ans 保存发送的数据包和收到的应答包,使用 ans.summary()可以查看两个包的内容,unans列表为空。
>>> ans.summary()
IP / ICMP 192.168.1.125 > 192.168.1.10 echo-request 0 ==> IP / ICMP 192.168.1.10 > 192.168.1.125 echo-reply 0 / Padding
  • sr1()函数跟sr()函数作用基本相同,但只返回一个应答包,只需要一个列表。例如:
>>> ans = sr1(IP(dst = "192.168.1.10")/ICMP())
Begin emission:
.Finished sending 1 packets.
*
Received 2 packets, got 1 answers, remaining 0 packets
>>> ans
<IP  version=4 ihl=5 tos=0x0 len=28 id=8154 flags= frag=0 ttl=128 proto=icmp chksum=0x97aa src=192.168.1.10 dst=192.168.1.125 |<ICMP  type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding  load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' |>>>
  • 可以利用sr1()函数来探测目标的某个端口是否开放,采用半开扫描(SYN)的办法。
>>> sr1(IP(dst = "192.168.1.10")/TCP(dport = 80 ,flags = "S"))
Begin emission:
.Finished sending 1 packets.
..............................
  • 另一重要函数 sniff(),可以在自己的程序中捕获经过本机网卡的数据包。使用sniff()开始监听,捕获的数据包不会即时显示,只有使用Ctrl+C组合键停止监听时才会显示捕获的数据包。例如:
>>> sniff()
^C<Sniffed: TCP:3 UDP:6 ICMP:0 Other:2>
  • 这个函数最强大的地方在于可以使用参数 filter对数据包进行过滤。例如:
>>> sniff(filter = "host 192.168.1.10")	#只捕获与192.168.1.10有关的数据包
^C<Sniffed: TCP:2 UDP:0 ICMP:0 Other:0>
>>> sniff(filter = "icmp")  	#过滤指定协议,ICMP类型的数据包
^C<Sniffed: TCP:0 UDP:0 ICMP:0 Other:0>
>>> sniff(filter ="host 192.168.1.10 and icmp")		#满足多个条件可以使用"and","or"等关系运算符
^C<Sniffed: TCP:0 UDP:0 ICMP:19 Other:0>
  • 另外两个重要参数iface、count
  • iface可以指定所要进行监听的网卡,例如:
>>> sniff(iface = "eth1")
^C<Sniffed: TCP:0 UDP:2 ICMP:0 Other:0>
  • count可以用来指定监听到的数据包的数量,达到指定的数量就会停止监听,例如:
>>> sniff(count = 5)
<Sniffed: TCP:2 UDP:0 ICMP:0 Other:3>
  • 设计一个综合性的监听器,在网卡eth0上监听源地址或者目的地址为192.168.1.6的icmp数据包,接收3个这样的数据包就停止监听。(正常情况下是不会去往或来自192.168.1.10的icmp数据包,需要ping)
>>> sniff(filter = "host 192.168.1.10 and icmp", count = 3 , iface = "eth0")
<Sniffed: TCP:0 UDP:0 ICMP:3 Other:0>
>>> a = _      #在Scapy中。"_"表示上一个语句执行的结果
>>> a.nsummary()	#使用nsummary()函数查看三个数据包内容,操作对象是多个数据包
0000 Ether / IP / ICMP 192.168.1.125 > 192.168.1.10 echo-request 0 / Raw
0001 Ether / IP / ICMP 192.168.1.10 > 192.168.1.125 echo-reply 0 / Raw
0002 Ether / IP / ICMP 192.168.1.125 > 192.168.1.10 echo-request 0 / Raw
>>> a.summary()		#使用summary()函数查看,操作对象是一个数据包
>>> p=IP(dst="192.168.1.10")
>>> p.summary()
'192.168.1.125 > 192.168.1.10 hopopt'

Scapy常用简单实例

  1. 一次ACK类型的端口扫描,例如:对192.168.1.6的 21、23、80、135、445、3389端口是否被屏蔽(屏蔽不是关闭)进行ACK扫描。
>>> ans,unnas = sr(IP(dst = "192.168.1.6")/TCP(dport = [21,23,80,135,445,3389],flags='A'))
Begin emission:
..*****Finished sending 6 packets.
*
Received 8 packets, got 6 answers, remaining 0 packets
  • 正常情况下,一个开放的端口会回应ack数据包,而关闭的端口会回应rst数据包。在网络中,一些不安全的端口(22,135,139,445,3389等)会被过滤,这些端口的状态不是开放或关闭,而是被屏蔽。
  • 向目标发送5个标志位置为’A’的TCP数据包,按照TCP三次握手规则,如果端口目标为被过滤,发送的数据包就会得到回应,否则没有回应。
  • 查看未被过滤的端口:
>>> for s,r in ans:
...     if s[TCP].dport == r[TCP].sport:
...             print str(s[TCP].dport) + " is unfiltered."
... 
21 is unfiltered.
23 is unfiltered.
80 is unfiltered.
135 is unfiltered.
445 is unfiltered.
3389 is unfiltered.
  • 查看被过滤的端口:
>>> for s in unnas:
...     print str(s[TCP].dport) + " is filtered."
... 
  • 在python中编写程序来实现查看端口是否被屏蔽的简单程序。
>>> from scapy.all import IP,TCP,sr		
>>> ans,unnas = sr(IP(dst = "192.168.1.6")/TCP(dport = [21,23,80,135,445,3839],flags='A')) 
Begin emission:
.Finished sending 6 packets
...............................
Received 32 packets, got 0 answers, remaining 6 packets
  • 使用Scapy强大的包处理能力来设计一个端口是否开放的扫描器
  • 注意,与前例的区别 : 如果端口屏蔽,不会产生任何响应报文;端口开放,在收到syn数据包之后回应一个rst数据包。反之,端口关闭,在收到syn数据包之后回应一个rst数据包。
>>> from scapy.all import fuzz,TCP,IP,sr	#IP()、TCP()创建数据包、fuzz()填充数据包、sr()发送数据包  
#如果没有使用fuzz()来填充数据包,可能会导致目标端口不响应,无法对目标端口的状态进行判断
>>> ans,unnas = sr(IP(dst="192.168.1.6")/fuzz(TCP(dport=80,flags='S')))
Begin emission:
.Finished sending 1 packets.
.*
Received 3 packets, got 1 answers, remaining 0 packets
>>> for s,r in ans:		#循环查看包
...     if r[TCP].flags == 18:	#返回数据包flags的值为0x012(SYN,ACK),目标端口开放 
...             print "This port is Open."
...     if r[TCP].flags == 20:	#返回数据包flags的值为0x014(RST,ACK),目标端口关闭 
...             print "This port is Closed."
...
This port is closed.
>>> 

你可能感兴趣的:(python)