当前位置:   article > 正文

Scapy实现基于ARP/ICMP/TCP/UDP的活跃设备扫描技术,以及TCP全/半端口扫描_scapy arp

scapy arp

目录

基于ARP的活跃设备发现

基于ICMP的活跃设备发现

基于TCP扫描的活跃设备发现

基于UDP扫描的活跃设备发现

Scapy实现端口扫描

基于TCP全开端口扫描

基于TCP半开端口扫描


基于ARP的活跃设备发现技术

ARP:地址解析协议,ARP(Address Resolution Protocol)

根据IP地址获取物理地址的一个TCP/IP协议,环境所在的设备如果只知道目的设备的IP地址却不知道其MAC地址的时候,可以通过这种协议,使用以太 广播包给网络上的每一台设备发送ARP数据包,获取其中符合条件的MAC地址,以保证通信的顺利进行

ARP的工作过程

假设主机A和B在同一个网段,主机A只知道主机B的IP地址,却不知道主机B的MAC地址的时候,这时候主机A首先会查看自己的ARP表,如果ARP表中含有主机B的IP相对应的MAC地址,只需要按照这个地址发送出去即可。如果主机A在ARP表中找不到对应的MAC地址,这时需要使用以太广播包给网络上的每一台设备发送ARP请求包,首先我们构造一个ARP请求,然后使用wireshark抓取这个数据包进行分析,如下:

  1. from scapy.all import *
  2. from scapy.layers.l2 import ARP, Ether
  3. ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst="192.168.200.134"), timeout=1)

以下,我们发送的数据包大小为42个字节

Destination:括号内的内容如果为(ff:ff:ff:ff:ff:ff)则是广播地址,当前数据包会被广播到当前网段的所有设备上

以下为请求信息

Hardware type: Ethernet (1)硬件的类型,硬件类型值为1, 表示是以太网地址

Protocol type: IPv4 (0x0800)协议的类型

Hardware size: 6硬件地址的长度

Protocol size: 4协议的长度

Opcode: request (1):操作码,1表示是一个arp的请求数据包

最后就是发送方的MAC地址和IP地址以及接收方IP地址,接收方MAC地址为00:00:00_00:00:00

当网络上的其他设备在接收到这个ARP请求后,会将自己的IP地址与ARP请求数据包中头部的目标设备IP地址进行比较,如果不匹配,则丢弃这个数据包。如果匹配成功,通过ARP请求数据包内源IP地址和源MAC地址,给发送方回复一个应答数据包,该数据包格式如下(注意:如果想要有应答数据包,那么这个IP地址需要真实存活):

Opcode:reply表示这是一个操作码为2的应答数据包,然后把自己的硬件地址填入,根据请求包的源IP和MAC打包发送回去

当收到这个ARP请求数据包或应答数据包时,双方就会把结果存在各自的ARP缓存表中,如下:

以后再需要和双方进行通讯,只需查询这个ARP表即可。所以,如果双方处于同一局域网时,利用ARP扫描是一个比较好的选择,不但快,而且准确且没有任何安全机制会阻止这种扫描方式

ARP实现活跃设备的扫描

首先查看一下scapy库中ARP类需要的参数,ls()查看该函数需要的具体参数

hwsrc和hwdst分别是源IP地址和源MAC地址,这两个参数不用设置,在发送的时候会自动填写进去,不过pdst需要设备为目的地址,由于是发送的广播数据包,我们需要在Ether层进行设置

  1. from scapy.all import *
  2. from scapy.layers.l2 import ARP, Ether
  3. ganyu = '192.168.200.134'
  4. pkt = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=ganyu)
  5. ans, unans = srp(pkt, timeout=1)
  6. for s, r in ans:
  7. print('success')
  8. print(r.sprintf('%Ether.src% - %ARP.psrc%'))

dst="ff:ff:ff:ff:ff:ff"即为广播数据包发送到各个网络设备上,ans中的s和r分别表示发出的ARP请求数据包和收到的应答数据包

基于ICMP的活跃设备发现技术

ICMP:Internet控制报文协议(Internet Control Message Protocol)

在日常生活中,我们经常会使用某个命令去检测本地设备与目标设备之间的连通性,比如我们所在的设备地址为192.168.1.1,目的地址为192.168.1.2,通常使用ping这个命令去判断目标是否存活,而ping的过程就是向特定的目的主机发送ICMP请求报文的过程

ICMP提供了多种报文,可以分成差错报文和查询报文,后者由一个请求数据包和查询数据包构成,与ARP扫描一样,如果发送请求数据包后接收到应答数据包,则可以判断目标主机为存活状态

