FIN探測 --  通過傳送一個FIN資料包(或任何未設定ACK或SYN標記位的資料包)
            到一個開啟的埠,並等待迴應。RFC793定義的標準行為是“不”響
            應,但諸如MS Windows、BSDi、CISCO、HP/UX、MVS和IRIX等操作系
            統會迴應一個RESET包。大多數的探測器都使用了這項技術。

BOGUS(偽造)標記位探測 -- 據我所知,Queso是第一個使用這種更聰明技術的
            探測器。它原理是在一個SYN資料包TCP頭中設定未定義的TCP“標記”
            (64或128)。低於2.0.35版本的Linux核心會在迴應包中保持這個
            標記,而其它作業系統好象都沒有這個問題。不過,有些作業系統
            當接收到一個SYN+BOGUS資料包時會復位連線。所以這種方法能夠比
            較有效地識別出操作系統。

TCP ISN 取樣 -- 其原理是通過在作業系統對連線請求的迴應中尋找TCP連線初
            始化序列號的特徵。目前可以區分的類別有傳統的64K(舊UNIX系統
            使用)、隨機增加(新版本的Solaris、IRIX、FreeBSD、Digital
            UNIX、Cray和其它許多系統使用)、真正“隨機”(Linux 2.0.*及更
            高版本、OpenVMS和新版本的AIX等作業系統使用)等。Windows平臺
            (還有其它一些平臺)使用“基於時間”方式產生的ISN會隨著時間的
            變化而有著相對固定的增長。不必說,最容易受到攻擊的當然是老
            式的64K方式。而最受我們喜愛的當然是“固定”ISN!確實有些機器
            總是使用相同的ISN,如某些3Com集線器(使用0x83)和Apple
            LaserWriter印表機(使用0xC7001)。

            根據計算ISN的變化、最大公約數和其它一些有跡可循的規律,還可
            以將這些類別分得更細、更準確。

“無碎片”標記位 -- 許多作業系統逐漸開始在它們傳送的資料包中設定IP“不分
            片(無碎片)”位。這對於提高傳輸效能有好處(雖然有時它很討厭
            -- 這也是為什麼nmap不對Solaris系統進行碎片探測的原因)。但
            並不是所有作業系統都有這個設定,或許併不併總是使用這個設定,
            因此通過留意這個標記位的設定可以收集到關於目標主機作業系統
            的更多有用資訊。

TCP 初始化“視窗” -- 就是檢查返回資料包的“視窗”大小。以前的探測器僅僅通
            過RST資料包的非零“視窗”值來標識為“起源於BSD 4.4”。而象queso
            和nmap這些新的探測器會記錄確切的視窗值,因為該視窗隨操作系
            統型別有較為穩定的數值。這種探測能夠提供許多有用的資訊,因
            為某些系統總是使用比較特殊的視窗值(例如,據我所知AIX是唯一
            使用0x3F25視窗值的作業系統)。而在聲稱“完全重寫”的NT5的TCP
            堆疊中,Microsoft使用的視窗值總是0x402E。更有趣的是,這個數
            值同時也被OpenBSD和FreeBSD使用。

ACK值 --    也許你認為ACK值總是很標準的,但事實上作業系統在ACK域值的實
            現也有所不同。例如,假設向一個關閉的TCP埠傳送一個FIN|PSH|
            URG包,許多作業系統會將ACK值設定為ISN值,但Windows和某些愚
            蠢的印表機會設定為seq+1。如果向開啟的埠傳送SYN|FIN|URG|
            PSH包,Windows的返回值就會非常不確定。有時是seq序列號值,有
            時是S++,而有時回送的是一個似乎很隨機性的數值。我們很懷疑為
            什麼MS總是能寫出這種莫名其妙的程式碼。

ICMP錯誤資訊查詢 -- 有些(聰明的)作業系統根據RFC 1812的建議對某些型別
            的錯誤資訊傳送頻率作了限制。例如,Linux核心(在net/ipv4/
            icmp.h)限制傳送“目標不可到達”資訊次數為每4秒80次,如果超過
            這個限制則會再減少1/4秒。一種測試方法是向高階隨機UDP埠發
            送成批的資料包,並計算接收到的“目標不可到達”資料包的數量。
            在nmap中只有UDP埠掃描使用了這個技術。這種探測作業系統方法
            需要稍微長的時間,因為需要傳送大量的資料包並等待它們的返回。
            這種資料包處理方式也會對網路效能造成某種程度的影響。

ICMP資訊引用 -- RFC定義了一些ICMP錯誤資訊格式。如對於一個埠不可到達
            資訊,幾乎所有作業系統都只回送IP請求頭+8位元組長度的包,但
            Solaris返回的包會稍微長一點,Linux則返回更長的包。這樣即使
            作業系統沒有任何監聽任何埠,nmap仍然有可能確定Linux和
            Solaris作業系統的主機。

