韓嘉佳,孫 歆,呂 磅,孫昌華,錢 錦
(國網浙江省電力有限公司電力科學研究院,杭州 310014)
隨著我國大力推進實施以雙碳和新能源為主的新型電力系統(tǒng)戰(zhàn)略,未來電力系統(tǒng)結構形態(tài)將發(fā)生較大改變,電力系統(tǒng)逐步打破了以往的封閉性和專有性,接入企業(yè)的終端數量快速增加。電力行業(yè)安全防護責任界限擴展,安全防護壓力增加,各類設備、平臺廣泛接入電力系統(tǒng),可能出現多種異構網絡,通信傳輸模型更為復雜,可能出現通過破解算法、協(xié)議及中間人攻擊等多攻擊方式,對傳輸數據及控制指令進行篡改、屏蔽等,新型電力系統(tǒng)安全形勢日益嚴峻。因此,如何在新型電力系統(tǒng)終端上利用擬態(tài)防御思想,對提升新型電力系統(tǒng)終端系統(tǒng)的防御能力和安全等級至關重要。新型電力系統(tǒng)終端擬態(tài)防御的第一步,就是要通過對截獲的新型電力系統(tǒng)終端通信數據進行分析,動態(tài)識別出新型電力系統(tǒng)終端應用程序所用的網絡協(xié)議,從而理解通信行為,判斷未知數據是否為攻擊方發(fā)出的病毒數據。
新型電力系統(tǒng)終端可獲取的通信數據類型繁多,隨著應用程序的爆發(fā)式增長,針對應用程序執(zhí)行產生的數據信息的獲取途徑逐漸成為研究熱點。然而,在應用程序執(zhí)行過程中,初始數據可能被覆蓋或者刪除,也可能由于加密技術,不能獲得完整的應用程序數據。為了信息采集的完整性,還應對應用程序執(zhí)行過程中產生的網絡通信數據進行獲取。通過分析截獲的通信數據,識別和解析出應用程序采用的網絡協(xié)議,根據其通信機制和內容,理解通信行為,為判斷網絡數據的危險性、提取有效證據信息提供基礎。
目前工控漏洞挖掘方法有兩種,一種是面向協(xié)議報文的逆向分析,另一種是面向固件及執(zhí)行程序的逆向分析。對固件進行分析如文獻[1],該類方法需要的條件較為嚴苛,需要對實現通信的程序進行監(jiān)控,訪問其運行環(huán)境并記錄產生的指令信息,使用了軟件逆向的方法。但是在實際工業(yè)控制系統(tǒng)中很難接觸到工控設備實體。一般來說,為了提高協(xié)議安全研究的效率,需要首先對協(xié)議進行協(xié)議逆向工程,以獲取協(xié)議的消息格式等信息。因此,在工業(yè)互聯網中更加關注以協(xié)議逆向為前提的面向協(xié)議的漏洞挖掘和分析技術。PRE(協(xié)議逆向工程)僅通過對捕獲到的通信實體雙方的通信流量進行分析,提取協(xié)議消息格式等相關內容,從而推斷出未知協(xié)議的消息格式和狀態(tài)機模型的過程[2]。在相關領域,已經有許多研究對協(xié)議逆向的方法進行探索和改進,目的是提高逆向結果的準確性。近年來,協(xié)議逆向技術被用于各個相關的安全領域,模糊測試、網絡入侵檢測、入侵防御等都使用了協(xié)議逆向來獲取未知協(xié)議的先驗知識,以提高分析工作效率。
通常采用對未知協(xié)議流量中的報文序列分析來進行協(xié)議逆向。最早的協(xié)議逆向技術的是Protocol Informatics[3]項目(以下簡稱“PI”)。PI 項目借鑒了一種從DNA序列尋找特定基因的算法,類比到協(xié)議逆向領域即從捕獲流量報文數據中尋找特定類型的消息。PI 項目為后來的許多工作提供了指導,后來的研究者對方法進行了改進,例如Al-Dhaq[4]等人的協(xié)議狀態(tài)機自動提取工具ScriptGen就是以PI 項目為指導,該工具完成部分語義的提取,但是在推斷狀態(tài)機之前并未對消息序列進行聚類,性能上與今天的工具有很大差距。另一個重要且經典的工具是Golubeva[5]等人提出的Discoverer 工具,其對不同類型的待分析報文能夠選擇合適的方法,提高了分析性能。在此之后,隨著人工智能技術的興起,機器學習、自然語言處理領域的算法被應用于協(xié)議逆向領域中,協(xié)議逆向工程在短時間內得到迅速發(fā)展,研究對象從普通的文本協(xié)議擴展到二進制協(xié)議,方法類型也不斷豐富,并且準確率和可靠性等方面得到大幅度提升。比如張明遠[6]等人使用了基于序列比對算法將報文各個字段對齊,Casino[7]等人使用了概率模型尋找報文關鍵字段,Khan[8]等人基于頻繁集和先驗算法提出了一種無監(jiān)督學習方法來提取消息格式和協(xié)議狀態(tài)機,Li[9]等人和Rahman[10]等人同時考慮了基于語義分析和語義分析,并提出了一種由數據流和控制流信息組成的EFSM(擴展有限狀態(tài)機)行為模型。近年來也不斷有新的方法提出,例如Sun[11]等人提出使用基于聚類效果直觀度量的協(xié)議關鍵詞概率提取算法,Yang[12]等人提出利用報文本身特點使用連續(xù)段相似性。
上述文獻針對協(xié)議安全性分析的工作主要包括對協(xié)議進行逆向,推斷協(xié)議狀態(tài)機,大多數是基于網絡流量的被動推斷方式。在協(xié)議漏洞挖掘方面主要是模糊測試,但存在測試用例效率低下、耗時長、程序崩潰時無法定位到崩潰點等問題。
為了解決上述問題,本文提出了一種基于網絡流量分析的私有協(xié)議逆向方法,通過對捕獲的流量報文進行分層處理,將未知協(xié)議的數據字段提取出來,然后利用N-gram算法進行分詞,對協(xié)議關鍵詞進行聚類,利用增廣前綴樹合并狀態(tài),推斷出協(xié)議狀態(tài)機。生成的協(xié)議狀態(tài)機與標準協(xié)議狀態(tài)機利用深度學習進行一致性匹配,推測出協(xié)議脆弱性可能出現的地方。對協(xié)議進行安全性測試,利用模糊測試的方法分別對Modbus協(xié)議源碼和消息格式進行測試,通過對比不同模糊測試工具的效率和性能,選擇出了一種較好的協(xié)議測試工具。
物聯網終端依靠網絡協(xié)議進行通信,不同廠商可能會使用不同的協(xié)議,而且不同的應用場景和需求對協(xié)議也有不同的要求。例如,生活中常見的FTP(文件傳輸協(xié)議)、SMTP(簡單郵件傳輸協(xié)議)、汽車使用的CAN(控制器局域網總線協(xié)議)、工控領域中的Modbus/TCP 協(xié)議和西門子S7Comm協(xié)議。
Modbus協(xié)議全稱為Modbus/TCP協(xié)議,就是基于TCP/IP 的工控協(xié)議,其通信模式有3 種情況,分別為請求/應答、訂閱/推送和主動推送。其設計是面向功能的,協(xié)議報文多為二進制報文,主要傳輸控制命令(控制碼),報文精簡,比較系統(tǒng)化、結構化。
Modbus 協(xié)議定義了PDU(協(xié)議數據單元)和ADU(應用數據單元)。ADU由4部分組成,分別是地址域、功能碼、數據部分和差錯校驗。地址域和功能碼都為1個字節(jié),前者表示設備地址,后者表示操作功能代碼。數據部分可包括偏移量、子功能碼、可變參考等,最大為252字節(jié)。差錯校驗部分為2字節(jié)。
Modbus 功能碼的有效范圍是1~255,其常用的功能碼及其功能如表1 所示。其中,01 表示讀取線圈狀態(tài),02 表示讀取輸入狀態(tài),03 表示讀取保持寄存器,04 表示讀取輸入寄存器??捎玫墓δ艽a有127個,其中108個為公共功能碼,公開聲明的,具有普遍適用性的,包含保留的未定義的功能碼;其余為用戶定義功能碼,用戶自定義操作碼功能。
表1 常見功能碼及功能Table 1 Common function codes and the functions
系統(tǒng)框架如圖1所示,新型電力系統(tǒng)終端第三方廠商私有協(xié)議安全性分析系統(tǒng)共分為兩個模塊:協(xié)議逆向模塊和模糊測試模塊。協(xié)議逆向模塊是基于網絡流量分析而設計的,主要包括4 個步驟:預處理、格式推斷、語義分析和狀態(tài)機推斷。模糊測試模塊分為兩部分,為基于源碼的模糊測試和基于消息格式的模糊測試,分別對應不同的模糊測試工具AFL和Boofuzz。
圖1 智能終端協(xié)議安全性分析系統(tǒng)框架圖Fig.1 Framework of protocol security analyzer for intelligent terminal
對于網絡中捕獲的流量,由于帶寬的不穩(wěn)定和混雜流量的影響,需要先對捕獲的報文進行分流、去重傳等操作,然后基于5層網絡架構體系對流量報文進行處理。預處理可將私有協(xié)議字段部分提取出來,然后進行格式推斷,通過分詞提取協(xié)議關鍵詞,分析各關鍵詞之間的關系,初步推斷協(xié)議格式。之后進行語義分析,劃分后的關鍵詞需要推斷其所代表的含義,如報文長度、操作功能、地址或ID等,需要對固定的取值和可變取值進行分析,甚至還有協(xié)議未使用的字段部分。最后依據前面的分析,推斷協(xié)議狀態(tài)機,將具有相同特征的關鍵詞聚為同一類簇,可視為同一個狀態(tài),由此為基礎推斷協(xié)議狀態(tài)機,來獲得每個狀態(tài)之間的關系,尤其是最重要的時序關系。最后將推斷的狀態(tài)機與開源協(xié)議逆向軟件推斷的結果進行比對,來對協(xié)議安全性進行分析。
N-gram 模型是一種基于統(tǒng)計的語言模型算法,常用于NLP(自然語言處理)。其基本思想是利用了滑動窗口的思想,即對一串文本數據進行分詞時,按照字節(jié)的先后順序,依次進行大小為N的滑動窗口分詞操作,形成若干個長度為N的字節(jié)片段序列。
這與協(xié)議關鍵詞和協(xié)議狀態(tài)機的思想類似,所以將N-gram算法用于劃分協(xié)議格式,推斷協(xié)議關鍵字是一種有效的方式。常用的算法是基于二元的Bi-Gram和基于三元的Tri-Gram。
經過前面的處理,私有網絡協(xié)議的字段被處理成文本,由于協(xié)議未知,無法進行狀態(tài)標注,于是可以先用N-gram算法進行處理切分,提取協(xié)議關鍵詞。評價N-gram算法的有效性在于N的取值大小。若N的值過小,會使得協(xié)議關鍵詞被切分,影響準確率;若N的值過大,會導致切分結果體量過大,影響處理效率。在經過多次實驗后,了解到關鍵詞的大小多為1~2 字節(jié),因此選取N的值為1~2。
由于Modbus是單狀態(tài)協(xié)議,很難根據協(xié)議的運行狀態(tài)推斷協(xié)議狀態(tài)機,因此,本節(jié)利用協(xié)議的字段構建Modbus協(xié)議狀態(tài)機。在進行關鍵詞分類時,由于對每個類簇進行標記,所以進行無監(jiān)督學習分類。對于私有網絡協(xié)議的報文,其數據字段可能由于功能不同,結構也不同,所以根據分詞后協(xié)議特征關鍵詞的分布密度進行聚類,測試結果也可能是不同的。
因此,需要用一種方法來對聚類結果進行有效性評價,輪廓系數被認為是一種比較好的用于評估聚類有效性的方式。它的取值范圍在-1~1,越接近1 表示聚類的結果越有效。當系數小于0時,表示有部分重疊樣本,即分類出現誤差;當系數在0上下浮動時,表示邊際有重合;當系數大于0 時,表示聚類效果較好,每一類簇的分類較清晰。
進行輪廓系數計算方法時,首先隨機選擇一個類簇里的樣本,作為初始向量,然后計算其到同類樣本距離的期望,表示簇內的聚合度。然后再計算其到其他類簇的距離的最小值:
式中:a(j)是樣本j與同一簇內其他所有樣本的平均距離,這個值越小,表示該樣本與所在簇的相似度越高;b(i)是樣本i與其他簇內所有樣本的最小平均距離,即樣本i與最近的那個簇的所有樣本的平均距離,這個值越小,表示該樣本與其他簇的差異性越小;輪廓系數S(i)的取值范圍是[-1,1],S(i)的值越接近于1,說明樣本i與所在的簇匹配得很好,S(i)的值越接近于-1,說明樣本i與所在的簇匹配得不好,可能被分到了錯誤的簇,如果S(i)接近于0,則說明樣本i在兩個簇的邊界上。
由于Modbus協(xié)議為單狀態(tài)協(xié)議的特殊性,所以基于協(xié)議的幀格式來構建協(xié)議狀態(tài)機。構建的過程如下:以幀的起始作為狀態(tài)機的開始狀態(tài),然后對后面讀入的字節(jié)進行校驗,若為合法的輸入,則轉到下一個狀態(tài),否則回到起始狀態(tài),直到讀入幀結束字符。
基于逆向分析推導的協(xié)議狀態(tài)機如圖2 所示。對于幀起始,可作為初始狀態(tài),一個輸入事件可由每一次讀入的字符決定,若判斷為合理輸入,則跳轉到下一狀態(tài);若為非法輸入,則狀態(tài)機返回初始態(tài)。Modbus協(xié)議不同的功能碼則可以對應不同的設定狀態(tài)。
圖2 Modbus協(xié)議逆向推導得出的狀態(tài)機Fig.2 State machines obtained through reverse derivation of Modbus protocols
在Modbus 協(xié)議分析結果基礎上,選用Boofuzz作為協(xié)議的模糊測試工具。Boofuzz是基于Python 語言實現的,但它無法直接獲得協(xié)議相關信息,需要人工定義協(xié)議格式,因此使用Boofuzz對Modbus的協(xié)議格式進行模糊測試。
由于Boofuzz 無法直接獲得協(xié)議的相關內容,需要借助工具PyModbus實現一個Modbus服務器。為了構建一個Modbus服務器,首先需要實例化一個ModbusSlaveContext,并向其傳遞一些與輸入寄存器、線圈等相對應的“數據塊”。數據塊是一種存儲機制的實例,它至少支持在某個地址讀取和寫入數值。最簡單的,Modbus Sequential Data Block,只是對可序列化字節(jié)集合的一個簡單封裝,其本質上只是一個C 數組。在實驗中將使用數據塊來創(chuàng)建數據存儲,本質上只是幾個數據塊的集合,從中構建代表設備狀態(tài)的上下文。設置TCP服務器模擬設備與服務器之間的通信。Modbus 服務器主要包括3 個模塊:Sequential Data Block、Bad Data Block 和Communication Block。第一個模塊負責順序通信,包括定義了線圈、寄存器個數等相關數據塊;第二個模塊只要定義了觸發(fā)崩潰的條件,即服務器被要求在高于0xFF的地址處輸入值時,程序將會出現崩潰;第三個模塊主要是定義通信過程,創(chuàng)建socket 線程與客戶端通信。
Boofuzz 進行測試的基本單位是會話,每個會話由一個連接和多個字段定義,這些字段可以組織成塊。通常,每個Boofuzz字段映射到一個協(xié)議字段。根據協(xié)議,某些字段將是“二進制”字段。例如s_bytes,這是描述IP數據包的源和目標字段的一種方式,但其他字段可以是完全的ASCII 字符串。每個字段都由一個起始值和一些參數定義,這些參數描述了它將如何被模糊化。例如,事務ID字段如下所示:
s_bytes(value=bytes([0x00, 0x01]),size=2,max_len=2,name="transaction_id")
如果一個字段應該是固定的,可以通過fuzzable=False。但是,對數據包的所有字段進行模糊測試是沒有意義的,在大多數情況下都是如此,可以在一個塊中收集多個字段。因此,使用Boofuzz構建的模糊測試器工作步驟如下:
1)實例化一個會話對象,將它指向需要模糊測試的對象,例如會話進程。
2)通過定義協(xié)議的每個字段并告知Boofuzz如何修改字段的值來定義協(xié)議,或者將字段都放入塊中。
3)使用上面的會話對象連接到被測目標,調用fuzz()開始測試。
在測試中將構建一個僅包含一種數據包類型的協(xié)議定義——讀取輸入寄存器。這個數據包的結構除了典型的Modbus 頭和函數ID,它只包含兩個字段:起始地址和要讀取的輸入寄存器的數量。從輸入地址開始,兩者都是2字節(jié)。
接下來確定需要模糊測試的字段。顯而易見的是,起始地址和寄存器數量字段是被測對象,如果處理請求的邏輯有缺陷,它將與這兩個值相關聯。在測試中對讀取輸入寄存器函數進行模糊測試,因此需要將函數ID字段固定為0x04。協(xié)議字段設置為:起始地址、寄存器數量和事務處理ID字段將模糊測試;協(xié)議ID、長度、單元ID和函數ID字段將固定。
測試服務器主要由4 個模塊構成,分別為:Communication Block、 Fuzz Data Block、 Fixed Data Block和Operation Data Block。第一個模塊主要是實現與服務器的通信;第二個模塊是定義需要模糊測試的字段;第三個模塊是固定字段;最后一個模塊是向服務器發(fā)送操作碼。
為了實現環(huán)境隔離的原則,實驗中Boofuzz運行在虛擬環(huán)境中,并使用pip對Boofuzz下載安裝,具體安裝命令如下:
# mkdir boofuzz && cd boofuzz
# python3 -m venv env
# source env/bin/activate
# pip install boofuzz
首先運行Modbus 服務器,然后開始對TCP會話進行模糊測試。通過觀察運行結果發(fā)現程序崩潰,具體結果存放在boofuzz-results 文件夾中,這是一個簡單的SQLite數據庫,可以使用Boofuzz自帶的Web UI進行查看,如圖3所示。
圖3 使用Boofuzz模糊測試運行過程Fig.3 The operating process using Boofuzz
在瀏覽器中打開127.0.0.1:26000可以查看每次測試運行的具體情況,如圖4所示。由圖4可以看到測試用例一共運行了78次,第78次是嘗試連接但是連接失敗了,所以程序在第77 次發(fā)生了崩潰。程序崩潰的原因在于嘗試從地址0xFF00讀取1 個寄存器(04)??梢钥闯鯞oofuzz 的模糊測試雖然前期需要準備協(xié)議的相關知識,但測試有效性要高于AFL。
圖4 測試數據具體情況Fig.4 Data testing
針對現有第三方廠商新型電力系統(tǒng)終端協(xié)議封閉難以識別及測試的安全問題,提出了基于Ngram 算法和協(xié)議狀態(tài)機推斷的逆向分析方法,在此基礎上通過協(xié)議源碼編譯插樁的方式,實現協(xié)議的模糊測試。以典型Modbus協(xié)議為例開展本文所提方法的有效性驗證,經測試表明,該方法可以有效對第三方廠商私有協(xié)議開展快速識別和安全性測試,有較高的實用價值。