同一网段/不同网段内内的ping操作

假设主机A和B在同一个网段,需要通过ping判断主机B是否存活,首先会判断主机B是否在同一网段内,若IP层协议通过主机B的IP地址和自己的子网掩码,发现跟自己属于同一网络,那么主机A会查询本地的MAC地址表,如果没有发现主机B的地址,发送ARP请求广播请求得到回应主机B的MAC地址,接下来就是进行ICMP通讯了,过程就是先利用ARP获取到主机B的地址,然后再利用MAC地址发送ICMP报文。当进行跨网段ping时,可以理解为:两个同网段的过程,通过路由器连接起来

我们通过scapy库中的ICMP函数来实现扫描,使用ls()查看函数使用时具体需要的参数,其实ICMP()内大多数参数都不需要设置,直接调用该类即可,type为8代表请求,默认为8,如果为0则表示应答

  1. from scapy.all import *
  2. from scapy.layers.inet import ICMP, IP
  3. ganyu = '192.168.200.134'
  4. pkt = IP(dst=ganyu) / ICMP()
  5. ans, unans = sr(pkt, timeout=1)
  6. for s, r in ans:
  7. print(r.sprintf('%IP.src% is alive'))

这种扫描方式相比ARP只能在特定的局域网环境下扫描来说,应用范围就会宽阔很多,无论是在互联网还是以太网都可以使用这种扫描技术,不过缺点也很明显,大部分网络设备会对ICMP进行屏蔽,所以常常会发现有一个真实存活的网络设备,但是没有扫描出来

基于TCP扫描的活跃设备发现技术

TCP:传输控制协议(Transmission Control Protocol)

一种面向连接的、可靠的、基于字节流的位于传输层通信协议,特点是使用3次握手协议建立连接,当客户端发送SYN数据包后,就等待服务器回应SYN+ACK数据包,并最终对服务器发送ACK数据包进行确认,至此通讯双方建立连接

TCP3次握手协议过程:

  • 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认

  • 第二次握手:服务器收到syn包,必须确认客户的syn(ack=j+1),同时自己也发送一个SYN+ACK包,此时服务器进入SYN_RECV状态

  • 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手

  • 完成三次握手,客户端与服务器传输数据

在TCP处于的传输层出现了端口的概念,可以理解为是设备与外界通讯交流的出口,可以分为物理端口和虚拟端口,通过虚拟端口如80,端口、3306端口、6379端口分别被不同的服务所占用来进行通讯,这些服务都是通过IP+端口号来区分的

如果我们想检测目标主机是否存活,可以从端口入手,当检测到一台设备的摸个端口有回应时(SYN+ACK数据包),可以判断该主机为存活状态,当然端口即使是关闭的,也会返回一个RST(连接重置)数据包,如下

  1. 当源地址对目的地址发送一个SYN数据包后,如果目的地址80端口关闭了,所以会返回一个RST(连接重置)数据包;

  2. 当源地址对目的地址发送一个SYN数据包后,如果目的地址80端口开启了,会返回一个SYN-ACK数据包;

  3. 当源地址对目的地址发送一个SYN数据包后,如果目的地址不存在,没有任何数据包返回;

我们通过scapy库中的TCP函数来实现扫描,使用ls()查看函数使用时具体需要的参数,这里的大多数参数都不需要设置,需要考虑的是sport、dport和flags。其中sport是源端口,dport是目标端口,flags是标志位,可能的值包括SYN(建立连接)、FIN(关闭连接)、ACK(响应)、PSH(有DATA数据传输)和RST(连接重置)

  1. from scapy.all import *
  2. from scapy.layers.inet import ICMP, IP, TCP
  3. ls(TCP())

构造一个发往192.168.3.206的3306端口的SYN数据包

  1. from scapy.all import *
  2. from scapy.layers.inet import ICMP, IP, TCP
  3. ganyu = '192.168.3.206'
  4. ganyuport = 3306
  5. pkt = IP(dst=ganyu) / TCP(dport=ganyuport, flags='S')
  6. ans, unans = sr(pkt, timeout=1)
  7. for s, r in ans: print(r.sprintf('%IP.src% is alive'))
  8. for s in unans: print('you ip is not alive')

基于UDP扫描的活跃设备发现技术

UDP:用户数据报协议(User Datagram Protocol)

