为何Windows下Golang TCP扫描误报scanme.nmap.org的25端口开放?
Windows与Linux下Go端口扫描工具检测25端口结果差异的原因分析
问题背景
我正在通过《Blackhat-Go》学习使用Golang开发黑客工具,并在Windows和Linux系统上对scanme.nmap.org进行TCP端口扫描,使用的代码如下:
package main import ( "fmt" "net" "sort" ) func worker(ports, result chan int) { for port := range ports { address := fmt.Sprintf("scanme.nmap.org:%d", port) conn, err := net.Dial("tcp", address) if err != nil { result <- 0 continue } conn.Close() result <- port } } func main() { ports := make(chan int, 100) result := make(chan int) var openport []int for i := 0; i < cap(ports); i++ { go worker(ports, result) } go func() { for i := 0; i < 1024; i++ { ports <- i } }() for i := 0; i < 1024; i++ { port := <-result if port != 0 { openport = append(openport, port) } } close(ports) close(result) sort.Ints(openport) for _, value := range openport { fmt.Printf("%d open\n", value) } }
运行结果差异
- Windows系统运行输出:
22 open 25 open 80 open 110 open
- Linux系统运行输出:
22 open 80 open 110 open
- 使用NMAP扫描结果显示该25端口状态为Filtered:
25/tcp filtered smtp
请问为何Windows系统下会检测到该端口开放?
原因分析
核心差异来自Windows与Linux的TCP栈行为不同:
当目标端口处于Filtered状态时,网络防火墙会直接丢弃SYN请求包,不返回任何响应(既无SYN-ACK也无RST)。此时:
- Linux系统:
net.Dial严格遵循TCP三次握手逻辑,在多次重试仍未收到响应后,会返回连接超时错误,代码因此判定端口未开放。 - Windows系统:Windows TCP栈在连接超时前,可能将未完成的半连接状态误判为"连接已建立",导致
net.Dial返回成功,进而让代码认为端口开放。
改进建议
- 添加明确的超时控制
使用net.DialTimeout替代net.Dial,指定合理的超时时间(如3秒),消除系统栈默认超时逻辑的影响,让跨系统扫描结果更一致:
// 需要先在import中添加 "time" conn, err := net.DialTimeout("tcp", address, 3*time.Second)
- 精准区分端口状态
通过解析错误类型,区分Closed、Filtered和Open端口:
- 若错误为
*net.OpError且底层错误是syscall.ECONNREFUSED,说明端口Closed; - 若错误是超时类错误,说明端口大概率Filtered;
- 只有成功建立连接,才判定端口Open。
内容的提问来源于stack exchange,提问作者L2ksy0d
相关产品推荐
相关产品推荐

