漏洞挖掘高級方法

作者:安全小子

投稿方式:發送郵件至linwei#360.cn,或登陸網頁版在線投稿

前言

在此文中我將講述我在軟體漏洞挖掘的實踐中學到的技術及方法,不過這些內容並非那些前沿的技術,大多是基礎類型的技術及方法。對於初學者而言,希望能夠給予入門的指導,對於經驗豐富的漏洞挖掘工作者而言,我認為也可以從中獲得一些啟發。

受限於我個人的知識水平及能力,這篇文章並不可能做到面面俱到,也希望閱讀者能夠與我積極交流,對於其中的錯誤不吝賜教。

我將會把此文分為三個章節,分別闡述我的觀點。首先我會從一個較高的角度總結於我眼中何謂漏洞挖掘;然後詳細討論在軟體漏洞挖掘過程中我們需要掌握的技能以及需要的知識和工具等;最後我將談談一些我認為有利於漏洞挖掘但是卻並非純技術性的想法。

一、什麼是漏洞挖掘

從某個角度來講,我們可以將漏洞挖掘工作比作玩迷宮遊戲,不同的是,這個迷宮與我們平時所見的遊戲中的迷宮略有不同:

1. 你無法立即看到它整體的外觀

2. 隨著漏洞挖掘工作的深入,這個迷宮的形狀逐漸擴大

3. 你將會擁有多個起點及終點,但是無法確定這些點具體在哪裡

4. 最終這個迷宮可能永遠也無法100%的完整,但是卻能夠弄清楚A點至B點的一條完整路徑

可以用下面這張圖來進行描述:

具體一點的描述,我們可以將漏洞挖掘工作歸結為三個步驟:

1. 枚舉程序入口點(例如:與程序交互的介面)

2. 思考可能出現的不安全狀態(即漏洞)

3. 設法使用識別的入口點到達不安全狀態

即是說,在這個過程中,迷宮是我們研究的應用程序,地圖是我們堆程序的理解程度,起點是我們的入口點(交互介面),終點為程序的不安全狀態。

所謂入口點,既可以是UI界面上直觀可見的交互介面,也可以是非常模糊與透明的交互介面(例如IPC),以下是部分安全研究員較為感興趣的關注點:

1. 應用程序中比較古老的代碼段,並且這一部分隨著時間的推移並沒有太大的變化。

2. 應用程序中用於連接由不同開發團隊或者開發者開發的程序模塊的介面部分

3. 應用程序中那些調試和測試的部分代碼,這部分代碼本應在形成Release版本時去除,但由於某些原因不小心遺留在程序中。

4. C-S模式(帶客戶端和服務端)的應用中客戶端及服務端調用API的差異部分(例如網頁表單中的hide屬性欄位)

5. 不受終端用戶直接影響的內部請求(如IPC)

我認為從攻擊面上來劃分可以講漏洞分為兩大類,通用漏洞(General)和上下文漏洞(contextual)。通用型漏洞是指在我們對應用的業務邏輯不是非常熟悉的情況下能夠找出的漏洞,例如一些RCE(遠程代碼執行)、SQLi(sql注入)、XSS(跨站)等。上下文漏洞是指需要在對應用的業務邏輯、認證方式等非常熟悉的情況下才能找到的漏洞,例如許可權繞過等。

在漏洞挖掘的過程中,我首先會根據經驗優先考慮研究測試那些可能會對應用產生巨大威脅的部分。一些輕量級威脅檢測模型(如STRIDE)可以輔助我們做出這樣的決策。

下面我們首先看一下一個WEB應用程序的漏洞示例,後面將會介紹桌面程序:

首先我們假設目標web應用是一個單頁面應用(single-page-application SPA),我們已經獲得合法驗證去訪問這個應用,但是我們沒有任何關於服務端的源代碼或者二進位文件。在這種情況下,當我們枚舉入口點時,可以通過探尋該應用的不同功能來進一步了解其業務邏輯及功能,可以通過抓包分析看HTTP請求內容,也可以分析客戶端的網頁代碼獲取需要提交表單的列表,但是最終的限制還是我們無法具體知悉客戶端和服務端調用的API之間的區別,不過通過以上方法,我們可以找到一些入口點,

接著就是操作這些入口點,以試圖達到我們預期的不安全狀態。由於漏洞的形態很多,我們通常需要構建一個適用於該測試應用程序的業務功能漏洞的測試集,以求達到最高效的尋找漏洞。如果不那樣做的話,我們就將會在一些無用的測試集上花費大量時間,並且看不到任何效果(舉個例子,當後台的資料庫為Postgresql時,我們用xp_cmdshell去測試,測試再多次都無濟於事)。所以在構造測試集時,需對應用程序的邏輯有較深的理解。下圖形象的展示了低效率測試集的效果:

對於桌面應用程序,漏洞挖掘的思路本質上與web程序是類似的,不過也有一些區別:最大的區別在於,桌面應用的執行方式與流程與web程序不一樣,下圖展示的是桌面應用漏洞挖掘的一些內容:

與黑盒測試相比,當有源代碼時(白盒測試),在尋找代碼入口和程序執行路徑等漏洞挖掘點時所做的猜測性的工作會大大減少,在這種情況下,將數據載荷從入口點執行到不安全的程序位置的效率低於從不安全的程序位置回溯至入口點。不過在白盒測試中,你對代碼的測試的覆蓋面可能會由於你自己的知識局限性而受到影響。

二、漏洞挖掘需要具備的知識

從事漏洞挖掘工作需要具備的知識是極其廣泛的,並且隨著時間在不斷改變,也取決於你所研究的對象(web程序、桌面程序、嵌入式等等)。不過,萬變不離其宗,所需要掌握的知識領域卻總可以認為是確定的,我認為大致可以分為以下四個方面:

1. 程序正向開發技術。這是一個開發者需要掌握的能力,包括編程語言、系統內部設計、設計模式、協議、框架等。擁有豐富編程經驗與開發能力的人在漏洞挖掘過程中往往比那些只對安全相關領域有所了解的人員對目標應用能有更深入的理解,從而有更高的產出。

2. 攻防一體的理念。這些知識涵蓋了從基本的安全原則到不斷變換的漏洞形態及漏洞緩解措施。攻擊和防禦結合的理念,能夠有效幫助研究者既能夠發現漏洞,同時也能夠快速給出有效的漏洞緩解措施和規避方法。

3. 有效使用工具。能夠高效的使用工具能夠快速將思路轉化為實踐,這需要通過花時間去學習如何配置和使用工具,將其應用於自己的任務並構建自己的工作流程來不斷積累經驗。更進一步,需要深入掌握所使用工具的原理,以及如何對其進行二次開發,以使得其能夠更加高效的應用於當前的工作實際。事實上,我認為面向過程的學習方法往往比面向工具的學習方法更加高效以及有價值,當自己發現一個在使用一個工具遇到瓶頸時,先不要退縮,嘗試去改造它,或者通過自己動手實踐去完成能夠適應當前工作的工具,這往往能夠幫助快速積累大量實踐經驗。幫助我們以後更加高效的去實踐漏洞挖掘工作。

4. 對目標應用的理解。最後,也是最重要的,作為一個漏洞挖掘人員,對自己研究的應用程序在安全性方面必須要比這個程序的開發者或維護者有更深的理解。這樣你才能儘可能的發現這個程序中的漏洞並修復它。

下面這張表格介紹了我認為在挖掘web應用程序和桌面應用程序的漏洞時所需要掌握的內容,限於筆者個人的認知水平,所展示的內容並非特別齊全:

這是我經過無數的不眠之夜、數以千計的小時、一次又一次的錯誤而總結的知識,我相信它將會幫助你提高你挖掘漏洞的能力。如果說上面一節是講訴挖掘漏洞所需要的知識,那麼下面的這一節將講述挖漏洞如何做。

三. 漏洞挖掘需要做什麼

當我分析一個應用程序時,我通常採用下圖展示的四個「分析模型」,每當我遇到障礙導致我思路受阻時,我就會從其中一個模型切換到下一個模型,當然,這不是一個線性的切換,我不知道這個方法是否對每個人都有用,但是對於我的確是幫助巨大:

在每一個模型之中都有主動活動(active activities)與客觀活動存在(passive activities),主動活動需要我們對程序的執行環境及上下文有一個比較全面的了解,而客觀活動卻不一定,比如它是客觀存在與程序的一些技術文檔之中。不過,這種劃分也不一定嚴格,不過對於每一個activity,我們可以從以下幾方面去考慮:

1. 理解有關漏洞的相關模型

2. 試圖假設一個場景去破壞程序

3. 嘗試去破壞程序

程序用途分析(Use case analysis)。程序用途分析是指理解一個應用程序做了什麼工作,會提供什麼服務等。每當我去分析一個新的應用程序時,我所做的第一件事就是程序用途分析。同時,閱讀與該程序的相關文檔將有助於進一步理解程序功能(如上圖所示)。我總是這樣做,以期對程序有一個透徹的了解。

或許,比起直接構造測試樣例進行測試,這項工作可能並不是那麼有趣。不過,它的確幫助我節省了一大筆時間。舉一個我自己的例子,我之前發現過Oracle Opera(一個廣泛使用的酒店管理軟體)[CVE-2016-5563/4/5]的遠程代碼執行漏洞,我就是通過閱讀器用戶手冊快速找到可能存在危險的數據表,最後快速找出遠程代碼執行漏洞。有關這個漏洞的分析,請參看:jackson.thuraisamy.me/o

