鄧兆琨, 陸余良, 黃釗, 黃暉, 朱凱龍
(國防科技大學電子對抗學院, 合肥 230037)
隨著互聯網技術的不斷發展,網絡安全問題得到越來越多人們的關心,網絡程序作為用戶使用互聯網的重要媒介,其自身存在的漏洞問題也為網絡用戶安全造成了巨大的隱患。攻擊者利用網絡程序存在的漏洞,對用戶節點和服務器節點展開的攻擊層出不窮。現階段針對網絡程序安全展開的工作主要分為兩類:一類是通過白盒、灰盒、黑盒等測試手段對網絡程序的源代碼或二進制代碼進行檢測,從而發現高危代碼區域和漏洞點;另一類是通過監控程序上線運行的過程,發現程序產生運行異常的節點以及導致程序異常的輸入數據。相比于前者,后者針對漏洞的檢測成功率更高,但在發現漏洞的時間上相對被動,對漏洞的發現往往滯后于攻擊破壞的產生[1]。
本文研究和分析了現階段的3種主要網絡程序結構及其典型漏洞,同時,對C/S結構下網絡程序的漏洞檢測技術進行了研究。在這一基礎上提出了一種基于程序建模的網絡程序漏洞檢測技術,并利用該技術實現了一套網絡程序漏洞檢測系統。該技術對不同I/O模型下的網絡程序進行關鍵函數提取并進一步構建程序模型,通過API函數掛鉤的方式引入符號變元,對程序模型進行符號執行,通過程序模型識別和關鍵函數插樁的方式對程序二進制代碼進行分析。當程序執行異常時得到觸發異常位置的符號約束集,通過約束求解得到觸發異常的具體輸入和異常點,實現對目標網絡程序漏洞的檢測。
網絡程序主要存在3種結構類型:C/S結構、B/S結構和P2P結構。這3種結構分別有著自身的優缺點,根據網絡環境和用戶使用需求的不同,程序開發者采用的結構也不同,且三者之間相互聯系,并沒有嚴格意義上的區分[2]。
C/S結構下的網絡程序由客戶端和服務器端共同組成,通過將網絡任務合理地分配到網絡程序的雙端,達到降低系統開銷、充分利用雙端軟硬件條件的目的[3-4]。C/S結構下網絡程序的雙端建立連接后會一直保持連接狀態,任何一方都可以實時地向對方發送信息或文件。如微信、QQ等即時通信軟件,通過安裝在電腦上的客戶端向騰訊的服務器發送數據,而騰訊的服務器也可以實時向本地的客戶端回復信息和文件請求。該架構下的大量工作在客戶端進行,服務器端作為中介節點執行保存、轉發功能,雙端信息交互有著實時轉發、一對一通信、點對點單線傳輸的特性,現階段如QQ、微信、迅雷、快播、暴風影音等眾多商業軟件都采用該結構。C/S結構下的網絡程序,除了協議解析和對數據提取模塊外,客戶端和服務器端在本地運行過程中的原理和普通二進制程序基本相同,因此,其本身存在的漏洞也以典型的二進制程序漏洞為主,如堆棧等緩沖區溢出漏洞、格式化字符串漏洞等。
B/S結構是在C/S結構的基礎上變化、改進而來,主要是為滿足互聯網用戶通過瀏覽器瀏覽、查詢信息的需求。B/S結構下網絡程序的客戶端一般以瀏覽器的形式存在,客戶端僅實現部分邏輯運算和信息處理,而將大部分的運算和需求處理交付給服務器端實現。該架構用于支持多人訪問的門戶網站或論壇,如搜狐、新浪、微博等,該類情況下無需信息的實時性,但需要其長期有效[5]。B/S結構下網絡程序的服務器端為網站服務器,但客戶端瀏覽器的結構和功能得到簡化,由于HTML等網絡編程語言的特性,導致網站本身(服務器端)和瀏覽器(客戶端)存在的漏洞以典型的web漏洞為主,如SQL注入,XSS跨站腳本漏洞,CSRF跨站請求偽造,文件上傳等。
P2P結構是一種最新提出的網絡程序結構形式,目的是適應點對點網絡中程序開發的需求,該結構最大的優點是分布性和共享性[6]。但由于取消了服務器端的存在,網絡用戶以服務器端和客戶端的雙重身份出現在網絡中,導致了網絡可信性的下降和網絡資源的丟失。同時,由于客戶端高度分散難以管理的缺點,導致現今互聯網上并不存在純P2P結構的網絡程序,在應用過程中P2P結構網絡常和前兩種結構混合使用,除了搭載在各個客戶節點的客戶端外,一般仍會布置一臺或多臺中心服務器,用來保存核心資源起到維持網絡的作用。根據混合結構的不同,該結構下網絡程序中存在的漏洞也同樣以C/S結構和B/S結構本身的漏洞為主。
現階段,研究人員針對不同結構下的網絡程序漏洞已進行了相關研究,并基于各項研究形成了一些相關工具。文獻[7]就針對B/S結構下的瀏覽器端漏洞挖掘進行了研究,其通過特征提取的方式制定漏洞模板,并利用此類模板進行漏洞檢測,其對于XSS和SQL注入等web漏洞有較好的檢測效果,特別是在可視化方面實現較好。文獻[8]同樣針對XSS和SQL注入等web漏洞進行挖掘,不同的是其采用了Fuzzing技術,通過構造大量隨機輸入的方式執行目標程序尋找漏洞點,該挖掘方法的效果較為直接,針對挖掘到的漏洞也能很好地提供相關信息和觸發POC。文獻[9]在Fuzzing技術的基礎上提出了一種結合了動態污點分析的漏洞檢測技術,針對C/S架構下的網絡程序二進制漏洞進行檢測,實驗證明該方法針對協議漏洞有較好的效果。文獻[10]提出了一種基于QEMU虛擬機的二進制程序離線動態污點分析方法,該技術通過硬件虛擬化的方式提高了污點分析過程中的執行效率。文獻[11]使用符號執行技術對B/S結構下瀏覽器端存在的Use-After-Free漏洞進行檢測并實現了一套檢測工具,該工具針對Use-After-Free漏洞進行了模型分析和開發,因此針對性更強。
作為一種重要的漏洞檢測手段,符號執行技術將具體的輸入值替換為符號變元,通過監控數據流的方式記錄程序的執行軌跡,并實時收集與符號變元相關的路徑約束條件,當一條路徑執行完畢后,系統會恢復到上一分支節點探索新的執行路徑。通過對程序進行全路徑分析的方式尋找觸發程序崩潰的位置,求解從程序起始點到達該點的路徑約束集,就能夠同時得到漏洞點和觸發該漏洞的POC輸入[12-14]。
早期的符號執行技術主要采取了靜態分析的方式,這主要是受限于計算機系統軟硬件的性能,該方式在不運行程序的前提下通過程序代碼分析的方式獲得執行約束,能夠極大地降低系統消耗,但由于缺少程序執行過程的動態信息導致分析過程的代碼覆蓋不夠準確[15-16]。之后研究人員針對該問題提出了動態符號執行思想,通過真實運行目標程序的方式檢測漏洞存在點,該方式提高了漏洞發現的準確率,但隨著程序規模的擴大出現了路徑爆炸的問題,特別是隨著路徑復雜度的提升路徑約束的復雜度也隨之提升,受限于約束求解器的性能,導致符號執行技術一直沒有得到更好的應用和發展。隨著2009年選擇符號執行的提出,該問題得到了一定程度上的解決。該技術的思想核心首先是對執行位置和區域的“選擇”,如圖1所示,通過選擇符號執行技術將符號執行區域限制在網絡程序的核心函數調取部分,而針對非程序核心或者一般性程序代碼區域進行具體執行過程,這樣,有效地降低了系統運行開支,同時降低了符號約束求解過程的復雜度。
S2E系統由瑞士洛桑理工大學的Chipounov等[13]開發,該系統基于選擇符號執行技術構建系統框架,提供了基本的功能性插件模塊。例如,開發者能夠通過Selection Plugins類插件制定注入符號值的位置和選擇執行的路徑,當OS Event Monitor類插件中的Module Execution Detector截取到系統對目標函數的調用時,會發送信號給執行插件,此時系統會跳轉執行定義好的行為或者啟動符號執行過程。
本文原型系統采用了選擇符號執行技術,系統基于S2E符號執行平臺進行開發,其中QEMU虛擬機為待測試程序提供了模擬運行環境,并為運行提供全系統的執行監控;LLVM提供二進制翻譯,將二進制代碼翻譯為可供符號執行引擎使用的中間級代碼;KLEE進行符號執行。同時,針對不同種類的網絡程序進行架構抽取并建立函數模型。與以往的技術相比創新點主要體現在3個方面:一是針對目標程序進行全系統模擬,能夠更好地發現目標程序存在的真實漏洞,而選擇符號執行技術能夠將符號執行的區域集中在敏感區域,有效地降低了符號執行的路徑爆炸問題;二是建立了不同類型網絡程序模型,通過目標識別的方式調取不同模塊,檢測的針對性更強;三是抽取 程序運行過程中的關鍵函數進行函數掛鉤和掛鉤執行語義定制,通過監控符號執行的過程記錄符號約束表達式,針對出現的程序崩潰進行約束求解,能夠直接定位到程序漏洞點和觸發漏洞的具體輸入。

