nmap部分源码分析
字数 1565 2025-08-22 18:37:15

Nmap源码分析与关键技术解析

一、Nmap概述

Nmap(Network Mapper)是一款开源的网络探测和安全审计工具,主要用于:

  • 主机发现
  • 端口扫描
  • 服务版本检测
  • 操作系统识别
  • 脚本扫描(NSE)

二、源码结构分析

Nmap源码主要目录结构:

.github/                # GitHub问题模板
docs/                   # 文档
licenses/               # 许可证文件
mswin32/                # Windows支持
macosx/                 # macOS支持
nbase/                  # 基础库
ncat/                   # 新版nc实现
ndiff/                  # 扫描结果比较工具
nping/                  # 网络探测工具
nselib/                 # Lua脚本库
nsock/                  # 并行Socket处理库
scripts/                # 常用扫描Lua脚本
tests/                  # 测试代码
zenmap/                 # Python图形界面

三、核心执行流程

1. 主入口

main.cc中的main()函数仅调用nmap_main()(位于nmap.cc中),所有功能都在nmap_main()中有入口。

2. 扫描阶段

Nmap的10个主要扫描阶段:

  1. 脚本预扫描(可选)
  2. 目标枚举
  3. 主机发现(ping扫描)
  4. 反向DNS解析
  5. 端口扫描
  6. 版本检测
  7. 操作系统检测
  8. Traceroute
  9. 脚本扫描
  10. 输出

四、关键技术实现

1. 端口扫描技术

(1) SYN扫描(半开放扫描)

if (o.synscan)
    ultra_scan(Targets, &ports, SYN_SCAN);

实现原理:

  • 发送SYN包
  • 收到SYN/ACK则认为端口开放
  • 收到RST则认为端口关闭
  • 不完成完整TCP三次握手

(2) TCP连接扫描

if (o.connectscan)
    ultra_scan(Targets, &ports, CONNECT_SCAN);

实现原理:

  • 使用系统connect()函数建立完整TCP连接
  • 更可靠但速度较慢

(3) UDP扫描

if (o.udpscan)
    ultra_scan(Targets, &ports, UDP_SCAN);

实现原理:

  • 发送UDP数据包
  • 根据ICMP端口不可达消息判断端口状态

(4) 空闲扫描(Idle Scan)

if (o.idlescan) {
    for (targetno = 0; targetno < Targets.size(); targetno++) {
        o.current_scantype = IDLE_SCAN;
        idle_scan(Targets[targetno], ports.tcp_ports, ports.tcp_count, 
                 o.idleProxy, &ports);
    }
}

特点:

  • 利用僵尸主机的IP ID递增特性
  • 实现完全欺骗扫描
  • 不暴露扫描者真实IP

(5) FTP弹跳扫描

if (o.bouncescan) {
    for (targetno = 0; targetno < Targets.size(); targetno++) {
        o.current_scantype = BOUNCE_SCAN;
        if (ftp.sd <= 0) ftp_anon_connect(&ftp);
        if (ftp.sd > 0)
            bounce_scan(Targets[targetno], ports.tcp_ports, 
                       ports.tcp_count, &ftp);
    }
}

原理:

  • 利用FTP协议的PORT/EPRT命令特性
  • 通过FTP服务器代理连接第三方主机

2. 主机发现技术

void sendPingProbe(UltraScanInfo *USI, HostScanStats *hss) {
    switch(pingprobe->type) {
        case PS_CONNECTTCP: sendConnectScanProbe(...); break;
        case PS_TCP: case PS_UDP: case PS_SCTP: case PS_PROTO: 
        case PS_ICMP: sendIPScanProbe(...); break;
        case PS_ARP: sendArpScanProbe(...); break;
        case PS_ND: sendNDScanProbe(...); break;
    }
}

支持的探测方式:

  • TCP连接探测
  • ICMP Echo请求
  • ARP探测(局域网)
  • ND探测(IPv6邻居发现)
  • UDP探测
  • SCTP探测

3. 服务版本检测

if (o.servicescan) {
    o.current_scantype = SERVICE_SCAN;
    service_scan(Targets);
}