(執行條件分析)Implementation analysis,執行條件分析是指理解應用程序運行時需要包括的環境因素,比如網路配置,埠使用等。可以通過埠掃描,漏洞掃描等方式進行操作。這些配置上的問題,很可能就會導致一個漏洞的出現。

聚個例子,一個系統許可權級別的程序,由於配置錯誤,可能會使的低許可權的用戶能夠訪問並修改,最終導致一個許可權提升,引發一個提權漏洞。又比如,在一個網路程序中,可能程序本身並沒有錯誤,但是由於這個伺服器開了一個anonymous的FTP伺服器,那麼任何人都有可能訪問這個機器,這就導致web應用的源代碼或者其他敏感文件暴露在外面。這些問題,理論上並非程序自身的漏洞,但是由於其執行環境的因素,就使得其成為一個漏洞。

通信分析(Communications analysis)。通信分析是指對一個目標程序與其他進程或系統之間交互信息的方式進行深入分析。在這樣的前提下,可通過發送精心構造的請求(request)等方法,觸發不安全狀態。許多web應用程序漏洞都是通過這種方式發現的。

在上述模式下,需要我們對數據通信協議有較為清晰的認識,如果並不能夠清晰的了解協議格式呢?這種情況就要藉助黑盒測試的技術進行解決,主要通過發送請求,並根據返回值進行判斷是否存在異常。

下面舉個例子來說明,這裡假設存在一個金融網站,裡面有一項功能允許用戶使用不同的貨幣購買預付信用卡。這裡假設實現這項業務的請求(Request)如下:

FromAccount : 用於購買預付卡的賬戶

FromAmount : 需要從fromAccount轉入預付卡的金額(例如 ¥100)

