基於Lua插件化的Pcap流量監聽代理
*本文原創作者:糖果L5Q,本文屬於FreeBuf原創獎勵計劃,禁止轉載
1.前言
我們在實際工作中,遇到了一個這樣的用例,在每天例行掃描活動中,發現有些應用系統不定期的被掃掛,因為我們不是服務的製造者,沒有辦法在不同的系統里列印日誌,所以我們就想用一個工具來獲取特定服務的輸入數據流。我們如果不在IDS上看應用的服務,可以直接針對服務所在服務位置,針對應用埠進行,有針對性的監聽分析。
Tshark和tcpdump、windump這些監聽工具提供了比較豐富的命令行參數來監聽流量數據。wireshark、burpsuite這些工具也提供相應的lua、python腳本的機制用於去處理監聽的流量數據。但有些場景我們不會使用體積這麼大的工具,命令行方式的監聽工具又不能加入更多數據處理邏輯,細化對數據的操作。實際上我們可以自制一個小型的工具,做流量監聽,是除了命令聯合shell腳本,、wireshark、suricata等插件開發的另一種形式。現在很多的監聽工具都是基於pcap的,我們基於pcap底層開發一個監聽工具。
pcap支持C、python兩種開發方式,基於C和pcap庫的開發效率比pyton的性能高,這樣在高性能的場景python就不太適合,但是從開發效率角度看,用python開發比C又要快很多,畢竟用C開發工具,需要進行邊編譯,一是有技術門檻,另外的確維護相對比較麻煩。
鑒於以上的原因,既要性能相對夠高一些,又能便於維護,在命令行這個粒度上,又可以嵌入自己數據處理邏輯,定製化自己的運行時序,因些,我們選擇了C和LUA配合的這種方式。實施方面,就是用C來處理pcap的主件循環,接受pcap監聽的buffer數據。然後,將監聽的數據通過C與LUA之間的通信,將數據推送給LUA。
數據交給LUA之後,如何管理數據的複雜性就靠LUA的設計方式來解決,因為流量數據是文本流式的,程序原型就想到了pipeline管道的方式進行組織管理。
有了管道的方式,我們就可以在一個監聽數據流上,疊加各種插件進地監聽數據的處理,可以把複雜的業務,拆解成若干個小的插件處理單元,寫作完成任務。演示原型代碼的C部分是很少的,主要的任務是獲取buffer的數據,推送lua,代碼如下:
2.PCap的C語言實現
C部分將監聽的流量buffer的數據,以數組的形式給lua,在lua中array其實就是一個table,我們在lua部分重組了一下數組數據,生成了一個字元串,代碼如下:
編譯C程序就靠下面的命令行,後期我們也可以生成一個makefile簡化編譯流程。
為了方便 ,我們寫了一個Makefile:
3.Lua與管道插件設計
為什麼要使用管道插件的方式拆分和組織模塊?以什麼形式傳送數據變成了一個手藝,解耦最直接的方法是分層,先把數據與為業分開,再把業務代碼和共通代碼分開。數據層對我們系統來說就是規則,系統使用的共通代碼都封裝到了框架層,而系統功能業務共通的部分,以插件為機能單位分開並建立聯繫。數據是面象用戶的,框架是面向插件開發者的, 插件的實現就是機能擔當要做的事情,不同的插件組合相對便捷的生成新機能,也是插件便利的益處與存在的意義。
因為管道中的插件是會被順序調用的,因此插件模板中的init和action函數也會被正常的回調,而這些回調函數在被調用時,管道系統會把流數據push給單元插件,而接到數據流的插件在接到回調push過來的數據後,進行相應的判斷篩選,將編輯後的數據通過sink插槽push給後面的插件,直到管道尾端的插件報警或是記日誌,一次管道啟動運行的時序就結束了。
這是一個稍微圖型化的pipeline示意圖:
我們用代碼說明管道的實現更直觀,代碼如下:
字元型式的管道圖示:
我們通過LUA特有的類組織方式構建了一個順序的管道數據結構,管道中的插件是按聲明的先後順序來執行的。pipeline管道程序的主要邏輯就是管理回調函數的調用,代碼如下:
插件抽像出了幾個特的函數給開發用戶,時序是事先設計好的,最主要的數據和回調也明確了,主要是Pipeline.run統一回調了幾個模板的函數,init、push、match函數,這樣頂層的設計幾乎是固定的,之後所有的業務邏輯都在模板了,按這個時序執行,而插件之間的數據傳遞依靠的就src和sink這個插件。
基於管道插件的設計特點就是之前的插件會把源頭的數據推送給後面的插件,如果管道中的數據在之前被編輯過,會體現在後面的插件接受數據後看見變化,具體的實現,代碼如下:
source_plugin是一個典型的插件模板,所有被pipeline回調函數都一目了然,但對於插件的使用來說,可以完全不用關心內部細節,只關心一個函數就行了,就action(self, stream)這個函數,能提供的所有數據都已經被保存到stream這個數據結構里了,對監聽的所有後期處理都從這裡開始。如果創建一個新插件呢?就是複製源文件改一個名就行了,創建了一個filter_plugin的插件,代碼如下:
生成了這個文件,我們在管理里加入這個插件就OK了,代碼:
管道圖示:
我們在這個管道圖示的後面,看到多了一個syslog-plugin的插件,這個插件追加的功能就是將前面插件處理的流數據,通過syslog協議,將數所存到遠端的syslog伺服器上,集中到大數據日誌中心進行分析展示,這樣這個程序就是一個簡單的監控代理的模型。下面我們將程序過行起來,看一下執行的效果。
4.應用實例
當你取得了流量數據後,理論上我們想幹什麼,由我們的想像力決定,在實際的應用場景中,我們像不深入一個應用的部分,就想得到這個應用的輸入數據,比如這個應用是一個HTTP SEVER,Openrety服務,我們能不能通過啟動這個監聽程序,來取得對某個nginx服務的用戶請求的agent數據呢,其實這個演示程序可以做到,我們構造一個簡單的請求。
然後我們,啟動這個腳本程序:
我們只是在 flter-plugin這個lua插件中,對action()回調函數,添加了一個簡單的處理,就捕獲到了User-Agent的信息含有」pcap」的數據。
5.總結
實際上我們通過把流量數據轉發給Lua,讓Lua處理更高級的數據檢索需求,在實際的工作中,有些應用的訪問者會給出非正常的垃圾信息。如果某些應用輸入臟數據,直接會造成程序崩潰,程序又不輸出日誌,這種機制的流量監聽就會有應用場景了,比方說,我們進行大量的掃描行為了,會發出一些某些程序之前預料之外的數據,為了還原是具體那條掃描把程序弄掛了,我們就可以靈活的寫一個lua插件,捕獲臟數據。
這程序只是一個拋磚引玉,我們直接通過C加Lua的方式,靈感來自至Nginx + lua , 就是現在流行的openresty伺服器,又可以用到C的高性能,又使用Lua提高了後續處理的靈活性。如果要處理更大流量的單機流量監聽,應該後續加入環形buffer 緩存數據,如果直接將日誌數據syslog到遠埠的syslog服務上,我們就可以使lua開發一個插件,做syslog轉發就好,這就是當時考慮使用lua管道設計做這個實驗工具的目地。
現在我們做的工作就類似是,讓tcpdump支持lua插件擴展。
文中提到的代碼,放到了Github上:https://github.com/shengnoah/riff
*本文原創作者:糖果L5Q,本文屬於FreeBuf原創獎勵計劃,禁止轉載


※相冊類木馬專題分析
※我是怎麼打開車庫門的:ASKOOK手動解碼及重放
※為什麼朝鮮格外關注加密貨幣
※婚戀網站背後,可能藏著精心設計的釣魚攻擊
TAG:FreeBuf |