圖1 選擇符號執行技術Fig.1 Technology of selective symbolic execution
S2E平臺對自身框架代碼進行了開源,并提供了5種功能性插件供給開發者進行調用,該5類插件分別為:系統事件監控插件、執行跟蹤插件、選擇性插件、分析類插件和其他類插件,插件間能夠相互調用。通過開發功能性插件的方式對該平臺進行針對性開發,通過lua腳本操作原型系統的執行狀態和執行情況。
原型系統在執行區域選擇、執行語義定制和符號化數據引入的環節上,采用了系統API函數掛鉤的技術。通過在函數調用的起始點和返回點掛鉤,首先可以得到系統函數服務提供過程的具體執行語義信息,其次通過截取函數調用的信號,可以控制符號變元引入的位置,間接控制了具體執行和符號執行的實際切換位置。
如圖2所示,基于選擇符號執行技術思想,原型系統在QEMU虛擬機環境下正常啟動目標程序開始具體執行。當程序執行到目標區域的起始位置時,Windows Monitor會捕獲到操作系統對掛鉤的系統API函數調用,同時將信號發送給模型模塊中的執行插件,執行插件中記錄了與目標位置相對應的執行語義。當目標區域執行完畢,程序執行到結束位置時,系統會截取到結束位置API函數的調用信號,當該函數執行結束時會觸發返回點的函數執行語義跳出符號執行過程。