与TCP不同的是,UDP没有三次握手协议,当我们像目的地址发送UDP数据包后,目标不会返回任何UDP数据包,如果主机处于存活状态时,目标端口是关闭的,就会返回一个ICMP数据包,这个数据包的内容为"unreachable"(不可达)

  1. from scapy.layers.inet import IP, UDP
  2. from scapy.sendrecv import sr1
  3. ganyu = '192.168.3.206'
  4. ganyuport = 3306
  5. packet = IP(dst=ganyu)/UDP(dport=ganyuport)
  6. ans = sr1(packet, timeout=1.0)
  7. if ans:
  8. if int(ans[IP].proto) == 1:
  9. print(ganyu + ' ' + 'is alive')
  10. else:
  11. print(ganyu + ' ' + 'is alive')
  12. else:
  13. print(ganyu + ' ' + 'is alive')

Scapy实现端口扫描

如果把服务器比作房子,那么端口就是通往不同房间的大门,如果需要去了解对方服务器,那么这栋房子里都有什么样子的门,门里面有什么,是我们首要需要去了解的

基于TCP全开端口扫描技术

如果目标端口开放,那么在收到设备的端口发出的SYN数据包后,就会返回一个SYN+ACK的数据包,表示接收这次连接请求,如果目标端口是关闭的,则收到SYN包后会返回一个RST数据包

假设我们向目标主机发送一个数据包,flags参数设置为S,代表这是一个SYN数据包

pkt = IP(dst = dstip)/TCP(sport=sport,dport=dport,flags='S')

然后通过sr1将这个数据包发送出去

ans = sr1(pkt,timeout=1) 

如果ans返回为空,表示我们没有收到来自目标端口的回应,直接判断端口关闭,如果接收到了回应,首先会判断这个数据包的类型是SYYN+ACK还是RET的,可以使用haslayer()来判断,比如判断某个数据包使用的是TCP协议吗,就可以使用haslayer(TCP),可以使用getlayer(TCP)来读取其中某个字段的内容,如下

ans.getlayer(TCP).flags == 'SA'  # SA代表SYN+ACK 

通过ans.getlayer(TCP).flags结果,对端口是否存活进行判断.SA代表SYYN+ACK,A代表ACK,R代表RST

  1. from scapy.layers.inet import *
  2. from scapy.sendrecv import *
  3. ganyu = '192.168.2.46'
  4. ganyuport = 3306
  5. ganyusport = RandShort() # 由于在和目标端口建立连接的时候,自己也需要使用一个源端口,RandShort用于随机产生一个端口号
  6. pkt = IP(dst=ganyu) / TCP(sport=ganyusport, dport=ganyuport, flags='S')
  7. ans = sr1(pkt, timeout=1) # 指定等待应答数据包的时间,不使用的话可能需要要等待很久
  8. if str(type(ans)) == "<class 'NoneType'>":
  9. print('%s' % ganyu, ':%s is closed' % ganyuport)
  10. elif ans.haslayer(TCP):
  11. if ans.getlayer(TCP).flags == 'SA': # SYN+ACK
  12. seq1 = ans.ack
  13. ack1 = ans.seq + 1
  14. pkt_rst = IP(dst=ganyu) / TCP(sport=ganyusport, dport=ganyuport, seq=seq1, ack=ack1, flags='A') # ACK
  15. send(pkt_rst)
  16. print('%s' % ganyu, ':%s is open' % ganyuport)
  17. elif ans.getlayer(TCP).flags == 'R': # RST
  18. print('%s' % ganyu, ':%s is closed' % ganyuport)

基于TCP半开端口扫描技术

之所以被称为半开是由于如果对方端口开放的话,那么收到设备端口发出的SYN数据包后,会返回一个SYN+ACK数据包,表示愿意接收这次连接请求,然后设备不在回应一个ACK数据包,而是发送一个RST数据包中断这次连接

  1. from scapy.layers.inet import *
  2. from scapy.sendrecv import *
  3. ganyu = '192.168.2.46'
  4. ganyuport = 3306
  5. ganyusport = RandShort() # 由于在和目标端口建立连接的时候,自己也需要使用一个源端口,RandShort用于随机产生一个端口号
  6. pkt = IP(dst=ganyu) / TCP(sport=ganyusport, dport=ganyuport, flags='S')
  7. ans = sr1(pkt, timeout=1)
  8. if str(type(ans)) == "<class 'NoneType'>":print('%s' % ganyu, ':%s is closed' % ganyuport)
  9. elif ans.haslayer(TCP):
  10. if ans.getlayer(TCP).flags == 'SA':print('%s' % ganyu, ':%s is open' % ganyuport)
  11. elif ans.getlayer(TCP).flags == 'R':print('%s' % ganyu, ':%s is closed' % ganyuport)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/157031
推荐阅读
相关标签
  

闽ICP备14008679号