Nmap第四个核心功能是操作系统侦测,包括识别出操作系统类型、版本号、目标机硬件平台类型及附加信息(如TCP序号产生方式、IPID产生方式、启动时间等)。目前Nmap 拥有丰富的系统指纹数据库 (nmap-os-db),能够识别出2600多种操作系统与设备类型。

如上图对网关进行操作系统扫描,可以看到探测出的结果:由MAC地址推断网关是TP-LINK公司产品,设备类型是WAP(无线接入点,即无线路由器)或打印机,运行的是Wind River公司的VxWorks操作系统,OS CPE描述为cpe:/o:windriver:vxworks,网络距离是一跳(1 hop)。

1   简单引入

  下面从OS扫描原理、命令行选项角度进行简单回顾。

1.1  扫描原理

  Nmap使用TCP/IP协议栈指纹来识别不同的操作系统和设备。在RFC规范中,有些地方对TCP/IP的实现并没有强制规定,由此不同的TCP/IP方案中可能都有自己的特殊的处理方式。Nmap主要是根据这些细节上的差异来判断操作系统的类型的。

具体实现方式如下:

  • Nmap内部包含了2600多已知系统的指纹特征(在文件nmap-os-db文件中)。将此指纹数据库作为进行指纹对比的样本库。
  • 分别挑选一个open和closed的端口,向其发送经过精心设计的TCP/UDP/ICMP数据包,根据返回的数据包生成一份系统指纹。
  • 将探测生成的指纹与nmap-os-db中指纹进行对比,查找匹配的系统。如果无法匹配,以概率形式列举出可能的系统。

1.2  命令行选项

  OS侦测的用法简单,Nmap提供的命令比较少。

  -O: 指定Nmap进行OS侦测。--osscan-limit: 限制Nmap只对确定的主机的进行OS探测(至少需确知该主机分别有一个open和closed的端口)。--osscan-guess: 大胆猜测对方的主机的系统类型。由此准确性会下降不少,但会尽可能多为用户提供潜在的操作系统。

2   实现框架

  下面主要从文件组织、核心类、代码流程的角度来分析操作系统侦测的实现框架。

2.1  文件组织

2.1.1 流程文件

  操作系统侦测功能主要在os_scan2.h/os_scan2.cc文件中实现(os_scan.h/ os_scan.cc是第一代操作系统侦测的代码,目前默认不使用其流程);IPv6的操作系统探测过程主要FPengine.h/FPengine.cc文件中实现。

2.1.2 数据库文件

  Nmap操作系统指纹数据库文件nmap-os-db,里面包含了2600多种操作系统与设备的指纹。所谓的指纹,即由特定的回复包提取出的数据特征。

  下面摘取其中片段,简单了解其结构。

#Windows 7 Professional Version 6.1 Build 7600Fingerprint MicrosoftWindows 7 ProfessionalClassMicrosoft | Windows | 7 | general purposeCPEcpe:/o:microsoft:windows_7::professionalSEQ(SP=FC-106%GCD=1-6%ISR=108-112%TI=I%II=I%SS=S%TS=7)OPS(O1=M5B4NW8ST11%O2=M5B4NW8ST11%O3=M5B4NW8NNT11%O4=M5B4NW8ST11%O5=M5B4NW8ST11%O6=M5B4ST11)WIN(W1=2000%W2=2000%W3=2000%W4=2000%W5=2000%W6=2000)ECN(R=Y%DF=Y%T=7B-85%TG=80%W=2000%O=M5B4NW8NNS%CC=N%Q=)T1(R=Y%DF=Y%T=7B-85%TG=80%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=N)T5(R=Y%DF=Y%T=7B-85%TG=80%W=2000%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=N)T7(R=N)U1(DF=N%T=7B-85%TG=80%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(DFI=N%T=7B-85%TG=80%CD=Z)

  以上是Windows 7 professional版本的指纹特征。

  第一行为注释行,说明此指纹对应的操作系统与版本。

  Fingerprint关键字定义一个新的指纹,紧随其后的是指纹名字Microsoft Windows 7Professional。

  Class行用于指定该指纹所属的类别,依次指定该系统的vendor(生产厂家), OS family(系统类别), OS generation(第几代操作系统), and device type(设备类型),如此处Vendor为Microsoft, OS family为Windows,OS generation为7,设备类型为通用设备(普通PC或服务器)。

  接下来是CPE行,此行非常重要,使用CPE(Common Platform Enumeration,通用平台枚举)格式描述该系统的信息。以标准的CPE格式来描述操作系统类型,便于Nmap与外界信息的交换,比如可以很快从网上开源数据库查找到CPE描述的操作系统具体信息。

  关于CPE标准介绍:http://cpe.mitre.org/

  此处作为指纹描述字段的CPE格式如下:

