1. 前言
最近要做一个扫描 ip 端口的功能
扫描的工具有很多,但是如何做到短时间扫描大量的 ip 是个相对困难的事情。
市场上比较出名的工具有 masscan
和nmap
masscan 支持异步扫描,对多线程的利用很好,同时仅仅支持 syn 半开扫描,这让 masscan 对端口进行粗糙扫描的性能达到了非常高的地步
半开扫描是指发送一个 SYN 包(SYN-SENT 状态),等待目标主机回复 SYN+ACK 包(SYN-RECEIVED 状态),然后发送一个 RST 包(ESTABLISHED 状态),以终止连接。半开扫描的优点是速度快,因为它只需要发送一个 SYN 包和一个 RST 包,而不需要完成整个三次握手过程。缺点是容易被一些防火墙和 IDS/IPS 检测到,因为它不是一个完整的连接过程
缺点就是结果比较模糊,无法知道是否是被防火墙 ban 掉的端口
那么用 mmsacn 作为第一层的预处理是很好用的
2. masscan 的安装
准备 (这里不提倡使用yum,yum的版本比较低 )
- git 工具
- c 编译环境
- 克隆、编译
git clone https://github.com/robertdavidgraham/masscan
cd masscan
make
- 安装
make install
- 测试是否安装
masscan --version
3. masscan 的简单使用
masscan 的主要关乎性能的参数有两个
选项 | 意义 |
---|---|
/ --rate | 发送包的速率,和扫描端口速度正相关 |
/ --wait | 发送完包等待时间,和性能负相关,不过时间越久可以扫到的端口就可以越多 |
实际上,masscan 扫描速度非常快, masscan rate 1000 扫描一个 C 段(256 个 IP 地址)的主机,需要约 3-5 秒钟的时间,一般来说不用担心 masscan 性能不足的问题
- 扫描端口范围
masscan -p 1-65535 115.42.32.45
- 扫描多个不连续端口
masscan -p 32,43,5453,45 115.42.32.45
- 扫描网段
masscan -p 1-65535 10.0.0.0/16
4. Golang 使用
golang 可以通过 cmd 直接和 masscan 进行交互,这里我们直接捕获输出值
startPort := 1
endPort := 65535
portRange := fmt.Sprintf("%d-%d", startPort, endPort)
// 构建 masscan 命令
cmd := exec.Command("sudo", "masscan", ip, "-p", portRange, "--rate", "50k")
// 获取命令输出
var out bytes.Buffer
cmd.Stdout = &out
err := cmd.Run()
var stderr bytes.Buffer
cmd.Stderr = &stderr
if err != nil {
fmt.Printf("Error running masscan: %v\n", err)
return nil, err
}
fmt.Printf(out)
通过golang 结合命令行可以很方便的对 masscan 结果进行处理
我们也可以把它解析为数组
func parseMasscanOutput(output string) []int {
var openPorts []int
re := regexp.MustCompile(`port (\d+)/tcp`)
matches := re.FindAllStringSubmatch(output, -1)
for _, match := range matches {
if len(match) > 1 {
portStr := match[1]
portInt, err := strconv.Atoi(portStr)
if err != nil {
fmt.Printf("Error running masscan: %v\n", err)
continue
}
openPorts = append(openPorts, portInt)
}
}
return openPorts
}
5. 总结
masscan 是非常高性能的端口扫描工具(高到不需要考虑优化),我们可以使用masscan 进行一次扫描后,再后续使用其他工具进行处理