0x00:简介

Scapy 不仅可以在二层、三层去发现目标主机,也可以在四层去应用。主要用到的协议是 TCP 和 UDP。

0x01:scapy tcp

首先,构造一个 tcp 包,tcp 单独是不能发送的,所以需要结合一下三层的 ip 协议,scapy 中也就是 ip 函数和 tcp 函数的结合,示例如下:

信息搜集 - 四层发现 Scapy

IP 包头里的 dst 字段,指定目标地址。
TCP 包头里的 flags 字段,用来指定 tcp 包要发送的类型,这里用 A,意思是 TCP 握手包中的 ACK。
TCP 包里的 sport 指源发送的端口,也就是我们用哪个端口去请求,这里是 ftp20。
TCP 包里的 dport 指目标的端口,也就是要请求目标的哪个端口,这里默认是 http80。

dst、flags 我们手动设置,sport、dport 默认即可,最后用 sr1 函数发送即可,示例图如下:

信息搜集 - 四层发现 Scapy

我请求的是网关地址,也就是路由,路由的 80 端口是开放的,看返回结果,主要看 TCP 中的 flags,因为如果目标地址存在,握手包都会返回一个 RST。返回包的 flags 是 R 时,也就代表返回了 RST 包。则证明目标存在。

再看一下目标 ip 不开放时的情况,首先修改 TCP 包的 dport 值,指定一个没有开放的端口,例如 3306,示例图如下:

信息搜集 - 四层发现 Scapy

这时发送此包,然后 display 查看返回结果,如下图:

信息搜集 - 四层发现 Scapy

可见 TCP 中的 flags 值为 R,也就是返回了 RST 包,则目标在线。

注意:以上过程是利用四层 TCP 协议去发现相关的主机,而不是端口探测。综上可知,L 利用 TCP 去进行四层发现时,如果某一个目标在线,不管使用哪一个端口去发现,其都会返回 RST 包,则可根据此标志来判断目标是否在线。

那么当目标在线时,开放的端口和未开放的端口都会返回 RST 包,那该如何判断目标不在线,当目标不在线时,就不会返回 RST 包,而是返回信息告诉你没有找到目标地址,示例如下:

信息搜集 - 四层发现 Scapy

上面地址是没在线的,因为没有在线,所以需要加个 timeout 超时时间,可以看到提示地址 mac 没有找到,这可以判断目标地址此时没有在线。

以上操作也可以放到一行中去执行,例如 a=sr1(IP(dst="20.18.0.254")/TCP(dport=80,flags='A'),timeout=1) ,运行结果如下:

信息搜集 - 四层发现 Scapy

一行形式写 python 脚本,批量去发现,效率更快,示例代码如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*- 

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *

if len(sys.argv)!=2:
    print "参数错误,示例:./scapy-tcp.py 192.168.1.0"
    sys.exit()

address=str(sys.argv[1])
prefix=address.split('.')[0]+'.'+address.split('.')[1]+'.'+address.split('.')[2]+'.'

for addr in range(1,254):
    response=sr1(IP(dst=prefix+str(addr))/TCP(dport=2222,flags='A'),timeout=0.1,verbose=0)
    try:
        if response[TCP].flags)=='R':
            print prefix+str(addr)
    except:
        pass

使用时,直接更 ip 即可,脚本会获取 ip 地址前三段,然后遍历第时段从 1-254,最后使用 TCP 来发送,如果 response 返回的 TCP 中的 flags 是 R,也就是返回了 RST 包,则打印此 ip,执行结果如下:

信息搜集 - 四层发现 Scapy

通过 wireshark 抓包,可以看出协议是 TCP,由 20 端口发像 2222 端口,发的是 ACK,如下图:

信息搜集 - 四层发现 Scapy

0x02:scapy udp

udp 不像 tcp 有多次握手,udp 包发送后是不会有 flags 响应的。判断时需要选择一个端口,如果返回的包提示端口不可达,则说明目标在线。当目标不在线时,会发出提示地址的 mac 没有找到。

同样的,发现目标是否存在,在四层中除了 tcp,也可以使用 udp,,首先在 scapy 中利用 ip 函数和 udp 函数来构造一个请求包,如下图:

信息搜集 - 四层发现 Scapy

然后设置 ip 的 dst 指定目标地址,设置 udp 的 dport 指定目标端口,如下:

信息搜集 - 四层发现 Scapy

如果设置一个不在线的 ip 地址,则执行结果如下:

信息搜集 - 四层发现 Scapy

以上过程也可以通过一行命令来执行,以下是一行命令,目标在线和目标不在线结果对比:

信息搜集 - 四层发现 Scapy

目标在线时会得到一个响应包,目标不在线时会得到零个响应包且会提示 mac 地址没有找到。使用 udp 批量扫描时,python 脚本如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*- 

import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *

if len(sys.argv)!=2:
    print "参数错误,示例:./scapy-udp.py 192.168.1.0"
    sys.exit()

address=str(sys.argv[1])
prefix=address.split('.')[0]+'.'+address.split('.')[1]+'.'+address.split('.')[2]+'.'

for addr in range(1,254):
    response=sr1(IP(dst=prefix+str(addr))/UDP(dport=22222),timeout=0.1,verbose=0)
    try:
        if int(response[IP].proto)==1:
            print prefix+str(addr)
    except:
        pass

脚本和 tcp 一样,原理也相似,最后打印判断时,取的是 ip 包头里的 proto 字段,当 proto 为 1 时,则代表 udp 上一层协议为 icmp 协议,当上一层为 icmp 时,上一层能成功返回则可认为目标是在线的,通过前面的返回 IP 包头也可以看到,proto 的值为 icmp,脚本运行结果如下:

信息搜集 - 四层发现 Scapy

可以抓包看一下 ip 包头的 proto 值,不同的数字代表不同的协议,如下图:

信息搜集 - 四层发现 Scapy

具体数字代表哪些协议可以查看 RFC1700 文档,1 为 icmp 截图如下:

信息搜集 - 四层发现 Scapy

0x03:总结

利用 scapy 的 tcp 和 udp 在四层发现目标是否在线,虽然利用到了端口,但这里检测的是主机是否在线,而不是端口是否开放。四层不能单独的去发包,需要结合其他层来实现,例如返回的包有三层 icmp,发送需要三层的 ip 等。如果目标在线,而 tcp 或 udp 没有检测到时,建议再使用其他层来确认,检测结果只是参考,而不是确认结果。

更多关于代码审计、WEB渗透、网络安全的运维的知识,请关注微信公众号:发哥微课堂。

信息搜集 - 四层发现 Scapy

相关文章:

  • 2022-12-23
  • 2021-05-28
  • 2021-11-04
  • 2021-08-03
  • 2021-09-22
  • 2021-04-02
  • 2021-12-01
猜你喜欢
  • 2021-10-21
  • 2021-06-20
  • 2021-08-27
  • 2021-08-09
  • 2021-06-17
  • 2021-05-19
  • 2021-11-29
相关资源
相似解决方案