cpe:/<part>:<vendor>:<product>:<version>:<update>:<edition>:<language>

  接下来从SEQ到IE的13行都是具体指纹数据描述行,在对比指纹时,就是对比这13行里面的具体数据,如果匹配则目标机为指纹所描述的系统类型。

  SEQ描述顺序产生方式;OPS描述TCP包中可选字段的值;WIN描述TCP包的初始窗口大小;ECN(Explicit Congestion Notification)描述TCP明确指定拥塞通知时的特征;T1-T7描述TCP回复包的字段特征;U1描述向关闭的UDP发包产生的回复的特征;IE描述向目标机发送ICMP包产生的特征。

2.2  核心类

  下面简要介绍操作系统扫描部分涉及到的Class。

2.2.1 OSScan

  OSScan是管理操作系统扫描过程的类,将IPv4和IPv6的操作系统扫描过程封装起来,为Nmap主程序提供统一的调用接口os_scan()。

  以下是该类主要的内容:

  1. 提供操作系统扫描接口os_scan()
  2. 提供重置函数接口(初始化必要的变量)。
  3. 保存ip的协议版本
  4. 执行分块与扫描过程,确定并发执行的数量
  5. 针对IPv4进行操作系统扫描
  6. 针对IPv6进行操作系统扫描
/** This is the class that performs OS detection (both IPv4 and IPv6).* Using it is simple, just call os_scan() passing a list of targets.* The results of the detection will be stored inside the supplied* target objects. */
class OSScan {private:int ip_ver;             /* IP version for the OS Scan (4 or 6) */int chunk_and_do_scan(std::vector<Target *> &Targets, int family);int os_scan_ipv4(std::vector<Target *> &Targets);int os_scan_ipv6(std::vector<Target *> &Targets);public:OSScan();~OSScan();void reset();int os_scan(std::vector<Target *> &Targets);
};
 

2.2.2 OsScanInfo

  OsScanInfo类整体管理全部主机的扫描过程,其中维护操作系统扫描未完成列表。

  下面是其中主要的内容:

  1. 未完成扫描列表std::list<HostOsScanInfo *>incompleteHosts。
  2. 扫描起始时间starttime.
  3. 未完成列表访问接口,读取总数、获取下一个、 查找主机、重置迭代器。
  4. 移除已经完成的主机。

2.2.3 HostOsScanInfo

  HostOsScanInfo管理单个主机的操作系统扫描的信息。

  主要包含以下具体内容:

  1. 对应的目标机Target *target.
  2. 被包含的OsScanInfo对象地址。
  3. 当前主机产生的指纹信息FingerPrint **FPs
  4. 记录是否超时、是否完成
  5. 单个OS扫描每一轮(one round)的统计信息HostOsScanStats *hss。(同一个主机可能被扫描多个回合,所以这里使用该对象来管理每一轮扫描的信息)
  6. 指纹扫描结果与匹配情况。
 
/* The overall os scan information of a host:*  - Fingerprints gotten from every scan round;*  - Maching results of these fingerprints.*  - Is it timeout/completed?*  - ... */
class HostOsScanInfo {public:HostOsScanInfo(Target *t, OsScanInfo *OSI);~HostOsScanInfo();Target *target;       /* The target                                  */FingerPrintResultsIPv4 *FPR;OsScanInfo *OSI;      /* The OSI which contains this HostOsScanInfo  */FingerPrint **FPs;    /* Fingerprints of the host                    */FingerPrintResultsIPv4 *FP_matches; /* Fingerprint-matching results      */bool timedOut;        /* Did it time out?                            */bool isCompleted;     /* Has the OS detection been completed?        */HostOsScanStats *hss; /* Scan status of the host in one scan round   */
};