圖2 選擇符號執行系統運行過程Fig.2 Operational process of selective symbolic execution system
符號變元的引入通過“系統插件+lua腳本”的方式實現,根據不同的通信協議設置了符號變元的引入規則,其中定制的原型系統插件提供變元引入的具體操作,lua腳本制定了符號變元引入的具體規則。網絡中數據以字節流的形式傳播,與一般程序接收的輸入不同,網絡程序除了接收消息之外,還會接收傳輸的文件等,但無論是消息信息或文件數據,這些內容都是以網絡字節流的形式傳輸,因此本系統選擇通過字節流的方式引入符號變元。圖3所示是lua腳本中基于TCP協議的符號變元引入策略。

圖3 符號變元引入策略Fig.3 Symbolic variable introduction policies
原型系統基于STP約束求解器進行約束求解。首先,在執行的過程中會對每個執行分支節點的約束條件進行收集,2條相反路徑的約束會通過取反的方式分別記錄在2條不同路徑的約束條件集中,新約束條件通過取并集的方式添加。STP約束求解器提供了符號變元的構造器和在此基礎上的一階邏輯中各種表達式的構造器、符號公式的可滿足性判定器以及反例求解器。該求解器基于整數和位向量理論進行開發和編寫,能夠滿足大多數網絡程序執行路徑的約束求解要求。
網絡程序模型的組成包括開發者定義的個人函數以及調用的內核API函數。在Windows平臺下,網絡程序運行的過程中主要調取的是winsock函數庫,特別是在XP系統之后,微軟已將winsock2作為內核函數庫寫入了操作系統本身。從最原始的阻塞模型,到之后的select模型、WSAAsycSelect模型、Overlapped模型、IOCP模型,不同程序模型調用winsock庫中函數種類以及順序的不同決定了不同模型下網絡程序的運轉方式。本文原型系統針對不同網絡程序模型開發了針對性執行子模塊,基于模型識別的方式對不同模型下的網絡程序進行漏洞檢測。
阻塞模型即最早的一類網絡程序模型,該類模型基于Winsock API函數實現服務器和客戶端之間的通信。該模型運行過程中采用單線程的方式。在本次連接通信未完成、連接未斷開前,新的客戶端只能不斷地發出連接請求,等待新的連接。當正在進行的服務過程結束、本次連接斷開后,服務器端才接受新的連接請求并提供服務。
圖4為阻塞模型下的通信模型及通信過程,通過關鍵函數抽取的方式本文建立了網絡程序的阻塞模型。
針對模型中的關鍵函數進行掛鉤,并針對掛鉤后函數,定制特殊的執行語義,當系統執行到模型的節點函數時將觸發定制的操作,啟動符號執行過程。如圖5所示,針對程序運行過程中數據接收、處理的關鍵函數的調用點和返回點進行掛鉤,從而實現針對該模型下網絡程序的漏洞檢測,提高檢測過程和實際程序代碼的貼合率。