实现流程:

  1. 初始化所有探测(AllProbes::service_scan_init()
  2. 创建服务组(ServiceGroup
  3. 启动探测(launchSomeServiceProbes()
  4. 处理结果(processResults()

关键技术:

  • 多协议支持(TCP/UDP/SSL)
  • 并行探测
  • 响应匹配(精确匹配和模糊匹配)

4. 操作系统检测

if (o.osscan) {
    OSScan os_engine;
    os_engine.os_scan(Targets);
}

检测方法:

  • TCP/IP协议栈指纹识别
  • 响应分析
  • 支持IPv4和IPv6

5. 路由追踪

if (o.traceroute)
    traceroute(Targets);

实现分为:

  • 直接连接目标(traceroute_direct
  • 远程目标(traceroute_remote

技术要点:

  • TTL递增
  • ICMP/UDP/TCP探测
  • 跳数分析

6. Nmap脚本引擎(NSE)

#ifndef NOLUA
if (o.script || o.scriptversion) {
    script_scan(Targets, SCRIPT_SCAN);
}
#endif

关键组件:

  • Lua虚拟机集成
  • 脚本分类(pre-scan/scan/post-scan)
  • 丰富的脚本库(nselib/

五、关键数据结构

1. 扫描目标表示

class Target {
    // 目标主机信息
    // 端口状态
    // 扫描结果
};

2. 端口列表

struct scan_lists {
    int tcp_count;
    unsigned short *tcp_ports;
    int udp_count;
    unsigned short *udp_ports;
    // 其他协议端口
};

3. 扫描统计

class HostScanStats {
    // 主机扫描状态
    // 探测计数
    // 超时处理
};

六、网络通信实现

1. 原始套接字

rawsd = nmap_raw_socket();

2. 数据包构造

// TCP包构造
u8 *build_tcp_raw(const struct in_addr *source, const struct in_addr *victim, 
                 int ttl, u16 ipid, u8 tos, bool df, const u8 *ipopt, 
                 int ipoptlen, u16 sport, u16 dport, u32 seq, u32 ack, 
                 u8 reserved, u8 flags, u16 window, u16 urp, 
                 const u8 *tcpopt, int tcpoptlen, const char *data, 
                 u16 datalen, u32 *packetlen);

3. 发送接收

send_ip_packet(USI->rawsd, ethptr, hss->target->TargetSockAddr(), 
              packet, packetlen);

七、性能优化技术

  1. 并行扫描控制(o.max_parallelism
  2. 端口随机化(o.randomize_ports
  3. 常用端口优先(random_port_cheat
  4. 超时动态调整
  5. 速率控制

八、扩展开发指南

1. 添加新扫描类型

  1. stype枚举中添加新类型
  2. 实现对应的ultra_scan处理
  3. 添加命令行参数支持

2. 开发NSE脚本

  1. 使用Lua编写脚本
  2. 放置在scripts/目录
  3. 实现必要的回调函数

九、安全注意事项

  1. 权限要求(原始套接字需要root/Administrator)
  2. 扫描行为可能触发安全设备警报
  3. 遵守当地法律法规

十、总结

Nmap通过其模块化设计和丰富的功能集,成为网络探测和安全评估的瑞士军刀。理解其源码可以帮助:

  • 深入掌握网络扫描原理
  • 定制化开发专用扫描工具
  • 更好地防御网络探测行为
  • 学习高质量网络编程实践
Nmap源码分析与关键技术解析 一、Nmap概述 Nmap(Network Mapper)是一款开源的网络探测和安全审计工具,主要用于: 主机发现 端口扫描 服务版本检测 操作系统识别 脚本扫描(NSE) 二、源码结构分析 Nmap源码主要目录结构: 三、核心执行流程 1. 主入口 main.cc 中的 main() 函数仅调用 nmap_main() (位于 nmap.cc 中),所有功能都在 nmap_main() 中有入口。 2. 扫描阶段 Nmap的10个主要扫描阶段: 脚本预扫描(可选) 目标枚举 主机发现(ping扫描) 反向DNS解析 端口扫描 版本检测 操作系统检测 Traceroute 脚本扫描 输出 四、关键技术实现 1. 端口扫描技术 (1) SYN扫描(半开放扫描) 实现原理: 发送SYN包 收到SYN/ACK则认为端口开放 收到RST则认为端口关闭 不完成完整TCP三次握手 (2) TCP连接扫描 实现原理: 使用系统 connect() 函数建立完整TCP连接 更可靠但速度较慢 (3) UDP扫描 实现原理: 发送UDP数据包 根据ICMP端口不可达消息判断端口状态 (4) 空闲扫描(Idle Scan) 特点: 利用僵尸主机的IP ID递增特性 实现完全欺骗扫描 不暴露扫描者真实IP (5) FTP弹跳扫描 原理: 利用FTP协议的PORT/EPRT命令特性 通过FTP服务器代理连接第三方主机 2. 主机发现技术 支持的探测方式: TCP连接探测 ICMP Echo请求 ARP探测(局域网) ND探测(IPv6邻居发现) UDP探测 SCTP探测 3. 服务版本检测 实现流程: 初始化所有探测( AllProbes::service_scan_init() ) 创建服务组( ServiceGroup ) 启动探测( launchSomeServiceProbes() ) 处理结果( processResults() ) 关键技术: 多协议支持(TCP/UDP/SSL) 并行探测 响应匹配(精确匹配和模糊匹配) 4. 操作系统检测 检测方法: TCP/IP协议栈指纹识别 响应分析 支持IPv4和IPv6 5. 路由追踪 实现分为: 直接连接目标( traceroute_direct ) 远程目标( traceroute_remote ) 技术要点: TTL递增 ICMP/UDP/TCP探测 跳数分析 6. Nmap脚本引擎(NSE) 关键组件: Lua虚拟机集成 脚本分类(pre-scan/scan/post-scan) 丰富的脚本库( nselib/ ) 五、关键数据结构 1. 扫描目标表示 2. 端口列表 3. 扫描统计 六、网络通信实现 1. 原始套接字 2. 数据包构造 3. 发送接收 七、性能优化技术 并行扫描控制( o.max_parallelism ) 端口随机化( o.randomize_ports ) 常用端口优先( random_port_cheat ) 超时动态调整 速率控制 八、扩展开发指南 1. 添加新扫描类型 在 stype 枚举中添加新类型 实现对应的 ultra_scan 处理 添加命令行参数支持 2. 开发NSE脚本 使用Lua编写脚本 放置在 scripts/ 目录 实现必要的回调函数 九、安全注意事项 权限要求(原始套接字需要root/Administrator) 扫描行为可能触发安全设备警报 遵守当地法律法规 十、总结 Nmap通过其模块化设计和丰富的功能集,成为网络探测和安全评估的瑞士军刀。理解其源码可以帮助: 深入掌握网络扫描原理 定制化开发专用扫描工具 更好地防御网络探测行为 学习高质量网络编程实践