2.2.4 HostOsScanStats

  HostOsScanStats管理每个主机每一轮OS扫描的统计信息。

  内容概括起来如下:

  1. 扫描探测包的管理
  2. 以太网信息管理
  3. 指纹信息的管理
  4. TCP序号、IPID、启动时间等信息管理
  5. 其他杂项信息

2.2.5OFProbe

  OFProbe管理OS扫描过程需要的探测包信息,该对象中本身只包含用于构建探测包的关键属性,而不包含探测包本身。另外该对象也包含时序信息。

该对象主要在HostOsScanStats中使用。

2.3  代码流程

  在nmap.cc中的nmap_main()函数如果检测用户配置了OS扫描选项(或-A选项),那么将启动扫描系统扫描功能。Nmap将会创建OSScan对象,并调用OSScan::os_scan()进入详细的探测过程。

2.3.1代码流程图

2.3.2流程解析

  OSScan::os_scan()的执行流程非常简单,只有短短30行代码。

  首先将传入的Targets参数依据地址类型划分两个小组,IPv4和IPv6。因为对于两类的地址扫描的方式不同。

  随后调用os_scan_ipv4()做IPv4的操作系统扫描过程。

  然后调用os_scan_ipv6()做IPv6的操作系统扫描过程。

  判断ipv4和ipv6两类操作系统扫描执行的结果,返回最终结果。

  因为os_scan_ipv4()才是完成ipv4类的操作系统扫描真正的地方,这里我们也简要描述其过程。

  首先,定义未匹配主机管理列表list<HostOsScanInfo *>unMatchedHosts,用于管理超时未匹配的主机。

  随后,初始化扫描性能变量scan_perforamance_vars,以便对整个操作系统扫描过程时序与性能进行控制。

  创建OsScanInfo对象、并初始化必要的时间值。

  begin_sniffer()打开libpcap,设置相应filter,进行回复包的监听。

  随后进入主循环过程,直到所有的主机都完成扫描,才退出循环。下面是主要循环步骤:

  A.      根据进行的扫描次数,适当休眠

  B.       准备该轮扫描的所需的环境,清理垃圾数据并初始化必要的变量

  C.       做顺序产生测试(Sequence generationtests),提取指纹的SEQ/OPS/WIN/T1几行数据。

  D.      做TCP/UDP/ICMP综合探测,提取指纹数据。

  E.       处理此轮探测的结果,匹配相应的系统指纹,移除已完成。

  F.       移除超时不匹配的主机到unMatchedHosts列表中。

  退出循环后,将unMatchedHosts列表中主机移动到未完成列表,然后统一对其进行最接近指纹匹配。

  返回扫描执行结果。

3   代码注释

