本文系原創,轉載請說明出處:信安科研人
也可關注微信公眾號:信安科研人
原論文發表在2007年的USENIX上,鏈接如下:https://www.usenix.org/legacy/event/sec07/tech/full_papers/cui/cui.pdf
我看目前國內很少有對這個工具具體的實現細節進行分析,僅僅是提及這個工具是協議自動化逆向的開山鼻祖,因此出此文章。
@
簡介
在當時的情況下,網絡協議逆向的幾個難點:
- 對所處理的網絡流知之甚少,只有一個數據流向
- 不同協議所顯示的明顯不同
- 協議消息格式通常是上下文敏感的,其中較早的字段決定了對消息后續部分的解析。
discover的工作與貢獻:
1)設計基於推斷大部分協議消息格式中常見的協議特定的慣用語,從而能夠多種協議通用。
2)將無格式的字節流,分解為文本和二進制段或標記,作為對具有相似模式的消息進行聚類的出發點,其中每個聚類都近似於一種消息格式。
通過比較集群中的消息並觀察已知的跨字段依賴的特征(例如長度字段后跟着相應長度的字符串),推斷token的其他屬性,進而可以利用這些屬性細化和划分消息簇,其中每個子簇近似於更精確的格式。 這個過程遞歸地繼續,直到不能再根據新完成的推理划分任何消息集群。
在這個遞歸聚類階段之后,通過基於類型的序列比對算法全局地查看所有消息集群,並將相似的集群合並為一個,這樣可以生成更簡潔的消息格式。
一、背景知識
多種協議之間的共同慣用語
很多應用層協議共享相同的協議特定慣用語,這些慣用語對應協議規范中的基本組件。為了使逆向工程算法適用於更多的協議,設計基於推斷常見的協議習慣用法。
1)協議狀態機
大多數應用程序級協議都涉及應用程序會話的概念,其由完成特定任務的兩個主機之間的一系列消息(也稱為應用程序級數據單元或 ADU)組成。應用程序會話的結構由應用程序的協議狀態機確定,協議狀態機是協議規范中的一個重要組成部分,用於表征所有可能的合法消息序列。
2)消息格式規范
應用程序消息的結構由應用程序的消息格式規范決定,這是協議規范中的另一個重要組成部分。消息格式指定了一系列字段及其語義。
常見的字段語義包括長度(以可變長度反映后續字段的大小)、偏移量(確定另一個字段從某個點(如消息的開頭)開始的字節偏移量)、指針(指定任意項數組中字段的索引)、cookie(出現在來自應用程序會話雙方的消息中的特定於會話的不透明數據;會話 ID 是 cookie 字段的示例)、端點地址(編碼 IP 地址或端口某種形式的數字)和集合(一組可以按任意順序排列的字段)。
一種特殊類型的字段是 Format Distinguisher (FD) 字段。該字段的值用於區分消息后續部分的格式,這反映了許多應用程序級協議語法中的上下文敏感特性。一條消息可能有一系列 FD 字段,特別是在封裝多個協議時。
例如,CIFS/SMB 消息由封裝 SMB 頭的 NetBIOS 頭組成,而 SMB 頭又可以封裝 RPC 消息。這意味着應用程序需要從左到右掃描消息,在解析消息的后續部分之前解碼 FD 字段。
本文專注於推導消息格式規范,並將協議狀態機推斷留給未來的工作。
二、設計概覽
核心思想:將相同格式的消息聚起來,然后通過在單個聚類中比較以推斷消息格式。
共三個階段!
階段1 > 標識化與初始化聚類
該模塊處理初始化數據包,識別一個消息報文的區域邊界,並反饋第一階順序的結構至未標簽的消息報文。
1 標識化
標識,下文都用token來表示,一個標識是一段連續的字節序列,這些連續的字節序列有很大的可能屬於同一應用層字段。
在對消息進行標識化的過程中,不需要對消息的字段中的二進制字段與文本字段進行特別的區分,因為作者發明discoverer工具的初衷之一就是全自動化的讓用戶免於陷入手動區分文本字段與二進制字段的過程中。另一個原因是真的很難很難認定這個協議是純文本協議還是純二進制協議,因為文本協議可能包含二進制字段(例如HTTP協議傳輸一個二進制圖片),二進制協議又可能包含一些文本字段(例如傳輸一個文件的名字)。
標識化過程主要產生兩種標識,也就是上文說到的二進制token和文本token。
對於文本token:
文本token旨在跨越地表示某些文本的單個消息字段的幾個字節(例如 HTTP 請求中的“GET”)。識別文本token的程序如下:
1)通過與可打印出來的ascii字符進行比較,來識別文本字段;
2)將夾在兩個二進制字節之間的文本序列視為文本字段。
為了不將二進制字段識別為文本字段,discoverer認定這個字節序列有最小的長度。然后,用一些間隔符號,將這些文本序列分成token。discoverer也會尋找消息報文中的unicode編碼。
對於二進制token:
真的很難找到token的邊界。 在這里僅僅是將單個字節視作一個二進制token。這個過程可能會出現如下的錯誤:
- 具有可打印字符的 ASCII 值的連續二進制字節被錯誤地標記為文本標記;
- 短於最小長度的文本字符串被錯誤地標記為二進制標記;
- 由一些空白字符組成的文本字段被錯誤地划分為多個文本標記。
不用着急,在discoverer的合並階段解決這個問題。
2 通過token模式初始化聚類
基於 Needleman-Wunsch 算法的逐字節序列比對已在先前的很多研究中用於比對和比較消息。 逐字節序列對齊雖然非常適合對齊具有相似字節模式的消息,但不適合對齊具有相同格式的消息。 例如,具有可變長度的字段可能會導致兩個相同格式的消息不對齊。 此外,序列比對的參數選擇也很困難。
為了避免這種問題,discoverer通過token模式初始化第一次消息聚類,一個token模式是一個元組,格式如下:
其中,dir代表消息傳送的方向,后面跟着一個消息中的所有token類。考慮到dir的原因是響應包與請求包往往有着不同的消息格式。如:
需要注意的是,初始聚類是粗粒度的,因為具有不同格式的消息可能具有相同的token 模式。 例如,SMTP 命令通常有兩個文本標記(“MAIL 接收者”、“RCPT 發件人”、“HELO 服務器名稱”)。
discoverer將在遞歸聚類階段,通過遞歸識別 FD(格式區分字段) token 和 划分聚類來提高這種聚類的粒度。
階段2 > 遞歸聚類
遞歸聚類的核心是識別格式區分符 (FD) token。 為了找到 FD 標記,需要格式推斷和格式比較。
1 格式推斷
格式推斷階段將一組消息作為輸入,並推斷出簡潔地捕獲該組消息內容的格式。所推斷出來的消息格式不僅包括token的語義,還包括token屬性。
引入token屬性是因為無法推斷每個token的語義含義,並且某些token屬性對於描述消息格式很有用。token屬性包括,二進制與文本,常量與變量。也就是兩大類,第一類表示token的類別,第二類決定令牌是在相同格式消息中采用相同的值還是可變的值。同時,對於標記的類別,定義為語義和屬性的總和。
屬性推斷
首先,在標記化階段(第一階段)已經確定了token類別。
第二,常量或變量token也可以很容易地識別。 因為一組中的消息的token模式是相同的,那么就可以通過簡單地使用token偏移量直接將一條消息中的token與另一條消息中的對應toekn進行比較。 因此,常量token是那些在整個消息集中采用相同值的token,而可變token是那些采用多個值的token。
語義推斷
discoverer支持三種語義:長度、偏移量、cookie。
- 對於cookie的推斷,需要在合並階段也就是第三階段結束時識別。
而對於長度和偏移量,discoverer用到了這篇文章中提到的做法的擴展,主要是啟發式的方法,具體內容有機會再具體寫。
- 對於長度字段,直覺上來說,兩個消息中該區域的令牌不同可能會讓兩個消息的大小不同,或者后續的一些token不同。也就是說,將消息大小的差值與token之間的差值匹配可以起到較為有效的認定。如果說,這個集群種,所有的消息對之間的差值都能與所有消息對之間的token的差值相匹配,那么就認定這個是長度token。
- 對於偏移量字段,將值差異與一些后續token的偏移量差異相匹配。
2 格式比較
此過程的目標是確定兩個推斷的消息格式是否相同。 給定兩種格式,從左到右逐個標記地掃描這兩種格式,並將一種格式的標記的推斷類型(即語義和屬性)與另一種格式的對應部分進行匹配。 如果所有標記都匹配,則認為這兩種格式相同。
理想情況下,如果兩個token的語義匹配,則可以認為它們匹配。 然而,由於總是存在沒有語義的token,因此需要比較它們的值(它們具有相同的token類因為兩種格式具有相同的token模式):
如果變量token至少取一次常量token的值,則允許常量token與變量token匹配;
如果兩個變量token之間所取的兩組值有重疊,則允許變量token與另一變量token匹配。
3 通過格式比較器遞歸聚類
識別FD token的方法如下:
- 首先對一個消息集群使用格式推斷;
- 接着,從左到右以token為單位逐個掃描消息格式,以識別FD TOKEN。
三種標准判斷FD token:
-
首先檢查該token在一組消息中采取的獨特值的數量是否小於一個閾值,那么將這個閾值稱為FD token的最大的不同值。 這是因為fd token的取值通常與不同格式的總數相對應。
-
對於滿足第一個標准的token,進行的第二次測試。將整個集群按照這個token的不同取值分為幾個子集群。也就是每個子集群由候選FD TOKEN所采取的特定的值分成。認定最大的子消息集群的大小超過了一個閾值,這個閾值被稱為最小集群大小。這么做可以至少在一個子集群中的格式推斷有效果,否則這么划分什么都得不到。比如,一個子群如果只有一個消息,那我推斷個錘子。
-
當候選FD TOKEN過了第二關,調用上一節的格式比較來判斷這些子集群之間的格式是否兩兩不同。然后合並那些相同的格式的子集群並保持其他完整不變,那么未合並的token與其他token互相獨立成為其對應的格式代表,以達到一種識別格式區分符的目的。
這個過程在每個子集群上遞歸執行,因為一條消息可能有多個 FD token。 通過向消息的右側(末尾)進一步向下掃描消息來找到下一個 FD token。 這就需要一直掃描到最后,因為需要識別所有的 FD 以獲得較完善的聚類和格式推斷。
在查找下一個 FD token時,會再次對每個子集群中的消息集調用格式推斷。 這是因為推斷的token屬性和語義可能會因為消息集變得更小而改變,並且有可能擁有更強的屬性。 例如,以前可變的token現在可能是常量令牌; 以前可變的令牌現在可能被標識為長度字段。
階段3 > 與基於類型的序列比對合並
1 問題提出
在標記化和遞歸聚類階段,算法保守地確保格式推理過程在一組相同格式的消息上正確地運行。 然而,這導致了過度分類的新問題,即相同格式的消息可能分散到多個集群中。 這個問題可能非常嚴重; 例如,在近 400 萬條消息的 CIFS/SMB 網絡流中,有大約 7,000 個簇/格式作為此階段的輸入,而真正格式的總數為 130。合並過程的目標是將來自不同集群的相似格式合並為一個單一的格式。
合並階段背后的關鍵是,雖然序列比對不能用於對相同格式的消息進行聚類,但它可以用於對齊格式以識別不同聚類中的相似消息。 這是因為可以利用在遞歸聚類階段推斷出的多樣化的token類型(即語義和屬性),例如,知道一個特定的token是一種格式中的一個長度字段,就需要它在另一種格式中的對應物也是一個長度字段,這兩種格式才能被認為是匹配的。 那么,本文將用於對齊格式的算法稱為基於類型的序列對齊。
在基於類型的序列比對中,只允許同一類(二進制或文本)的兩個標記相互比對。同時聲稱如果兩個對齊的標記具有相同的語義或共享至少一個值,則它們是匹配的。
2 補償標記化階段做法
為了補償標記化階段錯誤,允許在基於類型的序列比對中存在間隙。除了使用差距懲罰來控制差距之外,本文還引入了額外的約束來避免過度的差距。
- 首先,一種消息格式的連續二進制token如果在對齊中位於另一種消息格式的文本token之前或之后,則允許與間隙對齊,並且二進制token的數量最多為文本token的大小,如果文本token與間隙對齊,或者如果與另一個文本token對齊,則為大小差異。此約束用於處理將二進制token序列誤認為是文本token或反之亦然的情況。
- 其次,允許文本token與間隙對齊,但最多允許兩個此類間隙。此約束用於處理由一些空白字符組成的文本字段被錯誤地划分為多個token的情況。
3 合並
當對齊和比較兩種消息格式以決定是否合並它們時,首先檢查是否可以滿足間隙約束。如果不滿足,停止並聲稱這兩種格式不匹配;否則,繼續檢查不匹配的數量。如果最多有一對對齊的token不匹配,聲稱這兩種格式匹配並合並它們。請注意,這是一種比較保守的方式,因為不匹配的token可以被視為變量token,它從涵蓋兩種格式的新集合中獲取值。
由於使用間隙約束和不匹配的數量來決定是否合並兩種消息格式,因此的合並性能對序列比對參數(匹配、不匹配和間隙的分數)不敏感。
三 舉例
為了更好的理解,這里給出一個基於SMB“Tree Connect AndX Request”消息格式的具體例子來解釋Discoverer的設計和輸出。從 Ethereal 獲得真實的消息格式(參見圖 2 和圖 3)。 Discoverer 的最終推斷格式如表 1 所示。
1 效果
首先是圖 2:Ethereal 的示例 SMB“Tree Connect AndX 請求”消息的 XML 輸出(經過編輯以更好地展示)
看起來很復雜,而discoverer主要是用來識別格式區域的,所以可以簡化成識別這些:
然后識別出來的效果如下:
這個表格展示了Discoverer 對圖 3 中真實格式所推斷出來的格式。對於 C(x,y),C 表示常量,x 表示二進制(“b”)或文本(“t”,即文本;在文本token中,“u”表示 Unicode ,“n” 表示它以空值結尾),y 是令牌的十六進制值或字符串; 對於 V(x,z),V表示變量,x與上文相同,z 是token的不同值的數量。
2 結果分析
可以看到,推斷的格式是具有標記屬性(二進制與文本、常量與變量)和語義(例如長度字段)的標記序列。對於語義未知的token,格式中也考慮了它們的可能值。
在合並步驟之前,這種真實格式的消息以 18 種不同的token模式分散到 24 個集群中。不同的token模式歸因於“smb.signature”字段。
由於該字段可能采用任何隨機值,因此當不同偏移量的三個以上連續字節從可打印的 ASCII 范圍內獲取值並被錯誤地視為文本token時,將具有不同的token模式。由於方法比較保守,某些token模式中的消息在遞歸聚類階段被進一步拆分為細粒度的集群。合並技術有效地緩解了這種過度分類問題。最后,所有 24 個集群合並為一個集群。
此示例還顯示了不精確的字段邊界的可能性。例如,字段“smb.nt status”的第一個空字節被視為它之前的文本標記的空終止符。但是,discoverer認為這種不精確不會影響推斷格式的有效性,而是會為“smb.nt status”創建一些具有不同值的額外推斷格式。