信息熵在ICMP隧道檢測中的實踐
ICMP協議通常用來測試網絡通不通、主機可不可達、路由可不可用。宅男們打游戲時也常用來ping一下,看看延遲高不高,太高迅雷就得關一關了。
而網絡攻擊者通過ICMP協議,可以進行隧道傳輸,實現數據竊取,規避掉一些防火墻規則。
如何檢測這種隧道?用傳統的簽名無法對抗負載加密,復雜的統計比對讓檢測引擎不堪重負,準確率也不高。
而基于ICMP常規的通訊數據和攻擊時產生的畸形數據,利用信息熵來分析,可以為檢測打開突破口。
1ICMP隧道
在ICMP報文中,最值得關注的是類型0x0和類型0x8。0x0類型的ICMP報文代表ICMPECHOREPLAY(響應),0x8類型的ICMP報文代表ICMPECHO(查詢)。
以ping命令為例。在進行工作時,ping命令向遠程主機發送一個或多個ICMPECHO數據包,其目的是判斷遠程主機是否可以到達。
ICMP數據包的選項部分可以填寫數據,通常在ICMP報文到達遠程主機的過程中,記錄沿途經過的路由器地址以及沿途經過路由器時耗費的時間。一般的通訊數據形式如下:

PTunnel介紹
PTunnel是一種可以把TCP鏈接通過ICMP的顯示請求(ping請求)和回復(ping回復)包進行傳輸的工具。
這種工具能夠將數據信息隱秘地送入或送出網絡,可以用于只有ICMP數據流允許出入的網絡的情況。源碼下載地址:
“http://www.cs.uit.no/~daniels/PingTunnel/。”
運行環境
PTunnel可以安裝在Windows系統和Linux系統中。實驗環境為:
客戶端:Windows 7 + WireShark 【192.168.12.87】;
服務端:Kali 【192.168.12.234】;
在客戶端和服務器端安裝PTunnel,雙方能直接通過IP地址實現點到點的數據通訊。
運行方式
客戶端:

服務端:

模擬場景中,服務端安裝MySQL僅允許本地登錄,雙方與防火墻串聯在一起形成單一網絡。
通過PTunnel工具建立ICMP隧道,繞過中間防火墻協議和服務器MySQL地址策略的限制,實現在客戶端上成功訪問服務器的本地MySQL數據庫。
在服務器端開啟PTunnel監聽模式:
root@localhost:~#ptunnel[inf]:Starting ptunnel v 0.71.[inf]:(c) 2004-2009 Daniel Stoedle, <daniels@cs.uit.no>[inf]:Security features by Sebastien Raveau,<sebastien.raveau@epita.fr>[inf]:Forwarding incoming ping packets over TCP.[inf]:Ping proxy is listening in privileged mode.
在客戶端以管理員權限啟動cmd命令行,輸入命令參數如下:
c:\Users\xxxx\Desktop>ptunnel.exe-p 192.168.12.234 -lp 808 -da 127.0.0.1 -dp 3306
將192.168.12.234上的3306端口和本地客戶端808端口建立ICMP隧道,實現數據的通訊。在客戶端連接808端口就相當于連接遠程服務器上的數據庫3306端口。
在客戶端另起一個cmd命令行,連接本地的808端口,實現對遠程服務器192.168.12.234數據庫的訪問。命令如下:
C:\xampp\mysql\bin>mysql.exe-h 127.0.0.1 -P 808 -uroot -p123456
在客戶端上通過PTunnel成功連接上服務器的數據庫:

數據報文分析
實際通信中,客戶端將一直發送ICMP請求報文,而對應的服務端將針對請求報文發送ICMP應答報文,從而在服務端和客戶端建立起一條ICMP隧道,通過將TCP報文封裝在ICMP報文中,從而能夠實現數據的傳輸。
如下圖所示,所有的ICMP請求報文均是從客戶端發送至服務端:

客戶端與服務端通過ICMP協議中請求和應答包建立初始連接,數據包序號為3、4,類似于TCP連接中的三次握手:

在建立初始連接后,從序號為5的數據包為服務端向客戶端發送握手初始化包,該包是為了提醒客戶端下面需要進行身份認證:

客戶端收到服務器提出的身份驗證請求后,將身份帳號密碼封裝到ICMP請求包的data部分,返回給客戶端:

操作數據庫時,可以看到命令和返回信息:


2信息熵
如果通過簽名規則的方式針對上述流量進行檢測還是能起到一定的效果,但如果數據經過了加密,例如SSH的流量,那就無法使用簽名的方式來檢測。
我們也可以通過找規律的方式去檢測,例如負載的長度不一致、請求和響應報數不一致、負載內容相似度等等,包括可以使用suricata的lua規則。但這類規則維護起來比較麻煩,且在公網流量中測試誤報較多。
對于這些很難用簽名規則檢測的惡意流量,不可能直接用一種規則就能準確檢測出來,首先需要從來海量流量中找到有異常的部分,也就是找線索。
針對ICMP隧道這類流量,相比正常流量,表現出來的規律就是數據的隨機性特別大——沒有規律,這就使得信息熵派上了用場。
信息熵
信息熵可以作為一個系統復雜程度的度量,如果系統越復雜,出現不同情況的種類越多,那么它的信息熵是比較大的。簡單的說就是,信息隨機性越強,熵值越大。
檢測思路
檢測思路其實就是觀察到的異常現象,用代碼語言描述然后落地,但如果沒有點數學基礎,實現起來就比較費時費力。
具體步驟如下:
首先,采集一定時間內的ICMP流量,計作一段流,作為計算輸入。
然后,針對流中的每次ICMP通訊中的負載進行熵計算。
最后,對所有熵計算標準平方差。
如果標準方差為0,則說明這些負載都一樣;如果標準方差越偏離0,則說明負載隨機性很高,不是正常的ICMP通訊。
代碼實現
根據信息熵計算的原理,即“對不重復數據的計算,且負載中的不重復數據的數量一定小于報文長度”,通過計算報文的熵,最后進行標準方差計算,部分代碼如下。
獲取報文熵:
//判斷是否存在 intIsRepeat(int x,u_char y,u_char** z){ for(int n = 0; n < x; n++) { if(z[0][n] == y) { z[1][n] += 1; return1; } } return 0; }
//返回存在個數intRepeatCount(u_char* x,int y,u_char** z) { z[0][0]=*x; z[1][0]=1; int maxC=1; x++; for(int n=0;n<y-1;n++) { if(!IsRepeat(maxC, *x, z)) { z[0][maxC]=*x; z[1][maxC]=1; maxC++; } x++; } return maxC; } //log換底公式floatMathLogFunc(float x){ return(x*(log(x)/log(2)));}
//計算報文的熵floatCalcEntropy(int x, int y, u_char** z) { float result = 0;
for(int n = 0; n < x; n++) { result += -MathLogFunc((float)z[1][n]/y); } returnresult; }
floatgetEntropy(u_char* x, int y){ u_char**tmp = (u_char**)malloc(2 * sizeof(u_char*)); for(inti1 = 0; i1 < 2 ; i1++) { tmp[i1] = (u_char*)malloc(y * sizeof(u_char)); memset(tmp[i1], 0, y * sizeof(u_char)); } floatresult = CalcEntropy(RepeatCount(x, y, tmp), y, tmp); for(inti2 = 0; i2 < 2;i2++) { free(tmp[i2]); } free(tmp); returnresult;}計算標準方差://計算平均值floatCalcAverage(float* x, int y){ floattmp = 0; for(inti = 0; i < y; i++) { tmp+= x[i]; } return((float)tmp/y);}
//計算標準方差floatCalcSD(float* x,int y){ float average = CalcAverage(x, y); float tmp = 0; for(int i = 0; i < y; i++) { tmp += (float)pow(x[i] - average, 2); } return((float)sqrt(tmp/y));}
測試效果
通過PTunnel、Nishang等工具制造出一些ICMP隧道的報文,用程序測試看一下效果。
正常ping百度、163等網站的ICMP報文,計算出來的為0:

而計算工具產生的隧道報文時,就看到以下標準方差很大:



3總結
在現網測試時,往往會遇到一些來歷不明的ICMP流量,大多數都是相似的負載,偶爾會夾雜時間戳信息,也會有一些IoT設備發出的流量,調整標準方差來判斷即可。
利用信息熵來檢測ICMP隧道的方式,能有效的解決規則不好描述、難以維護的問題,但對于一些加密、未知的流量,這種方式只是一個線索發現功能,要確認是否是真正的攻擊流量,還需要借助其他數據信息進行綜合判斷。