圖4 阻塞通信模型Fig.4 Blocking communication model

圖5 阻塞通信模型執行模塊部分代碼Fig.5 Part of execution module code of blocking communication model
select類網絡程序是網絡程序發展過程中實現的第1種非阻塞網絡程序,該類程序基于單進程實現,但其在阻塞類程序的基礎上實現了多套接字管理。通過程序分析發現,在該類程序中select函數負責了套接字的申請、分配和調度,因此在模型建立過程中重點對select及其附屬函數進行執行監控和漏洞檢測。定制select_call_hook()的掛鉤語義對readfds(檢查可讀性)、writefds(檢查可寫性)、exceptfds(檢查錯誤)等敏感變量進行符號化,通過收集該符號變元在執行過程中的路徑約束,監控該變量的傳播過程。針對執行過程中涉及權限檢查的部分進行重點監控,因為該部分往往是程序代碼的高危區域之一。針對select函數執行點進行掛鉤如下:
int select
(
int nfds,
fd_set* readfds,
fd_set* writefds,
fd_set* exceptfds,
const struct timeval* timeout
);
如圖6所示,當有網絡事件發生時,socket函數會建立對應的套接字處理接口,select函數會修改對應套接字接口的相關屬性,將套接字句柄添加到對應的屬性集合之中,從而賦予新的套接字接口新的權限。據此分析,程序代碼在該位置存在多次調用和反復的修改,在執行點掛鉤的基礎上,通過定制select_ret_hook()的掛鉤語義,檢查select函數的返回值和該值的傳遞路徑,判斷是否存在脆弱節點。

圖6 select模型執行過程Fig.6 select model execution process
IOCP類程序基于多線程并行處理器完成網絡程序客戶端的服務請求,該類網絡程序運行后會預先創造提供服務的線程池,與在接受請求時創建線程相比效率更高,Apache等高性能商業服務器程序均采用該架構進行開發。通過模型分析發現,在運行過程中,該類網絡程序采取兩類線程并行的方式:主線程負責監聽和創造任務線程,并完成接口關聯等操作;任務線程負責處理用戶請求,為用戶提供服務。任務線程處理請求過程中為接收用戶數據申請的緩沖區,該類內存空間操作往往是程序代碼存在漏洞的高危區域,需要重點進行程序運行監控和代碼分析,具體如下:
……
#define BUFFER_SIZE 1024
typedef struct _PER_HANDLE_DATA
{
SOCKET s;
sockaddr_in addr;
} PER_HANDLE_DATA, *PPER_HANDLE_DATA;
typedef struct _PER_IO_DATA
{
OVERLAPPED ol;
char buf[BUFFER_SIZE];
int nOperationType;
} PER_IO_DATA, *PPER_IO_DATA;
……
針對該類網絡程序進行建模,抽取了從服務連接建立到終止過程中的關鍵函數,同時作為該模型核心,對GetQueuedCompletionStatus()函數的執行點進行掛鉤,并定制特殊的函數執行語義。事件發生后I/O系統會向完成端口對象發送完整消息通知,GetQueuedCompletionStatus()函數會按照順序優先級的方式讀取隊列封包,通信過程每一個連接的相關輸入和參數見下文代碼,此時針對如lpNumberOfBytes等危險區域或變量進行執行監視,則有可能得到觸發程序崩潰的漏洞點。
BOOL GetQueuedCompletionStatus
(
HANDLE CompletionPort,
LPDWORD lpNumberOfBytes,
PULONG_PTR lpCompletionKey,
LPOVERLAPPED* lpOverlapped,
DWORD dwMilliseconds
);
本文提出了一種基于程序建模的網絡程序漏洞檢測技術,并利用該技術實現了一套多模型網絡程序漏洞檢測系統。系統共分為4個模塊:目標模型識別模塊、網絡程序模型模塊、網絡程序漏洞檢測模塊、漏洞記錄模塊。圖7所示為該原型系統的架構。

