robertdavidgraham/masscan
GitHub: robertdavidgraham/masscan
互联网规模的异步端口扫描器,单机每秒可发送千万级 SYN 包,数分钟内完成全网探测。
Stars: 25379 | Forks: 3193
[](https://github.com/robertdavidgraham/masscan/actions/workflows/unittests.yml/?branch=master)
# MASSCAN:大规模 IP 端口扫描器
这是一款互联网规模的端口扫描器。它可以在 5 分钟内扫描整个互联网,从单台机器每秒传输 1000 万个数据包。
它的用法(参数、输出)与最著名的端口扫描器 `nmap` 类似。如有疑问,请尝试其中一项功能 —— 支持对多台机器进行广泛扫描的功能是受支持的,而对单台机器的深度扫描则不支持。
在内部,它使用异步传输,类似于 `scanrand`、`unicornscan` 和 `ZMap` 等端口扫描器。它更灵活,允许任意端口和地址范围。
注意:masscan 使用其自己的 **ad hoc TCP/IP 栈**。除了简单的端口扫描外,任何其他操作都可能导致与本地 TCP/IP 栈发生冲突。这意味着你需要使用 `--src-ip` 选项从不同的 IP 地址运行,或者使用 `--src-port` 配置 masscan 使用的源端口,然后配置内部防火墙(如 `pf` 或 `iptables`)将这些端口与操作系统的其余部分隔离。
# 构建
在 Debian/Ubuntu 上,操作如下。除了 C 编译器(如 `gcc` 或 `clang`)外,它实际上没有任何依赖项。
```
sudo apt-get --assume-yes install git make gcc
git clone https://github.com/robertdavidgraham/masscan
cd masscan
make
```
这会将程序放在 `masscan/bin` 子目录中。
要安装它(在 Linux 上),请运行:
```
make install
```
源代码由许多小文件组成,因此使用多线程构建可以大大加快构建速度。这在 Raspberry Pi 上需要超过 2GB 的内存(并且会出错),因此你可能会使用较小的数字,例如 `-j4`,而不是所有可能的线程。
```
make -j
```
虽然 Linux 是主要目标平台,但该代码在许多其他系统(Windows、macOS 等)上也能很好地运行。以下是一些额外的构建信息:
在 macOS 上,x86 二进制文件在 ARM 模拟下的运行速度似乎一样快。
# 用法
用法与 `nmap` 类似。要扫描某个网段的某些端口:
```
# masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112
```
这将:
要查看完整的选项列表,请使用 `--echo` 功能。这将转储当前配置并退出。此输出可用作程序的输入:
```
# masscan -p80,8000-8100 10.0.0.0/8 2603:3001:2d00:da00::/112 --echo > xxx.conf
# masscan -c xxx.conf --rate 1000
```
## Banner 检查
Masscan 不仅能检测端口是否打开。它还可以完成 TCP 连接并与该端口的应用程序交互,以获取简单的“banner”信息。
Masscan 支持以下协议的 banner 检查:
这样做的问题是,masscan 包含自己的 TCP/IP 栈,与运行它的系统是分开的。当本地系统从被探测目标接收到 SYN-ACK 时,它会响应一个 RST 数据包,在 masscan 能够获取 banner 之前终止连接。
防止这种情况的最简单方法是为 masscan 分配一个单独的 IP 地址。这看起来像以下示例之一:
```
# masscan 10.0.0.0/8 -p80 --banners --source-ip 192.168.1.200
# masscan 2a00:1450:4007:810::/112 -p80 --banners --source-ip 2603:3001:2d00:da00:91d7:b54:b498:859d
```
你选择的地址必须在本地子网上,且未被其他系统使用。Masscan 会警告你犯了错误,但你可能已经扰乱了另一台机器的通信几分钟,所以要小心。
在某些情况下,例如 WiFi,这是不可能的。在这些情况下,你可以防火墙 masscan 使用的端口。这可以防止本地 TCP/IP 栈看到数据包,但 masscan 仍然可以看到它,因为它绕过了本地栈。对于 Linux,这看起来像:
```
# iptables -A INPUT -p tcp --dport 61000 -j DROP
# masscan 10.0.0.0/8 -p80 --banners --source-port 61000
```
你可能希望选择不与 Linux 可能选择作为源端口的端口冲突的端口。你可以通过查看以下文件来查看 Linux 使用的范围,并重新配置该范围:
```
/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 上,有类似的步骤。要找出要避免的范围,请使用如下命令:
```
# sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
```
在 FreeBSD 和较旧的 MacOS 上,使用 `ipfw` 命令:
```
# sudo ipfw add 1 deny tcp from any to any 40000 in
# masscan 10.0.0.0/8 -p80 --banners --source-port 40000
```
在较新的 MacOS 和 OpenBSD 上,使用 `pf` 数据包过滤实用程序。
编辑文件 `/etc/pf.conf` 以添加如下行:
```
block in proto tcp from any to any port 40000:40015
```
然后要启用防火墙,运行命令:
```
# pfctl -E
```
如果防火墙已经在运行,那么要么重新启动,要么使用以下命令重新加载规则:
```
# pfctl -f /etc/pf.conf
```
Windows 不会响应 RST 数据包,因此这两种技术都不是必需的。但是,masscan 仍然设计为在使用其自己的 IP 地址时效果最佳,因此应尽可能以这种方式运行,即使这并非绝对必要。
其他检查(例如 `--heartbleed` 检查)也需要同样的操作,这只是 banner 检查的一种形式。
## 如何扫描整个互联网
虽然对于较小的内部网络很有用,但该程序实际上是针对整个互联网设计的。它可能看起来像这样:
```
# masscan 0.0.0.0/0 -p0-65535
```
扫描整个互联网是不好的。首先,互联网的某些部分对被扫描反应不佳。其次,某些站点会跟踪扫描并将你添加到禁止列表中,这将使你被互联网有用部分的防火墙屏蔽。
因此,你要排除很多范围。要将范围列入黑名单或排除,你要使用以下语法:
```
# masscan 0.0.0.0/0 -p0-65535 --excludefile exclude.txt
```
这只是将结果打印到命令行。你可能希望将它们保存到文件中。因此,你需要这样的东西:
```
# masscan 0.0.0.0/0 -p0-65535 -oX scan.xml
```
这将结果保存在 XML 文件中,允许你轻松地将结果转储到数据库或其他东西中。
但是,这仅以默认速率 100 个数据包/秒进行,这将花费永远的时间来扫描互联网。你需要像这样加速:
```
# 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` 的启发。当然,有很多差异,因为程序的*异步*性质导致了解决问题的根本不同方法。
上面的命令行有点麻烦。不用把所有内容都放在命令行上,而是可以将其存储在文件中。上面的设置如下所示:
```
# My Scan
rate = 100000.00
output-format = xml
output-status = all
output-filename = scan.xml
ports = 0-65535
range = 0.0.0.0-255.255.255.255
excludefile = exclude.txt
```
要使用此配置文件,请使用 `-c`:
```
# masscan -c myscan.conf
```
这也使你在重复扫描时更容易。
默认情况下,masscan 首先加载配置文件 `/etc/masscan/masscan.conf`。任何后续配置参数都会覆盖此默认配置文件中的内容。那就是我放置“excludefile”参数的地方,这样我就永远不会忘记它。它会自动工作。
## 获取输出
默认情况下,masscan 生成相当大的文本文件,但很容易将它们转换为任何其他格式。支持五种输出格式:
## 与 Nmap 的比较
在合理的情况下,已尽一切努力使程序为 `nmap` 用户所熟悉,即使它根本不同。Masscan 针对大量机器的广泛范围扫描进行了调整,而 nmap 专为单台或小范围的密集扫描而设计。
两个重要的区别是:
你可以认为 `masscan` 永久启用了以下设置:
如果你想要其他 `nmap` 兼容设置的列表,请使用以下命令:
```
# masscan --nmap
```
## 传输速率(重要!!)
该程序非常快地喷出数据包。在 Windows 上,或从 VM,它可以做 300,000 个数据包/秒。在 Linux(无虚拟化)上,它将做 160 万个数据包/秒。这足以熔化大多数网络。
请注意,它只会熔化你自己的网络。它随机化目标 IP 地址,因此不应淹没任何远程网络。
默认情况下,速率设置为 100 个数据包/秒。要将速率增加到一百万,请使用类似 `--rate 1000000` 的内容。
扫描 IPv4 互联网时,你将扫描许多子网,因此即使有大量数据包传出,每个目标子网也会收到少量传入数据包。
但是,对于 IPv6 扫描,你倾向于关注具有数十亿个地址的单个目标子网。因此,你的默认行为将淹没目标网络。网络通常会在 masscan 可以生成的负载下崩溃。
# 设计
本节描述程序的主要设计问题。
## 代码布局
文件 `main.c` 包含 `main()` 函数,如你所料。它还包含 `transmit_thread()` 和 `receive_thread()` 函数。这些函数已被故意扁平化并进行了大量注释,以便你可以通过逐行单步执行每一个来简单地阅读程序的设计。
## 异步
这是一个*异步*设计。换句话说,对于 `nmap`,它就像 `nginx` Web 服务器对于 `Apache`。它具有独立的传输和接收线程,这些线程在很大程度上彼此独立。这是在 `scanrand`、`unicornscan` 和 `ZMap` 中发现的相同类型的设计。
因为它是异步的,所以它的运行速度与底层传输允许的速度一样快。
## 随机化
Masscan 和其他扫描器之间的一个关键区别在于它随机化目标的方式。
基本原则是拥有一个从零开始的索引变量,并且每次探测递增一。在 C 代码中,这表示为:
```
for (i = 0; i < range; i++) {
scan(i);
}
```
我们必须将索引转换为 IP 地址。假设你要扫描所有“私有”IP 地址。那将是像这样的范围表:
```
192.168.0.0/16
10.0.0.0/8
172.16.0.0/12
```
在此示例中,前 64k 个索引被附加到 192.168.x.x 以形成目标地址。然后,接下来的 1600 万个被附加到 10.x.x.x。范围中的其余索引应用于 172.16.x.x。
在此示例中,我们只有三个范围。扫描整个互联网时,我们实际上有 100 多个范围。那是因为你必须将许多子范围列入黑名单或排除。这将所需范围分割成数百个较小的范围。
这导致了代码中最慢的部分之一。我们每秒传输 1000 万个数据包,并且必须为每个探测将索引变量转换为 IP 地址。我们通过在少量内存中进行“二分查找”来解决这个问题。在此数据包速率下,缓存效率开始主导算法效率。理论上有很多更有效的技术,但它们都需要如此多的内存,以至于在实践中更慢。
我们将从索引转换为 IP 地址的函数称为 `pick()` 函数。在使用中,它看起来像:
```
for (i = 0; i < range; i++) {
ip = pick(addresses, i);
scan(ip);
}
```
Masscan 不仅支持 IP 地址范围,还支持端口范围。这意味着我们需要从索引变量中选择一个 IP 地址和一个端口。这相当简单:
```
range = ip_count * port_count;
for (i = 0; i < range; i++) {
ip = pick(addresses, i / port_count);
port = pick(ports, i % port_count);
scan(ip, port);
}
```
这导致了代码的另一个昂贵部分。除法/取模指令在 x86 CPU 上大约需要 90 个时钟周期或 30 纳秒。当以每秒 1000 万个数据包的速率传输时,我们每个数据包只有 100 纳秒。我认为无法更好地优化这一点。幸运的是,两个这样的操作可以同时执行,因此执行两个这样的操作(如上所示)并不比执行一个更昂贵。
实际上,对于上述性能问题有一些简单的优化,但它们都依赖于 `i++`,即索引变量在扫描过程中逐一增加的事实。实际上,我们需要随机化此变量。我们需要随机化我们扫描的 IP 地址的顺序,否则我们将冲击那些并非为此速度级别构建的目标网络。我们需要将流量均匀地分散到目标上。
我们随机化的方式只是加密索引变量。根据定义,加密是随机的,并在原始索引变量和输出之间创建一对一映射。这意味着当我们线性遍历范围时,输出 IP 地址是完全随机的。在代码中,这看起来像:
```
range = ip_count * port_count;
for (i = 0; i < range; i++) {
x = encrypt(i);
ip = pick(addresses, x / port_count);
port = pick(ports, x % port_count);
scan(ip, port);
}
```
这也有很大的成本。由于范围是不可预测的大小,而不是漂亮的 2 的偶次幂,我们不能使用廉价的二进制技术,如 AND (&) 和 XOR (^)。相反,我们必须使用昂贵的操作,如 MODULUS (%)。在我目前的基准测试中,加密变量需要 40 纳秒。
这种架构允许许多很酷的功能。例如,它支持“分片”。你可以设置 5 台机器,每台进行五分之一的扫描或 `range / shard_count`。分片可以是多台机器,或者只是同一台机器上的多个网络适配器,甚至(如果你愿意)同一网络适配器上的多个 IP 源地址。
或者,你可以为加密函数使用“种子”或“密钥”,以便每次扫描时获得不同的顺序,例如 `x = encrypt(seed, i)`。
我们还可以通过退出程序来暂停扫描,只需记住 `i` 的当前值,稍后再重新启动它。我在开发过程中经常这样做。我看到我的互联网扫描出了点问题,所以我按 停止扫描,然后在我修复错误后重新启动它。
另一个功能是重传/重试。数据包有时会在互联网上丢失,因此你可以背靠背发送两个数据包。但是,丢弃一个数据包的东西可能会丢弃紧随其后的数据包。因此,你希望将副本发送间隔大约 1 秒。这很简单。我们已经有了一个“速率”变量,它是我们传输的每秒数据包数,因此重传函数只是使用 `i + rate` 作为索引。总有一天我要研究一下互联网,并以这种方式区分“背靠背”、“1 秒”、“10 秒”和“1 分钟”重传,看看丢弃的内容是否有任何差异。
## C10 可扩展性
异步技术被称为“c10k 问题”的解决方案。
Masscan 是为下一级可扩展性设计的,即“C10M 问题”。
C10M 解决方案是绕过内核。Masscan 中有三个主要的内核绕过:
Masscan 可以使用 PF_RING DNA 驱动程序。此驱动程序将数据包直接从用户模式内存 DMA 到网络驱动程序,而无需内核参与。这允许软件,即使使用慢速 CPU,也能以硬件允许的最大速率传输数据包。如果你在计算机中放入 8 个 10-gbps 网卡,这意味着它可以以 1 亿个数据包/秒的速度传输。
Masscan 有自己的内置 TCP 栈,用于从 TCP 连接获取 banner。这意味着它可以轻松支持 1000 万个并发 TCP 连接,当然假设计算机有足够的内存。
Masscan 没有“互斥锁”。现代互斥锁(又名 futex)主要是用户模式的,但它们有两个问题。第一个问题是它们导致缓存行在 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` 方面投入了大量精力,每个进行端口扫描的人都(应该)熟悉 `nmap`。
## IPv6 和 IPv4 共存
Masscan 支持 IPv6,但没有特殊模式,两者同时受支持。(没有 `-6` 选项 —— 它始终可用)。
在你看到的任何 masscan 用法示例中,只需在看到 IPv4 地址的地方放置一个 IPv6 地址。你可以在同一次扫描中同时包含 IPv4 和 IPv6 地址。输出在同一位置包含适当的地址,没有特殊标记。
只要记住 IPv6 地址空间真的很大。你可能不想扫描大范围,除非是子网的前 64k 地址,它们是通过 DHCPv6 分配的。
相反,你可能希望扫描存储在文件(`--include-file filename.txt`)中的大量地址列表,这些地址是你从其他来源获得的。
像其他地方一样,此文件可以包含 IPv4 和 IPv6 地址的列表。
我使用的测试文件包含 800 万个地址。这种大小的文件在启动时需要额外的几秒钟来读取(masscan 在扫描之前对地址进行排序并删除重复项)。
请记住,masscan 包含自己的网络栈。因此,你运行 masscan 的本地机器不需要启用 IPv6 —— 尽管本地网络需要能够路由 IPv6 数据包。
## PF_RING
要超过 200 万个数据包/秒,你需要一个 Intel 10-gbps 以太网适配器和一个称为 [ntop 的“PF_RING ZC”](http://www.ntop.org/products/packet-capture/pf_ring/pf_ring-zc-zero-copy/) 的特殊驱动程序。Masscan 不需要重建即可使用 PF_RING。要使用 PF_RING,你需要构建以下组件:
你不需要构建他们的 `libpcap.so` 版本。
当 Masscan 检测到适配器命名为 `zc:enp1s0` 之类的名称而不是 `enp1s0` 之类的名称时,它会自动切换到 PF_RING ZC 模式。
更详细的讨论可以在 **PoC||GTFO 0x15** 中找到。
## 回归测试
该项目包含一个内置单元测试:
```
$ make test
bin/masscan --selftest
selftest: success!
```
这测试了代码的许多棘手部分。你应该在构建后执行此操作。
## 性能测试
要测试性能,请运行类似以下内容到一次性地址,以避免使本地路由器过载:
```
$ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --router-mac 66-55-44-33-22-11
```
伪造的 `--router-mac` 将数据包保留在本地网段上,这样它们就不会传到互联网上。
你也可以在“离线”模式下测试,这是程序在没有传输开销的情况下的运行速度:
```
$ bin/masscan 0.0.0.0/4 -p80 --rate 100000000 --offline
```
第二个基准测试粗略显示了如果使用 PF_RING,程序将运行多快,PF_RING 具有接近零的开销。
顺便说一句,随机化算法大量使用“整数运算”,这是 CPU 上长期缓慢的操作。现代 CPU 将执行此计算的速度提高了一倍,使 `masscan` 更快。
# 作者
此工具由 Robert Graham 创建:
email: robert_david_graham@yahoo.com
twitter: @ErrataRob
# 许可证
Copyright (c) 2013 Robert David Graham
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
标签:certspotter, C语言, Docker‑Compose, GraphQL指纹识别, Masscan, Nmap替代, TCP/IP协议栈, TCP SYN 扫描, Web UI, Web安全工具, Web应用安全, 二进制发布, 互联网扫描, 协议分析, 发包工具, 可视化仪表盘, 子域名侦测, 客户端加密, 客户端加密, 客户端加密, 客户端加密, 密码管理, 开源工具, 异步传输, 批量扫描, 插件系统, 数据库初始化, 数据泄露防护, 数据统计, 服务器安全, 权限提升, 渗透测试, 漏洞赏金平台, 用户界面自定义, 端口扫描, 红队工具, 网络安全, 网络安全平台, 网络探测, 网络空间测绘, 资产发现, 隐私保护, 高速扫描