ICMP錯誤資訊回顯完整性 -- 我們在前面已談到,機器必須根據接收到的資料
            包返回“埠不可到達”(如果確實是這樣)資料包。有些作業系統
            會在初始化處理過程中弄亂了請求頭,這樣當你接收到這種資料包
            時會出現不正常。例如,AIX和BSDI返回的IP包中的“總長度”域會
            被設定為20位元組(太長了)。某些BSDI、FreeBSD、OpenBSD、
            ULTRIX和VAX作業系統甚至會修改請求頭中的IP ID值。另外,由於
            TTL值的改變導致校驗和需要修改時,某些系統(如AIX、FreeBSD
            等)返回資料包的檢驗和會不正確或為0。有時這種情況也出現在
            UDP包檢驗和。總的說來,nmap使用了九種不同的ICMP錯誤資訊探
            測技術來區分不同的作業系統。

服務型別(TOS) -- 對於ICMP的“埠不可到達”資訊,經過對返回包的服務類
            型(TOS)值的檢查,幾乎所有的作業系統使用的是ICMP錯誤型別
            0,而Linux使用的值是0xC0。

片段(碎片)處理 -- 不同作業系統在處理IP片段重疊時採用了不同的方式。
            有些用新的內容覆蓋舊的內容,而又有些是以舊的內容為優先。有
            很多探測方法能確定這些包是被如何重組的,從而能幫助確定操作
            系統型別。

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
核心支援以上所有選項。

如果有幾個作業系統支援相同的選項,可以通過選項的值來進行區
分。例如,如果向Linux機器傳送一個很小的MSS值,它一般會將此
MSS值返回,而其它系統則會返回不同數值。

如果支援相同的選項,返回值也相同,又怎麼辦呢?仍然可以通過
返回選項的順序進行區分。如Solaris系統返回‘NNTNWME’,代表:



而如果是Linux 2.1.122系統,相同的選項,相同的返回值,但順
序卻有所不同:MENNTNW。

目前還沒有其它作業系統探測工具利用TCP選項,但它確實非常有效!

另外還有其它一些選項也可用於進行探測,如T/TCP支援等。

譯者注:還有至少兩種頗具攻擊性的探測方法。由於它們能導致拒絕服務攻擊,而這也是在nmap中沒有實現這些方法的主要原因。



NMAP探測細節和結果

上面我們討論了作業系統型別探測的多種技術(除了某些攻擊性方法外)。這些技術都在nmap掃描器中實現。Nmap掃描器收集了眾多作業系統埠開啟和關閉時的特徵,支援目前流行的Linux、*BSD和Solaris 2.5.1/2.6多種作業系統。

目前版本的nmap掃描器從一個檔案中讀取作業系統特徵模板。下面是一個例項:

FingerPrint IRIX 6.2 - 6.4 # Thanks to Lamont Granquist
TSeq(Class=i800)
T1(DF=N%W=C000|EF2A%ACK=S++%Flags=AS%Ops=MNWNNT)
T2(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)
T3(Resp=Y%DF=N%W=C000|EF2A%ACK=O%Flags=A%Ops=NNT)
T4(DF=N%W=0%ACK=O%Flags=R%Ops=)
T5(DF=N%W=0%ACK=S++%Flags=AR%Ops=)
T6(DF=N%W=0%ACK=O%Flags=R%Ops=)
T7(DF=N%W=0%ACK=S%Flags=AR%Ops=)
PU(DF=N%TOS=0%IPLEN=38%RIPTL=148%RID=E%RIPCK=E%UCK=E%ULEN=134%DAT=E)

讓我們來看一下每一行的含義:

> FingerPrint IRIX 6.2 - 6.3 # Thanks to Lamont Granquist

它說明這是一個IRIX 6.2 - 6.3作業系統特徵,註釋指出該特徵由Lamont Granquist提供。

> TSeq(Class=i800)

它說明ISN特徵是"i800 class",即每一個新序列號比上一個序列號大800的整數倍。

> T1(DF=N%W=C000|EF2A%ACK=S++%Flags=AS%Ops=MNWNNT)

T1代表test1。這個測試是向開啟的埠傳送帶有多個TCP選項的SYN資料包。DF=N說明返回包的
"Don't fragment"位必須沒有設定。W=C000|EF2A說明返回包的視窗值必須為0xC000或0xEF2A。ACK=S++說明返回包的ACK值必須為初始化序列號加1。Flags=AS說明返回包的ACK和SYN標記位必須被設定。Ops=MNWNNT說明返回包的TCP選項及其順序必須為:



> T2(Resp=Y%DF=N%W=0%ACK=S%Flags=AR%Ops=)

Test 2(第二個測試)向開啟埠傳送帶有相同TCP選項的NULL(空)資料包。Resp=Y說明必須接收到返回包。Ops= 說明返回包中的所有TCP選項必須都沒有被設定。‘%Ops=’匹配任意TCP選項。

> T3(Resp=Y%DF=N%W=400%ACK=S++%Flags=AS%Ops=M)

Test 3(第三個測試)向開啟埠傳送帶有TCP選項的SYN|FIN|URG|PSH資料包。

> T4(DF=N%W=0%ACK=O%Flags=R%Ops=)

這是向開啟埠傳送ACK資料包