/* This function performs the OS detection. It processes the supplied list of* targets and classifies it into two groups: IPv4 and IPv6 targets. Then,* OS detection is carried out for those two separate groups. It returns* OP_SUCCESS on success or OP_FAILURE in case of error. */
int OSScan::os_scan(vector<Target *> &Targets) {vector<Target *> ip4_targets; ///IPv4类型地址的目标机vector<Target *> ip6_targets; ///IPv6类型地址的目标机int res4 = OP_SUCCESS, res6 = OP_SUCCESS;/* Make sure we have at least one target */if (Targets.size() <= 0)return OP_FAILURE;/* Classify targets into two groups: IPv4 and IPv6 *////先根据地址将目标机划分到不同向量里,因为两类目标机扫描过程不同for (size_t i = 0; i < Targets.size(); i++) {if (Targets[i]->af() == AF_INET6)ip6_targets.push_back(Targets[i]);elseip4_targets.push_back(Targets[i]);}/* Do IPv4 OS Detection *////在os_scan_ipv4()函数中具体实现IPv4的操作系统探测的过程if (ip4_targets.size() > 0)res4 = this->os_scan_ipv4(ip4_targets);/* Do IPv6 OS Detection *////在os_scan_ipv6()函数中具体实现IPv6的操作系统探测的过程if (ip6_targets.size() > 0)res6 = this->os_scan_ipv6(ip6_targets);/* If both scans were succesful, return OK */if (res4 == OP_SUCCESS && res6 == OP_SUCCESS)return OP_SUCCESS;elsereturn OP_FAILURE;
}/* Performs the OS detection for IPv4 hosts. This method should not be called* directly. os_scan() should be used instead, as it handles chunking so* you don't do too many targets in parallel *////IPv4的操作系统探测的实现函数,由os_scan()来调用。
int OSScan::os_scan_ipv4(vector<Target *> &Targets) {int itry = 0;/* Hosts which haven't matched and have been removed from incompleteHosts because* they have exceeded the number of retransmissions the host is allowed. */list<HostOsScanInfo *> unMatchedHosts; ///记录超时或超过最大重传而未匹配的主机扫描信息/* Check we have at least one target*/if (Targets.size() == 0) {return OP_FAILURE;}perf.init();///初始化扫描性能变量///操作系统扫描的管理对象,维护未完成扫描列表std::list<HostOsScanInfo *> incompleteHosts;OsScanInfo OSI(Targets);if (OSI.numIncompleteHosts() == 0) {/* no one will be scanned */return OP_FAILURE;}///设置起始时间与超时OSI.starttime = o.TimeSinceStart();startTimeOutClocks(&OSI);///创建HOS对象,负责管理单个主机的具体扫描过程HostOsScan HOS(Targets[0]);/* Initialize the pcap session handler in HOS *////打开libpcap,设置对应的BPF filter,以便接收目标的回复包begin_sniffer(&HOS, Targets);while (OSI.numIncompleteHosts() != 0) {if (itry > 0)sleep(1);if (itry == 3)usleep(1500000); /* Try waiting a little longer just in case it matters */if (o.verbose) {char targetstr[128];bool plural = (OSI.numIncompleteHosts() != 1);if (!plural) {(*(OSI.incompleteHosts.begin()))->target->NameIP(targetstr, sizeof(targetstr));} else Snprintf(targetstr, sizeof(targetstr), "%d hosts", (int) OSI.numIncompleteHosts());log_write(LOG_STDOUT, "%s OS detection (try #%d) against %s\n", (itry == 0)? "Initiating" : "Retrying", itry + 1, targetstr);log_flush_all();}///准备第itry轮的OS探测:删除陈旧信息、初始化必要变量startRound(&OSI, &HOS, itry);///执行顺序产生测试(发送6个TCP探测包,每隔100ms一个)doSeqTests(&OSI, &HOS);///执行TCP/UDP/ICMP探测包测试doTUITests(&OSI, &HOS);///对该轮探测的结果做指纹对比,获取OS扫描信息endRound(&OSI, &HOS, itry);///将超时未匹配的主机移动到unMatchedHosts列表中expireUnmatchedHosts(&OSI, &unMatchedHosts);itry++;}/* Now move the unMatchedHosts array back to IncompleteHosts *////对没有找到匹配的主机,将之移动的未完成列表,并查找出最接近的指纹(以概率形式展现给用户)if (!unMatchedHosts.empty())OSI.incompleteHosts.splice(OSI.incompleteHosts.begin(), unMatchedHosts);if (OSI.numIncompleteHosts()) {/* For hosts that don't have a perfect match, find the closest fingerprint* in the DB and, if we are in debugging mode, print them. */findBestFPs(&OSI);if (o.debugging > 1)printFP(&OSI);}return OP_SUCCESS;
}

