当前指纹问题Nmap不是第一个用TCP/IP指纹辨识OS的程序。Johan的通用的IRC欺骗
程序sirc包括了非常基本的指纹技术从版本3 (或更早)开始。它尝
试把主机分为 "Linux","4.4BSD", "Win95", 或 "Unknown"几类通过
几个简单TCP标志测试。
另一个这样的程序是checkos,作者Shok对版本7终于有了信心在今年
一月公开发行。指纹技术和SIRC的完全一样,甚至_代码_都有许多同
样之处。Checkos 在公开发行前私下流传了很久,所以不知谁偷谁的。
但看起来谁都不信任对方。checkos增加的是telnet 标志检查,有用
但有前面说的问题。[更新:Shok写信来说checkos无意公开发行而这
就是为什么他没有找SIRC要那些代码的许可。]
Su1d也写了一个OS检查程序。他称它叫SS其版本3.11可以辨识12个不
同的OS类型。我有些偏爱它因为他许可我的nmap程序一些网络代码:)。
然后是queso 。这是最新的而且对其他程序是一个巨大的飞跃。不仅
是因为它们推出了一些新测试,而且它们是首先(就我所见)把OS指
纹_移出_代码的。其他扫描的代码象:
/* from ss */
if ((flagsfour & TH_RST) && (flagsfour & TH_ACK) && (winfour == 0) &&
(flagsthree & TH_ACK))
reportos(argv[2],argv[3],"Livingston Portmaster ComOS");
相反,queso 把这些代码移到一个配置文件显然使更易扩展而且使增
加一个OS成为在指纹文件中增加几行的简单工作。
Queso由Savage,Apostols.org的高手之一,所写。
以上所述所有问题中的一个问题是只有非常有限数量的指纹测试从而
限制了回答的详细程度。我想知道不仅是'这台机器是OpenBSD, FreeBSD,
或者NetBSD',我想确切知道它到底是那一个还有版本号。同样,我希
望看到'Solaris 2.6' 而不仅仅是'Solaris'。为此,我对一系列指纹
技术进行了研究,它们将在下一节说明。
指纹方法学
有许多许多技术可以用来定义网络栈指纹。基本上,你只要找出操作
系统间的不同并写探测器查明它们。如果你合并足够这些,你可以非
常细致的区分它们。例如nmap可以可靠分辨出Solaris 2.4 和Solaris 2.5-2.51
以及Solaris 2.6。他能分辨Linux内核2.0.30到2.0.31-34或or 2.0.35。
这有一些技术:
FIN 探测器 -- 这里我们送一个FIN包(或任何其他包不带ACK 或SYN
标记)给一个打开的端口并等待回应。正确的RFC793行为是不
响应,但许多有问题的实现例如 MS Windows, BSDI, CISCO,
HP/UX,MVS,和IRIX 发回一个RESET。许多现有工具利用这个技
术。
BOGUS 标记探测器 -- Queso 是我见过的第一个用这个聪明技术扫描
器。这个主意是设置一个未定义的TCP "标记"(64或128)在SYN
包的TCP头里。Linux机器到2.0.35之前在回应中保持这个标记。
我没有发现其他OS有这个错误。然而,一些操作系统象是复位
连接当它们得到一个SYN+ BOGUS包的时候。这一行为对辨识它
们有用。
TCP ISN 取样 -- 这个主意是找出当响应一个连接请求时由TCP 实现
所选择的初始化序列数式样。这可分为许多组例如传统的64K
(许多老UNIX机器),随机增量(新版本的Solaris, IRIX, FreeBSD,
Digital UNIX, Cray, 和许多其他的),真“随机”(Linux 2.0.*,
OpenVMS,新的AIX,等)。Windows 机器(和一些其他的)用一
个“时间相关”模型,每过一段时间ISN 就被加上一个小的固
定数。不用说,这几乎和老的64K 行为一样容易攻破。当然我
喜欢的技术是"常数"。机器总是使用确切同样的ISN :)。我已
经在3Com的集线器(用0x803)和Apple LaserWriter打印机(
用0xC7001 )上看到了。
你也可以通过例如计算其随机数的变化量,最大公约数,以及
序列数的其他函数和数之间的差异再进一步分组。
要知道ISN 的生成和安全息息相关。想了解更多情况,联络在
SDSC的“安全专家”Tsutome Shimmy Shimomura,问他所知道
的。Nmap是我所见到的第一个用它来辨识OS的程序。
不分段位 -- 许多操作系统开始在送出的一些包中设置IP的"Don't Fragment"
位。这带来多种性能上的好处(尽管它也可能是讨厌的 -- 这
就是nmap的分段扫描对Solaris机器无效的原因)。无论如何,
不是所有的OS都这样做而且另一些做的场合不同,所以通过注
意这个位我们甚至能收集目标OS的更多信息。在那两个程序中
没见过这个。
TCP 初始化窗口 -- 这只包括了检查返回包的窗口大小。较老的扫描
器简单地用一个非零窗口在RST包中来表示“BSD 4.4 族”。新
一些的如queso 和nmap则保持对窗口的精确跟踪因为它对于特定
OS基本是常数。这个测试事实上给出许多信息,因为有些可以被
唯一确定(例如,AIX 是所知唯一用0x3F25的)。在它们“完全
重写”的NT5 TCP 栈中,Microsoft 用的是0x402E。有趣的是,
这和OpenBSD 与FreeBSD 中所用的数字完全一样。
ACK 值 -- 尽管你会认为这个会完全标准,不同实现中一些情况下ACK
域的值是不同的。例如,如果你送了一个FIN|PSH|URG 到一个
关闭的TCP 端口。大多数实现会设置ACK 为你的初始序列数,
而Windows 和一些傻打印机会送给你序列数加1 。若你送一个
SYN|FIN|URG|PSH 到一个打开的端口,Windows 会非常古怪。
一些时候它送回序列号,但也有可能送回序列号加1, 甚至还
可能送回一个随机数。我们觉得奇怪,不知微软写的是些什么
代码。
ICMP 错误信息终结 -- 一些(聪明的)操作系统跟从RFC 1812的建
议限制各种错误信息的发送率。例如,Linux 内核(在net/ipv4/icmp.h)
限制目的不可达消息的生成每4 秒钟80个,违反导致一个1/4
秒的处罚。测试的一种办法是发一串包到一些随机的高UDP 端
口并计数收到的不可达消息。没见过用它的,而且实际上我也
没有把它加进nmap(除了作为UDP 端口扫描用)。这个测试会
让OS辨识多花一些时间因为需要送一批包再等它们回来。而且
对付网络丢包会很痛苦。
ICMP 消息引用 -- RFC 规定ICMP错误消息可以引用一部分引起错误
的源消息。对一个端口不可达消息,几乎所有实现只送回IP请
求头外加8 字节。然而,Solaris 送回的稍多,而Linux 更多。
这使得nmap甚至在没有对方没有监听端口的情况下认出Linux
和Solaris 主机。
ICMP 错误消息回应完整性 -- 我这个想法来自Theo De Raadt (OpenBSD
开发负责人)贴在comp.security.unix的文章。刚刚提到,机
器会把原始消息的一部分和端口不可达错误一起送回。然而一
些机器倾向于在初始化处理时用你的消息头作为“草稿纸”所
以再得到时会有些许的改动。例如,AIX 和BSDI送回一个IP“
全长”域在20字节处。一些 BSDI,FreeBSD,OpenBSD,ULTRIX,
和VAXen 改变了你送的IP ID 。因为TTL 改变而改变了检查和,
有些机器(AIX, FreeBSD, 等)送回错误的或0 检查和。总之,
nmap作9 种测试在ICMP错误上以分辨出这类细微差别。
服务类型 -- 对于ICMP端口不可达消息我察看送回包的服务类型(TOS)
值。几乎所有实现在这个ICMP错误里用0 除了Linux 用0xc0。
这不是标准的TOS 值,而是一个未使用优先域(AFAIK) 的一部
分。我不知道为什么如此,但如果他们改成0 我们还能够分辨
旧系统_而且_还能分辨出旧系统和新系统。
分段控制 -- 这是安全网络公司(现在由一帮在NAI 的Windows 用户
所拥有)的Thomas H. Ptacek喜爱的技术。它获益于事实即不
同实现经常以不同方式控制覆盖IP段。一些会用新的覆盖旧的
部分,另一些情况中旧的优先。有很多不同可能你可以用来决
定如何重组数据包。我没有加入这一特性因为没有简便的方式
发送IP分段(特别是,在Solaris 上是不允许的)。关于覆盖
段的更多信息,可以看IDS 的论文(
www.secnet.com)
TCP 选项 -- 这简直是泄漏信息的金矿。它的好处在于:
1) 这通常是可选的(哈!):) 所以并非所有实现都支持。
2) 若一个实现发出设置了选项的请求,目标通过设置它在回
应中表示支持。
3) 可以在一个数据包中设置而一次测试所有选项。
Nmap发送这些选项的几乎所有可能的包:
Window Scale=10; NOP; Max Segment Size = 265; Timestamp; End of Ops;
当你得到回应,看看那个选项被送回也就是被支持。一些操作
系统如最近的FreeBSD 机器支持上面所有的,而其他,如Linux 2.0.X
支持的则很少。最近的Linux 2.1.x 内核支持上面所有的。另
一方面,它们又有更易受攻击的TCP 序列生成方式。去看看。
即使几个操作系统支持同样的选项集,有时仍可以通过选项的
_值_分辨出它们。例如,如果送一个小的MSS值给Linux机器,
它会用那个MSS 生成一个回答给你。其他主机会给你不同的值。
甚至即使你得到同样的支持选项集和同样得值,你仍可以通过
选项提供的_顺序_和填充字进行辨识,例如Solaris返回'NNTNWME'
表示:
而Linux 2.2.122返回MENNTNW。同样的选项,同样的值,但不
同顺序!
没见过其他OS检测工具利用TCP 选项,但它非常有用。
因同样原因有其他几个有用的选项我会探测,象那些支持T/TCP
和选择性确认。
开发年代 -- 甚至使用上面所有测试,nmap仍不能从TCP 栈区分Win95,
WinNT,或Win98。这很令人惊讶,尤其是Win98 比Win95 晚出
现4 年。你可能想它们不得不从某些方面进行改善(象支持更
多的TCP 选项)这样我们可以检测到改变而分辨出它们。不幸
的是,不是这样的。NT的栈显然就是放在95里的蹩脚的东西。
而且到98也没加改动。
但别放弃希望,还有个办法。你可以简单的进行早期的Windows
DOS 攻击(Ping of Death, Winnuke, 等)而比当时的如Teardrop
和Land多做一些。就是在每个攻击之后,ping它们看是否垮
掉了。等到你最后crash 掉它们,你就能缩小的某一服务包
或补丁。
这个没加进nmap,尽管我承认它非常诱人:)。
SYN洪水限度 -- 一些操作系统会停止新的连接尝试如果你送太多的
伪造SYN 给它(伪造包避免你的内核复位连接)。许多操作系
统只能处理8 个包。最近的Linux 内核(包括其他操作系统)
允许不同的方式如SYN cookie来防止这成为严重问题。所以你
可以试着从伪造地址发8 个包到目标打开的端口再尝试你还能
否建立连接以发现一些信息。这没在nmap中实现因为有人不喜
欢你用SYN 洪水,甚至你解释这只是想知道它运行的操作系统
也不能使他们平静。