CardType: 需要購買的預付卡類型(例如 USD、GBP

currencyPair : 付款賬戶和預付信用卡的貨幣配對,用於計算匯率(如 CADUSD、CADGBP)

當我們要去測試這樣一個應用程序時,首先我們可能會想到發送一個正常的數據請求,以幫助我們了解該應用程序的標準響應的格式。例如下圖,用CAD去購買82美刀的預付卡的請求和響應是下面這個樣子:

或許我們並不知道程序在後台到底對我們的數據做了何種處理,但是我們通過觀察status欄位的屬性知道我們的請求是ok的,下面如果我們將fromAmount參數調整為一個負數,或者將fromAccount調整為其他某個人的賬戶,那麼這個web應用就可能會返回錯誤響應,比如驗證不通過。另外如果我們將currencyPair從CADUSD(加元對美元)改為CADJPY(加元對日元)而cardType不變,那麼我們會看到返回值中toAmount欄位從82.20變為8863.68。如果程序缺乏足夠的驗證的話,我們有可能通過這種方式獲取到更多的錢而付出的錢不變。

另一方面,如果我們能夠獲取到後台代碼或程序,那事情就變得更加有意思,我們可以輕鬆了解到後台的運作流程,如後台是如何處理請求,有哪些錯誤響應,這將有助於我們構造出更加具有針對性的數據對應用進行測試。

代碼分析(Code and binary analysis)。代碼分析是指理解一個目標程序是如何處理用戶輸入的數據,以及該程序的執行流程。目前有很多方法可以對程序實現動態和靜態分析,下面介紹其中一部分:

數據流分析。數據流分析對於尋找入口點以及數據是如何走向潛在的不安全狀態是非常有用的。當我在通信分析(Communications analysis)遇到困難,很難構造出合適的request,我便會調整思路採取其他的方式尋找不安全狀態,在數據流分析中,我可以使用這種方法,首先判斷是否存在不安全狀態,如果存在,則進一步跟蹤數據是如何流向該狀態。這個方法的有點是,一但發現不安全狀態,入口點也隨之確定,這為發掘漏洞提供巨大幫助。

在這個過程中,動態分析和靜態分析需要緊密配合起來。舉個例子,當你在尋找如何從A點走到B點時,靜態分析就好比是在閱讀一張地圖,而動態分析就好比直接在這地圖上走,需要實時關注路上的天氣及交通狀況,IDA和windbg的配合就是如此。靜態分析可以對程序有一個全貌但不細緻的理解,動態分析則可以對程序有一個狹隘但卻細緻的理解,二者是相互補充的。

外部引用分析。在分析程序的過程中,程序上下文環境中可能非常有限,這個時候分析程序的導入API可以幫助我們進一步了解程序的功能以及它與操作系統的交互方式。比如說,程序引用加密庫對數據進行加密,那麼你可以跟蹤這個加密庫並分析其功能,進而分析自己的輸入是否能夠影響其功能。令外,理解程序是如何與操作系統的交互也可以幫助我們進一步找到我們可以與程序進行交互的入口點。

字元串分析。與外部引用分析一樣,分析程序中的字元串將幫助我們進一步理解程序中的功能,特別是那些調試信息,關鍵字或者令牌什麼的,或者是那些看起來特別奇特的東西,對這些關鍵的字元串的分析及跟蹤也將有利於我們尋找到更多的程序入口,進而更加全面的找出程序中的缺陷。

安全掃描。使用自動化的掃描工具(如PHP源代碼掃描AWS)可能幫助我們快速找到一些常見的漏洞。但是對於尋找基於上下文和基於設計的漏洞並沒有太大幫助。我通常並不會對這種方法有太多青睞,只會用來做一些輔助性的功能,如果單純靠掃描就能找出一堆漏洞,你研究的目標安全做的就太差了,這在目前並不常見,或者說研究這類目標對於提高你自己並無任何幫助。

依賴性分析。一個應用程序往往會以來其他外來的組件,比如一些開源模塊,它所依賴的開源模塊自身存在的漏洞可能會被引入造成自身的未公開漏洞。值得一提的是,現今一個程序往往都是引用了眾多第三方擴展模塊,這些第三方的漏洞極易造成主程序的漏洞。舉個例子,大多數瀏覽器都會使用sqlite做數據緩存,如果sqlite存在漏洞,那麼這些瀏覽器都有可能存在問題,無論是谷歌還是火狐。

版本分析。如果你有機會訪問程序的代碼倉庫,那麼你就可以通過分析歷史版本的方式對程序進行分析,這種方式不是基於上下文的,比如說,尋找那些長時間沒有做改動的部分,這些部分極易尋在漏洞。

代碼分析通常需要花費比其他方式更多的時間,同時也更難,因為研究者對這個程序的功能和使用的技術的掌握程度要不亞於其開發者,另外,一個程序的開發可能是由一個團隊進行維護,那麼對於研究者,全面掌握這些東西顯得比較困難。但是只要肯專研,其實什麼也都是能夠克服的,中國有句古話,只要肯專研,鐵棒變花針。

我無法不去強調編程能力的重要性,如果一個研究人員對他當前研究的程序所採用的語言和技術有深入紮實的功底,那麼他必將創造出很多有價值的東西。從攻擊的角度來說,他可以發現更加簡單及直觀,編寫利用程序也將得心應手。從防禦的角度來說,他可以提供出代碼級別的具有高度針對性的修復建議而非那種通用的方法。

四. 有關漏洞挖掘的其他想法。

1. 漏洞的複雜性

漏洞的複雜性分布非常廣。一方面,有很多漏洞非常簡單與直觀,並且利用代碼一目了然,比如說經典的sql注入。另一方面,在系統中有的看似並不相關,並且就其自身而言並非不安全,但是當這些東西以一種特定的方式結合起來的時候,就有可能引發大的漏洞,比如說條件競爭,或者一些其他的複雜的邏輯漏洞。我嘗試將這些漏洞按照複雜級別分為「一級漏洞」和「二級漏洞」,不過也有其他分類方法。引用一局來自Project Zero的Ben Hawkes說過的一句話:

The modern exploit is not a single shot vulnerability anymore. They tend to be a chain of vulnerabilities that add up to a full-system compromise.

如今想要完成一個完整的利用,只靠單一的漏洞往往行不通。很多時候我們需要靠一連串的漏洞才能完成一起完整的利用,致使系統「妥協」。

2. 團隊工作

在一個團隊中工作能夠有效幫助自己了解自己不知道的知識,以及提高自己已知的知識。不過在團隊中要需要注意工作的方式方法,知之為知之,不知為不知,永遠不要強行假裝精通你不熟悉的東西,因為精通的人可以很輕易的指出你的癥結。如果一個團隊裡面大家都不坦誠相待,那麼這不是一個合格的團隊,你可以儘早更換。在優秀的團隊中,不要指望別人會把所有的知識交給你,要學會如何高效的學習,並在團隊交流與合作中不斷提高。

寫在最後

感謝花時間將我的文章讀完,我希望我的文章在可以幫助你解開你的一些對於漏洞挖掘的謎團。在學習和研究漏洞挖掘的過程中遇到困難並感到不知所措是非常正常的。不過學習的過程就是這樣,只有不斷的去嘗試才會進步。祝你在漏洞挖掘的路上走的越來越遠。

參考文章

1.jackson.thuraisamy.me/f

2.jackson.thuraisamy.me/o

3.cnblogs.com/SecurityKid


推薦閱讀:

現代計算機病毒,木馬的學習、實驗、分析都是在沙箱、虛擬機中運行,有沒有能夠逃逸出到宿主機的病毒?
重定義邊界網路安全:混合才是未來

TAG:漏洞挖掘 | 漏洞 | 网络安全 |