Nmap源码分析(操作系统扫描)相关推荐

  1. Nmap源码分析(脚本引擎)

    Nmap提供了强大的脚本引擎(NSE),以支持通过Lua编程来扩展Nmap的功能.目前脚本库已经包含300多个常用的Lua脚本,辅助完成Nmap的主机发现.端口扫描.服务侦测.操作系统侦测四个基本功能 ...

  2. Nmap源码分析(基本框架)

    Nmap是一款非常强大的开源扫描工具.自己在使用过程中忍不住想仔细阅读一下它的源码.源码里面汇集了众多安全专家的精巧设计与优雅写法,读起来令人心旷神怡而又受益匪浅. 这里我们以阅读nmap6.0的代码 ...

  3. Nmap源码分析(服务与版本扫描)

    在进行端口扫描后,Nmap可以进一步探测出运行在端口上的服务类型及应用程序的版本.目前Nmap可以识别几千种服务程序的签名(Signature),覆盖了180多种应用协议.比如,端口扫描检测到80端口 ...

  4. Nmap源码分析(端口扫描)

    端口扫描是Nmap的核心功能,用于确定目标机的端口状态(开放.关闭.过滤等),也为Nmap的服务与版本扫描.OS扫描.脚本扫描提供基本的指引信息.所以,深入理解端口扫描的实现对分析其他的扫描方式很有帮 ...

  5. Nmap源码分析(主机发现)

    ​Nmap在进行真正的端口扫描之前,通常需要确定目标主机是否在线(主机发现过程),以免发送大量探测包到不在线的主机.主机发现作为Nmap的基本功能之一,用户也可以单独运用.例如,仅仅需要确定局域网内哪 ...

  6. Nmap源码分析(整体架构)

    整体架构 功能目录 docs :相关文档 libdnet-stripped :开源网络接口库 liblinear:开源大型线性分类库 liblua:开源Lua脚本语言库 libnetutil:基本的网 ...

  7. Android wpa_supplicant源码分析--bss扫描结果

    1 扫描方式 手机扫描结果的获取有两种方式:被动和主动 1,AP隔固定时间会发送Beacon帧,Beacon帧中有AP的SSID BSSID等基本信息,手机接收到Beacon帧就认为搜索到该AP创建的 ...

  8. Wifi模块—源码分析Wifi热点扫描2(Android P)

    一 前言 这次接着讲Wifi工程流程中的Wifi热点扫描过程部分的获取扫描结果的过程,也是Wifi扫描过程的延续,可以先看前面Wifi扫描的分析过程. Wifi模块-源码分析Wifi热点扫描(Andr ...

  9. Wifi模块—源码分析Wifi热点扫描(Android P)

    一 前言 这次接着讲Wifi工程流程中的Wifi热点查找过程,也是Wifi启动的过程延续,Wifi启动过程中会更新Wifi的状态,框架层也有相应广播发出,应用层接收到广播后开始进行热点的扫描.可以先看 ...

最新文章

  1. Python自动化开发之基础篇--Day1
  2. Kubernetes 弹性伸缩全场景解析 (四)- 让核心组件充满弹性
  3. 【Lucene4.8教程之三】搜索
  4. 在IDEA中将SpringBoot项目打包成jar包的方法 不要用 在上面有可以用的
  5. Java框架体系架构的知识,轻松拿下offer
  6. 智慧交通day02-车流量检测实现04:卡尔曼滤波器
  7. Mysql总结_02_mysql数据库忘记密码时如何修改
  8. 春晚红包:挺住的百度和崩坏的应用商店
  9. 机器学习TP FP FN TN评价指标
  10. 搭乘百度语音识别技术,录音啦识别率最高可达95%
  11. 八大梦境提醒的你疾病所在 - 健康程序员,至尚生活!
  12. mssql差异备份获得的webshell的个人体会
  13. Python使用 opencv对CT图进行医学处理
  14. 易中天:望子成人,而非望子成龙
  15. vue项目打包后index.html文件打开空白
  16. linux 查看 man 路径配置文件 man.config,linux中的man(zz)
  17. php route,FastRoute
  18. 服务器ping返回信息,如何ping服务器线路?ping命令的用法
  19. 苏州新闻网V2.0 新版上线
  20. 运营策略实验最小样本量的确定

热门文章

  1. Python 进阶_OOP 面向对象编程_类和继承
  2. 【原创】 PostgreSQL 实现MySQL 的auto_increment 字段
  3. Linux下root修改密码报错解决方案
  4. The Power of Ten – Rules for Developing Safety Critical Code
  5. Sql Server 调用DLL
  6. postman使用介绍
  7. Webpack构建library时的踩坑经历
  8. MySQL数据表的创建、查看、插入
  9. Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤...
  10. Scala 学习笔记(1)