圖7 系統原型架構Fig.7 System prototype architecture
檢測過程主要分為以下5步:
1) 目標程序傳入檢測系統后,目標模型識別模塊會對目標程序所屬的網絡程序類型進行判斷,并從網絡程序模型模塊中調用相應模型的子模塊。同時,將目標程序傳入檢測運行環境中(QEMU虛擬機)。
2) 網絡程序模型模塊會將對應模型子模塊的調用信號發送給網絡程序漏洞檢測模塊,同時啟動漏洞檢測過程。
3) 針對目標程序進行檢測,并記錄不同路徑的約束條件,如果碰到程序崩潰則記錄到達對應崩潰點的約束條件集。
4) 將能夠到達崩潰點的約束集交給約束求解器進行求解,將結果發送給漏洞記錄模塊。
5) 漏洞記錄模塊記錄崩潰點的相關信息和導致崩潰的具體輸入。
該系統基于S2E框架進行開發,采用了模塊化的組成方式,最初版本的系統僅包含阻塞類模型,通過后期開發已經拓展到了4種主流模型。原型系統采用“系統-功能模塊-子模塊”的三級結構設置。系統會判定程序所屬的模型,并根據模型種類調用相應模型的漏洞檢測子模塊進行漏洞檢測過程,調用記錄模塊對相應的脆弱點進行分類和記錄,全系統能夠針對目標網絡程序實現自動化的漏洞檢測過程。
本文以QEMU虛擬機下WindowsXP-SP3操作系統為測試環境進行實驗,實驗環境配置如表1所示。
實驗過程分為兩部分進行,首先針對每種類型的網絡程序編寫了較為簡單的測試用例,并針對各類測試用例進行試驗。實驗結果證明原型系統可以穩定運行,并針對不同類型的網絡程序進行漏洞檢測。
其次,從CVE漏洞庫中選擇了2個已知漏洞作為實驗對象,這2個漏洞均存在于商業化網絡程序Tftpd32中,該程序軟件基于TCP通信協議開發,能夠實現數據文件的發送和接收,結果如表2所示。
如圖8所示,通過QEMU監視器可以看到,系統能夠識別操作系統版本,并定位到Tftpd32運行過程中需要調用的系統函數,實現對程序調用函數的掛鉤和監控。此時,啟動客戶端程序和服務器端建立連接,并向服務器發送數據。可以發現服務器端接收到網絡數據后會觸發掛鉤函數的語義內容,系統針對本次輸入啟動選擇性符號執行過程。
如圖9所示,服務器端針對符號執行過程的路徑約束進行收集,對分支節點的自身狀態進行保存。同時,向客戶端發送指令,要求其保存對應執行節點下的狀態信息。
通過客戶端的QEMU監視器可以看到以服務器端為中心的漏洞檢測過程。通過圖10可看 出,系統執行到了服務器端程序某一路徑的終點需要回溯到上一分支節點,此時,服務器端通過指令成功使客戶端恢復到了相同節點狀態。

表1 實驗環境配置Table 1 Experimental environment configuration

表2 實驗結果Table 2 Experimental result

圖8 實現函數掛鉤Fig.8 Function hook realization

圖9 服務器端符號執行過程Fig.9 Symbolic execution process of server

圖10 客戶端狀態保存及回置Fig.10 Client state savinges and restoringes
通過穩定的實驗測試過程,系統能夠檢測到針對Tftpd32的2款漏洞。為了驗證系統的穩定性,在平臺上對測試目標進行了500次重復試驗驗證,其中464次實驗正確探索到了2種程序缺陷所在的執行位置,25次實驗探測到了CVE-2006-6141缺陷所在位置,11次執行產生了誤報,反饋了無異常點的信息,整體性能較穩定。誤報率和漏報率較低。
1) 系統針對網絡程序各模型的漏洞檢測進行了可行性拓展,能夠適應現階段約85%的網絡程序目標,針對另外2種模型的適配也在進一步開發之中。
2) 相比于本文中提到的幾款漏洞檢測系統,本系統對C/S架構下網絡程序漏洞檢測的針對性更強,代碼覆蓋率更高,通過對不同模型網絡程序的針對性開發,目標區域函數代碼的覆蓋率可以提高到90%以上。
3) 針對目標程序所屬模型的判斷雖然增加了系統的開銷,但在后期的檢測過程中可以提高檢測效率和漏洞發現的準確率。
4) STP約束求解器為本系統提供了符號化支撐和求解,該求解器能夠針對非浮點數計算類指令進行求解分析。
5) 漏洞信息的記錄和導出采取了文本記錄的方式,隨著實驗的推進,實驗目標和漏洞信息不斷增多,在后期的開發中將結合數據庫技術思想添加數據管理模塊,對漏洞信息進行數據庫管理。
為提高本系統的實用性和檢測效果,下一步開發將重點進行網絡程序模型的探索和構建,進一步增強該系統的普適性,同時,進行針對大型網絡程序軟件的檢測實驗。