github连接:
https://github.com/robertdavidgraham/masscan
MASSCAN:海量 IP 端口扫描器
这是一个互联网规模的端口扫描器。它可以在 5 分钟内扫描整个互联网,从一台机器每秒传输 1000 万个数据包。
它的用法(参数、输出)类似于nmap
最著名的端口扫描器。如有疑问,请尝试其中一项功能——支持对多台计算机进行广泛扫描的功能,但不支持对单台计算机进行深度扫描。
在内部,它使用异步传输,类似于 scanrand
、unicornscan
、 和 等端口扫描器ZMap
。它更加灵活,允许任意端口和地址范围。
注意:masscan 使用自己的专用 TCP/IP 堆栈。除了简单的端口扫描之外的任何操作都可能导致与本地 TCP/IP 堆栈发生冲突。这意味着您需要使用--src-ip
从不同 IP 地址运行的选项,或者用于--src-port
配置 Masscan 使用的源端口,然后还配置内部防火墙(如pf
或iptables
)以将这些端口与操作系统的其余部分隔离。
该工具是免费的,但请考虑为其开发捐款:比特币钱包地址:1MASSCANaHUiyTtR3bJ2sLGuMw5kDBaj4T
建筑
在 Debian/Ubuntu 上,情况如下所示。gcc
除了 C 编译器(例如或)之外,它实际上没有任何依赖项clang
。
1 | sudo apt-get --assume-yes install git make gcc |
这会将程序放入masscan/bin
子目录中。要安装它(在 Linux 上),请运行:
1 | make install |
源代码由许多小文件组成,因此使用多线程构建可以加快构建速度。这需要 Raspberry Pi 上超过 2gig(并且会损坏),因此您可以使用较小的数量,而-j4
不是所有可能的线程。
1 | make -j |
虽然 Linux 是主要目标平台,但代码在许多其他系统(Windows、macOS 等)上运行良好。以下是一些额外的构建信息:
- Windows w/ Visual Studio:使用 VS10 项目
- Windows w/ MinGW:只需键入
make
- Windows w/cygwin:无法工作
- Mac OS X /w XCode:使用 XCode4 项目
- Mac OS X /w cmdline:只需键入
make
- FreeBSD:类型
gmake
- 其他:尝试将所有文件编译在一起,
cc src/*.vs -o bin/masscan
- 其他:尝试将所有文件编译在一起,
在 macOS 上,x86 二进制文件在 ARM 模拟下的运行速度似乎同样快。
用法
用法类似于nmap
. 扫描某个网段的某些端口:
1 | # masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112 |
这会:
- 扫描
10.x.x.x
子网和2603:3001:2d00:da00::x
子网 - 扫描两个子网上的端口 80 以及范围 8000 到 8100,即总共 102 个端口
- 打印输出
<stdout>
可以重定向到文件
要查看完整的选项列表,请使用该--echo
功能。这将转储当前配置并退出。该输出可以用作程序的输入:
1 | # masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112 --echo > xxx.conf |
横幅检查
Masscan 的功能不仅仅是检测端口是否打开。它还可以在该端口完成与应用程序的TCP连接和交互,以获取简单的“横幅”信息。
Masscan 支持以下协议的横幅检查:
- 文件传输协议
- HTTP协议
- IMAP4
- 内存缓存
- POP3
- 邮件传输协议
- SSH
- SSL协议
- SMBv1
- SMBv2
- 远程登录
- 远程开发计划
- 虚拟网络控制器
问题在于,masscan 包含自己的 TCP/IP 堆栈,与运行它的系统分开。当本地系统收到来自被探测目标的 SYN-ACK 时,它会使用 RST 数据包进行响应,该数据包会在 Masscan 抓取横幅之前终止连接。
防止这种情况的最简单方法是为 Masscan 分配一个单独的 IP 地址。这看起来像以下示例之一:
1 | # masscan 10.0.0.0/8 -p80 --banners --source-ip 192.168.1.200 |
您选择的地址必须位于本地子网上,并且不能被其他系统使用。Masscan 会警告你犯了一个错误,但你可能已经弄乱了另一台机器的通信几分钟,所以要小心。
在某些情况下,例如 WiFi,这是不可能的。在这些情况下,您可以对 Masscan 使用的端口进行防火墙。这可以防止本地 TCP/IP 堆栈看到该数据包,但 Masscan 仍然可以看到它,因为它绕过了本地堆栈。对于 Linux,这看起来像:
1 | # iptables -A INPUT -p tcp --dport 61000 -j DROP |
您可能希望选择与 Linux 可能选择的源端口不冲突的端口。您可以通过查看文件来查看 Linux 使用的范围并重新配置该范围:
1 | /proc/sys/net/ipv4/ip_local_port_range |
在最新版本的 Kali Linux(2018 年 8 月)上,该范围是 32768 到 60999,因此您应该选择低于 32768 或 61000 及以上的端口。
设置iptables
规则仅持续到下次重新启动为止。您需要根据您的发行版查找如何保存配置,例如使用iptables-save
和/或iptables-persistent
.
在 Mac OS X 和 BSD 上,也有类似的步骤。要找出要避免的范围,请使用如下命令:
1 | # sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last |
在 FreeBSD 和较旧的 MacOS 上,使用ipfw
命令:
1 | # sudo ipfw add 1 deny tcp from any to any 40000 in |
在较新的 MacOS 和 OpenBSD 上,使用pf
数据包过滤实用程序。编辑该文件/etc/pf.conf
以添加如下行:
1 | block in proto tcp from any to any port 40000:40015 |
然后要启用防火墙,请运行命令:
1 | # pfctl -E |
如果防火墙已在运行,则重新启动或使用以下命令重新加载规则:
1 | # pfctl -f /etc/pf.conf |
Windows 不会响应 RST 数据包,因此这些技术都不是必需的。然而,masscan 仍然被设计为使用自己的 IP 地址来最好地工作,因此您应该尽可能以这种方式运行,即使不是绝对必要的。
其他检查也需要同样的东西,例如检查--heartbleed
,这只是横幅检查的一种形式。
如何扫描整个互联网
虽然该程序对于较小的内部网络很有用,但它在设计时确实考虑到了整个互联网。它可能看起来像这样:
1 | # masscan 0.0.0.0/0 -p0-65535 |
扫描整个互联网是不好的。一方面,互联网的某些部分对扫描的反应很糟糕。另一方面,一些网站会跟踪扫描并将您添加到禁止列表中,这将使您无法访问互联网的有用部分。因此,您想要排除很多范围。要将范围列入黑名单或排除范围,您需要使用以下语法:
1 | # masscan 0.0.0.0/0 -p0-65535 --excludefile exclude.txt |
这只是将结果打印到命令行。您可能希望将它们保存到文件中。因此,你想要这样的东西:
1 | # masscan 0.0.0.0/0 -p0-65535 -oX scan.xml |
这会将结果保存在 XML 文件中,使您可以轻松地将结果转储到数据库或其他内容中。
但是,这仅以每秒 100 个数据包的默认速率进行,这将花费很长时间来扫描互联网。您需要像这样加快速度:
1 | # masscan 0.0.0.0/0 -p0-65535 --max-rate 100000 |
这会将速率提高到每秒 100,000 个数据包,这将在每个端口大约 10 小时内扫描整个互联网(减去排除)(如果扫描所有端口则需要 655,360 小时)。
关于此命令行需要注意的是,这些都是nmap
兼容的选项。此外,nmap
还为您设置了兼容的“隐形”选项:-sS -Pn -n --randomize-hosts --send-eth
。同样,XML 文件的格式也受到nmap
. 当然,存在很多差异,因为程序的异步性质导致了解决问题的根本不同的方法。
上面的命令行有点麻烦。不必将所有内容都放在命令行上,而是可以将其存储在文件中。上面的设置看起来像这样:
1 | # My Scan |
要使用此配置文件,请使用-c
:
1 | # masscan -c myscan.conf |
当您重复扫描时,这也使事情变得更容易。
默认情况下,masscan 首先加载配置文件 /etc/masscan/masscan.conf
。任何后续配置参数都会覆盖此默认配置文件中的内容。这就是我放置“excludefile”参数的地方,这样我就不会忘记它。它只是自动工作。
获取输出
默认情况下,masscan 会生成相当大的文本文件,但很容易将它们转换为任何其他格式。有五种支持的输出格式:
xml:只需使用参数
-oX <filename>
. 或者,使用参数--output-format xml
和--output-filename <filename>
。二进制:这是masscan 内置格式。它生成的文件要小得多,因此当我扫描互联网时,我的磁盘不会填满。但它们需要被解析。命令行选项
--readscan
将读取二进制扫描文件。--readscan
与该选项一起使用-oX
将生成结果文件的 XML 版本。grepable:这是 Nmap -oG 输出的实现,可以通过命令行工具轻松解析。只需使用参数即可
-oG <filename>
。或者,使用参数--output-format grepable
和--output-filename <filename>
。json:这会将结果保存为 JSON 格式。只需使用参数即可
-oJ <filename>
。或者,使用参数--output-format json
和--output-filename <filename>
。list:这是一个简单的列表,每行有一个主机和端口对。只需使用参数即可
-oL <filename>
。或者,使用参数--output-format list
和--output-filename <filename>
。格式为:1
2<port state> <protocol> <port number> <IP address> <POSIX timestamp>
open tcp 80 XXX.XXX.XXX.XXX 1390380064
与Nmap的比较
在合理的情况下,我们已尽一切努力使该程序为nmap
用户所熟悉,即使它有本质上的不同。Masscan 适合对大量机器进行大范围扫描,而 nmap 则设计用于对单台机器或小范围进行密集扫描。
两个重要的区别是:
- 没有要扫描的默认端口,您必须指定
-p <ports>
nmap
目标主机是 IP 地址或简单范围,而不是 DNS 名称,也不能使用时髦的子网范围(例如10.0.0-255.0-255
)。
您可以认为masscan
永久启用以下设置:
-sS
:这仅进行 SYN 扫描(目前,将来会改变)-Pn
:不首先 ping 主机,这是异步操作的基础-n
: 没有发生 DNS 解析--randomize-hosts
:始终完全随机扫描,您无法更改此设置--send-eth
:使用原始发送libpcap
如果您想要其他兼容设置的列表nmap
,请使用以下命令:
1 | # masscan --nmap |
传输速率(重要!!)
这个程序发出数据包的速度非常快。在 Windows 上或虚拟机上,它每秒可以处理 300,000 个数据包。在 Linux(无虚拟化)上,它每秒处理 160 万个数据包。这速度足以融化大多数网络。
请注意,它只会融化您自己的网络。它将目标 IP 地址随机化,这样就不会淹没任何远程网络。
默认情况下,速率设置为 100 个数据包/秒。要将速率提高到一百万,请使用类似--rate 1000000
.
扫描 IPv4 Internet 时,您将扫描大量子网,因此即使有大量数据包发出,每个目标子网也会收到少量传入数据包。
然而,通过 IPv6 扫描,您往往会关注具有数十亿个地址的单个目标子网。因此,您的默认行为将压垮目标网络。网络经常在 Masscan 产生的负载下崩溃。
设计
本节描述该程序的主要设计问题。
代码布局
正如您所期望的,该文件main.c
包含该函数。main()
它还包含transmit_thread()
和receive_thread()
函数。这些函数已被故意扁平化并带有大量注释,以便您只需逐行浏览每个函数即可阅读程序的设计。
异步
这是一个异步设计。换句话说,它的作用相当于网络服务器的nmap
作用。它具有独立的发送和接收线程,这些线程在很大程度上彼此独立。这与、、 和中发现的设计类型相同。nginx``Apache``scanrand``unicornscan``ZMap
由于它是异步的,因此它的运行速度与底层数据包传输允许的速度一样快。
随机化
Masscan 与其他扫描仪之间的一个关键区别在于它随机化目标的方式。
基本原则是有一个索引变量,该变量从零开始,每次探测时递增 1。在 C 代码中,这表示为:
1 | for (i = 0; i < range; i++) { |
我们必须将索引转换为 IP 地址。假设您想要扫描所有“私有”IP 地址。那将是范围表,例如:
1 | 192.168.0.0/16 |
在此示例中,前 64k 索引附加到 192.168.xx 以形成目标地址。然后,接下来的 1600 万被附加到 10.xxx 该范围内的剩余索引被应用到 172.16.xx
在此示例中,我们只有三个范围。当扫描整个互联网时,我们实际上有超过 100 个范围。那是因为您必须将许多子范围列入黑名单或排除。这会将所需的范围分成数百个较小的范围。
这导致代码中最慢的部分之一。我们每秒传输 1000 万个数据包,并且必须将每个探测器的索引变量转换为 IP 地址。我们通过在少量内存中进行“二分搜索”来解决这个问题。在此数据包速率下,缓存效率开始超过算法效率。理论上有很多更有效的技术,但它们都需要大量的内存,因此在实践中速度会变慢。
我们将把索引转换为 IP 地址的函数称为函数pick()
。在使用中,它看起来像:
1 | for (i = 0; i < range; i++) { |
Masscan 不仅支持 IP 地址范围,还支持端口范围。这意味着我们需要从索引变量中选择 IP 地址和端口。这相当简单:
1 | range = ip_count * port_count; |
这导致代码的另一个昂贵部分。在 x86 CPU 上,除法/取模指令大约需要 90 个时钟周期,即 30 纳秒。当以 1000 万个数据包/秒的速率传输时,每个数据包只有 100 纳秒。我认为没有办法更好地优化它。但幸运的是,两个这样的操作可以同时执行,因此执行其中两个操作(如上所示)并不比执行一个更昂贵。
对于上述性能问题其实有一些简单的优化,但是它们都依赖于i++
索引变量通过扫描逐一增加的事实。实际上,我们需要随机化这个变量。我们需要随机化所扫描的 IP 地址的顺序,否则我们将炸掉那些不是为这种速度水平构建的目标网络。我们需要将流量均匀地分布在目标上。
我们随机化的方式很简单,就是对索引变量进行加密。根据定义,加密是随机的,并在原始索引变量和输出之间创建 1 对 1 的映射。这意味着当我们线性遍历该范围时,输出 IP 地址是完全随机的。在代码中,这看起来像:
1 | range = ip_count * port_count; |
这也有很大的成本。由于范围的大小是不可预测的,而不是 2 的偶次幂,因此我们不能使用廉价的二进制技术,例如 AND (&) 和 XOR (^)。相反,我们必须使用昂贵的运算,例如 MODULUS (%)。在我当前的基准测试中,加密变量需要 40 纳秒。
这种架构允许许多很酷的功能。例如,它支持“分片”。您可以设置 5 台机器,每台机器执行五分之一的扫描或 range / shard_count
. 分片可以是多台机器,也可以是同一台机器上的多个网络适配器,甚至(如果您愿意)同一网络适配器上的多个 IP 源地址。
或者,您可以使用加密功能的“种子”或“密钥”,以便每次扫描时都会得到不同的顺序,例如x = encrypt(seed, i)
。
我们还可以通过退出程序来暂停扫描,只需记住 的当前值i
,然后重新启动即可。我在开发过程中经常这样做。我发现我的互联网扫描出了问题,所以我点击停止扫描,然后在修复错误后重新启动扫描。
另一个功能是重传/重试。数据包有时会在 Internet 上丢失,因此您可以连续发送两个数据包。然而,丢弃一个数据包的东西可能会丢弃紧随其后的数据包。因此,您希望间隔大约 1 秒发送副本。这很简单。我们已经有一个“速率”变量,它是我们正在传输的每秒数据包的数量,因此重传函数只是用作i + rate
索引。这几天我要研究一下互联网,区分一下“背靠背”、“1秒”、“10秒”、“1分钟”这样的重传,看看有没有被丢弃的东西有什么区别。
C10 可扩展性
异步技术被称为“c10k 问题”的解决方案。Masscan 专为下一级别的可扩展性“C10M 问题”而设计。
C10M的解决方案是绕过内核。Masscan 中存在三种主要的内核绕过方式:
- 自定义网络驱动程序
- 用户模式 TCP 堆栈
- 用户模式同步
Masscan 可以使用 PF_RING DNA 驱动程序。该驱动程序 DMA 数据包直接从用户模式内存发送到网络驱动程序,零内核参与。这样,即使 CPU 速度较慢,软件也能以硬件允许的最大速率传输数据包。如果您在计算机中放置 8 个 10 Gbps 网卡,这意味着它可以以每秒 1 亿个数据包的速度传输。
Masscan 有自己的内置 TCP 堆栈,用于从 TCP 连接抓取横幅。这意味着它可以轻松支持 1000 万个并发 TCP 连接,当然前提是计算机有足够的内存。
Masscan 没有“互斥体”。现代互斥体(又名 futexes)主要是用户模式的,但它们有两个问题。第一个问题是它们导致缓存行在 CPU 之间快速来回跳动。第二个是,当存在争用时,它们会对内核进行系统调用,这会降低性能。程序快速路径上的互斥体严重限制了可伸缩性。相反,Masscan 使用“环”来同步事物,例如当接收线程中的用户模式 TCP 堆栈需要传输数据包而不干扰传输线程时。
可移植性
该代码在 Linux、Windows 和 Mac OS X 上运行良好。所有重要部分均采用标准 C (C90) 语言。因此,它在 Visual Studio 上使用 Microsoft 的编译器进行编译,在 Mac OS X 上使用 Clang/LLVM 编译器进行编译,在 Linux 上使用 GCC 进行编译。
Windows 和 Mac 并未针对数据包传输进行调整,每秒只能传输约 300,000 个数据包,而 Linux 每秒可以传输 1,500,000 个数据包。无论如何,这可能比你想要的要快。
安全码
针对漏洞提供赏金,请参阅 VULNINFO.md 文件以获取更多信息。
该项目使用诸如 之类的安全函数,safe_strcpy()
而不是诸如 之类的不安全函数strcpy()
。
该项目具有自动化单元回归测试 ( make regress
)。
兼容性
我们付出了很多努力来使输入/输出看起来像nmap
,每个进行端口扫描的人都(或应该)熟悉这一点。
IPv6 和 IPv4 共存
Masscan支持IPv6,但没有特殊模式,两者同时支持。(没有-6
选择——它总是可用的)。
在您看到的 Masscan 使用的任何示例中,只需将 IPv6 地址放在您看到的 IPv4 地址处即可。您可以在同一扫描中同时包含 IPv4 和 IPv6 地址。输出包括同一位置的适当地址,没有特殊标记。
请记住,IPv6 地址空间非常大。您可能不想扫描大范围,除了通过 DHCPv6 分配的子网的前 64k 地址。
相反,您可能需要扫描--include-file filename.txt
从其他来源获得的文件 ( ) 中存储的大量地址列表。与其他地方一样,此文件可以包含 IPv4 和 IPv6 地址的列表。我使用的测试文件包含 800 万个地址。该大小的文件在启动时需要额外几秒钟的时间来读取(masscan 在扫描之前对地址进行排序并删除重复项)。
请记住,masscan 包含其自己的网络堆栈。因此,运行 Masscan 的本地计算机不需要启用 IPv6——尽管本地网络需要能够路由 IPv6 数据包。
PF_RING
要获得超过 200 万个数据包/秒,您需要一个 Intel 10-gbps 以太网适配器和一个来自 ntop 的名为“PF_RING ZC”的特殊驱动程序。无需重建 Masscan 即可使用 PF_RING。要使用 PF_RING,您需要构建以下组件:
libpfring.so
(安装在/usr/lib/libpfring.so中)pf_ring.ko
(他们的内核驱动程序)ixgbe.ko
(他们的 Intel 10-gbps 以太网驱动程序版本)
您不需要构建他们的版本libpcap.so
。
当 Masscan 检测到适配器的名称类似于 时zc:enp1s0
,enp1s0
它会自动切换到 PF_RING ZC 模式。
更详细的讨论可以在PoC||GTFO 0x15中找到。
回归测试
该项目包含一个内置的单元测试:
1 | $ make test |
这测试了代码的许多棘手部分。您应该在构建后执行此操作。
性能测试
要测试性能,请对一次性地址运行类似以下内容,以避免本地路由器过载:
1 | $ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --router-mac 66-55-44-33-22-11 |
伪造者--router-mac
将数据包保留在本地网段上,这样它们就不会传到互联网上。
您还可以在“离线”模式下进行测试,这是程序在没有传输开销的情况下运行的速度:
1 | $ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --offline |
第二个基准测试大致显示了如果使用 PF_RING 程序的运行速度,其开销几乎为零。
顺便说一句,随机化算法大量使用“整数算术”,这是 CPU 上长期缓慢的运算。现代 CPU 已将执行此计算的速度提高了一倍,速度masscan
更快。
作者
该工具由 Robert Graham 创建:电子邮件:robert_david_graham@yahoo.com 推特:@ErrataRob
执照
版权所有 (c) 2013 罗伯特·大卫·格雷厄姆
该程序是免费软件:您可以根据自由软件基金会发布的 GNU Affero 通用公共许可证(许可证版本 3)的条款重新分发和/或修改它。
分发此程序的目的是希望它有用,但不提供任何保证;甚至没有适销性或特定用途适用性的默示保证。有关更多详细信息,请参阅 GNU Affero 通用公共许可证。
您应该随该程序一起收到 GNU Affero 通用公共许可证的副本。如果没有,请参阅https://www.gnu.org/licenses/。
About this Post
This post is written by 杨CC, licensed under CC BY-NC 4.0.