识别远程主机的操作系统是主机安全扫描的起始工作。在对远程主机进行漏洞扫描之前,首先对其进行操作系统扫描,可以减小漏洞扫描的范围,缩小工作量,能够达到事半功倍的效果。现在流行的几款安全渗透测试工具,比如Metasploit、OpenVAS、Nessus中,都提供了远程操作系统识别的功能。

远程操作系统识别的原理其实很简单:相同的协议栈(TCP/IP),不同的操作系统实现的方式不同,导致对特定格式的数据包有不同的响应,这里说的响应既指是否响应,又包括响应的数据包内容。这种响应差异,成为操作系统栈指纹。我们最熟悉的,用ICMP协议Ping同一局域网内的不同主机,屏幕上回显的TTL值会因不同主机操作系统的不同而不同,甚至不同的主机,即使相同的操作系统,但因为系统版本、防火墙、补丁等细节不同,回显的TTL值也会不同。

1

2

注:选择ping局域网中主机的原因是因为,以太网中两台主机进行通信中间没有跳点,也就是说,TTL值是从发送端发出的原始值。直接ping Internet上的主机,虽然TTL值也有不同,但是不能直接显示发送端的原始值。不过这个值会接近2^n(1≤n≤8)。

 

一些机构,将不同操作系统的协议栈指纹采集,制作了一个庞大的协议栈指纹库。探测发起方有目的的发送一些特定格式的数据包,或者嗅探捕获一定格式的数据包,将返回结果与协议栈指纹库进行匹配,以此来判断远程操作系统。目前NMAP所建立并使用的nmap-os-db栈指纹数据库识别度非常高,并且能够将准确度量化,以百分比的形式给出相似度。

3

windows 7 栈指纹

4

Linux Kernel的栈指纹

注:nmap-os-db位于nmap的安装目录的根目录下,可以用记事本打开查看修改。

 

以上为远程操作系统识别的技术原理。对于远程操作系统识别的实现方式,可以分为主动识别和被动识别。

主动识别即探测发起方构造特定的数据包,将其发送到待探测主机,并接收待探测主机返回的数据包。主动识别效率比较高,用时比较少,但因为构造的这些数据包中,很多数据包是异常包,容易触发局域网中的IDS的规则。Nmap就是利用这种识别方式。

5

被动识别是利用嗅探的原理,隐藏在网络中,静默的收集带探测主机的数据包,并不向待探测主机发送数据包。这种识别方式隐秘性非常高,但速度很慢,并且受到嗅探技术的限制,不能直接探测Internet上的主机。

 

 

远程操作系统主动识别的程序设计:

刚刚完成的一个项目的其中一个模块就是需要完成这样的需求。实现环境是在Ubuntu 11.04,kernel 3.0.

在Nmap官网http://nmap.org/book/osdetect.html,有上面的nmap-os-db栈指纹数据库截图中的各个字段所表示的含义,以及用何种格式的数据包探测。Nmap发送一组探测数据包,包括IP raw,TCP、UDP、ICMP,将这些数据包的返回数据包的特定字段提取出,与nmap-os-db的条目依次匹配。匹配度最高的条目,就是最有可能的操作系统。

发送数据包利用的libnet库。libnet是一个构造和发送数据包的开发库。利用libnet可以只指定数据包中字段的值,而不用自己真正的构造数据包,运算校验和,非常方便。Google搜索貌似有两个Libnet,之前找了好久,http://packetfactory.openwall.net/projects/libnet/,是这个网址的。

接收数据包利用的LibPcap库。大名鼎鼎的数据包捕获数据库。Windows下的版本叫做WinPcap,Wireshark就是利用这个库开发的。

将捕获数据包的特征字段与数据库进行匹配是比较麻烦的事情。可以参考Nmap的设计,也可以自己写。我就是自己写了一个,但因为项目原因就不公开贴在博客里了。

libnet和libPcap理论上都可以直接移植到windows平台下。但是利用libnet发送IP_RAW类型的TCP的数据包会发送失败,原因是这种类型数据包的实现方式是利用原始套接字,而windows XP SP2之后,微软就封杀了TCP原始套接字(据说是因为震荡波病毒)。可以自己重写一下libnet的发送函数,将发送改成利用WinPcap的pcap_sendpkt()函数。WinPcap是安装了旁路驱动,并没有一同被封杀。

上面那种方法或许有些麻烦,代码量也比较大。当然有简单的方法:把Nmap的输入输出重定向到自己的软件中,通过分析Nmap的输出结果来得到识别结果。

 

 

上述介绍的远程操作系统识别是最通用的技术,还可以通过其他的手段进行操作系统识别,比如NetBios,Snmp等。这些介绍网上有好多,就不再赘述了。