符號執行,從漏洞掃描到自動化生成測試用例

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"ThoughtWorks安全團隊曾經在可信Frimware領域做了一些探索和研究。背景大概是這樣的:整車製造過程中,常常會引入供應商的部分設備,如車載娛樂系統,但是出於知識產權的原因,這些供應商很難提供完整的源碼給整車製造方,因此二進制的固件就成了整車製造環節中的安全隱患,各種漏洞都可能被供應商的零部件引入,存在於車載系統之中,隨時可能被攻擊者利用而影響整車的安全性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了探測二進制程序中的漏洞,經過一段時間的探索和研究後,把核心技術鎖定到了符號執行,利用該技術幫客戶搭建了一套自動化的二進制漏洞掃描平臺。並且,在後來不斷的研究中,我們發現,符號執行也可以用來自動化生成測試用例,爲我們更加全面的編寫測試用例, 帶來新的思路。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"什麼是符號執行"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Wikipedia上對符號執行的解釋:是一種程序分析技術,其可以通過分析程序來得到讓特定代碼區域執行的輸入。使用符號執行分析一個程序時,該程序會使用符號值作爲輸入,而非一般執行程序時使用的具體值。在達到目標代碼時,分析器可以得到相應的路徑約束,然後通過約束求解器來得到可以觸發目標代碼的具體值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"講的比較繞,舉個通俗的例子來說明:假設程序現在是一個王者榮耀中的英雄,這個英雄經過一定的出裝就會有一定的戰力(攻速,物理傷害,防禦等),符號執行的技術就是,給出了一個英雄的戰力,可以反推出什麼樣的出裝可以達到這樣的戰力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再舉個實際的代碼例子來說明符號執行:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"void foo(int x, int y)\n{\n int t = 0;\n if( x > y ){\n t = x;\n }else{\n t = y;\n }\n if (t < x ){\n assert false;\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設當"},{"type":"codeinline","content":[{"type":"text","text":"ty) => t=x\n(x<=y) => t=y"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來,符號執行會通過約束求解,去分析上述的每條路徑,通過約束求解分析得,如上的兩條路徑在任何情況下都不可能達到"},{"type":"codeinline","content":[{"type":"text","text":"tep;\nstruct sctp_transport *transport = NULL;\nstruct sctp_sndrcvinfo _sinfo, *sinfo;\n- struct sctp_association *asoc;\n+ struct sctp_association *asoc, *tmp;\nstruct sctp_cmsgs cmsgs;\nunion sctp_addr *daddr;\nbool new = false;\n@@ -2053,7 +2053,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)\n\/* SCTP_SENDALL process *\/\nif ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) {\n- list_for_each_entry(asoc, &ep->asocs, asocs) {\n+ list_for_each_entry_safe(asoc, tmp, &ep->asocs, asocs) {\nerr = sctp_sendmsg_check_sflags(asoc, sflags, msg,\nmsg_len);\nif (err == 0)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於這種漏洞補丁,沒有分支上的增減,只是改變了一個函數的入參個數,那麼補丁前後的CFG可能是一樣的,所以我們就不能僅僅通過CFG來判斷補丁是否存在,必須加上在語義上的分析,語義即這個參數對函數的整體影響。這就引出了符號執行的另一步:約束求解,前面我們提到符號執行會對所有路徑形成類似方程組的概念,然後使用約束求解器求出到達每個路徑的解的集合。如果其中某些變量發生了改變,其最終的解一定是不一樣的,以此作爲漏洞標識的另一個特徵。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"漏洞掃描總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以最終,我們是採用符號執行從CFG和語義分析兩個維度來唯一的確定一個漏洞的特徵,然後用這個唯一的特徵去目標的kernel中對比。以此來確定補丁是否已經存在。這個就是我們檢測二進制漏洞的關鍵技術,大致流程如下圖:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/b0\/b0af306e735f9e610b5aca62def3892e.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在整個過程中,我們會使用開源的符號執行引擎和約束求解器,比如Angr和Z3。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"符號執行的其他應用場景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面是符號執行在漏洞提取和掃描的一個案例,除此之外,符號執行在漏洞挖掘,CTF等方面也有比較廣泛的應用。例如如下程序是我用Ghidra逆向的一道CTF的題目:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"int verify(EVP_PKEY_CTX *ctx, uchar *sig, size_t siglen, uchar *tbs, size_t tbslen)\n{\nbyte bvar1;\nint local_c;\nlocal_c = 0;\nwhile(true) {\nif(ctx[(long)local_c] == (EVP_PKEY_CTX)0x0) {\nreturn (int)(uint)(local_c == 0x17);\n}\nbVar1 = (byte)local_c;\nif(encrypted{(long)local_c} != (byte)(((byte)((int)(uint)(bVar1 ^ (byte)ctx[(log)local_c]) \\\n>> (8-((bVar1 ^9)&3) & 0x1f)) | (bVar1 ^ (byte)ctx[(long)local_c]) << ((bVar1 ^9) & 3))+8)){\nbreak;\n}\nlocal_c = local_c + 1\n}\nreturn 0;\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以發現,其核心關鍵是去破解這個加解密的算法(異或,加減等操作),如果人工逆向,可能需要很長時間的推算和嘗試,而符號執行則可以自動的去不斷嘗試每個路徑的解,直到算出一個自己需要的值。有興趣的讀者,可以使用angr和z3去做一下這個CTF的破解,非常容易,這裏不再贅述。需要說明的是,在破解和CTF中,符號執行往往和IDA\/Ghidra等工具來配合使用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一方面是在測試領域,在單元測試中代碼覆蓋率往往被用於評估代碼的測試充分性水平,在軟件工業界,人工設計測試用例的方法被廣泛使用,即依靠人對程序代碼的理解設計測試用例,但對應的人力成本很高,有時候爲了降低人力成本且提高自動化程度,隨機測試的方法也被常常使用,但一般只能檢測到有限的程序行爲,容易遺漏軟件錯誤。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在單元測試中,常用的白盒測試的充分性準則大多屬於基於控制流的覆蓋準則,如語句覆蓋,分支覆蓋和MC\/DC覆蓋等。而測試準則的選取一般根據實際的測試需求而確定,比如,傳統軟件的測試一般要求實現儘可能高的語句覆蓋和分支覆蓋,而對於航天,軌交等控制軟件一般要求代碼滿足100%的分支覆蓋。而這種同時實施多種測試標準的需求,進一步加大了單元測試的工作量和難度, 使得單元測試在實際軟件開發中往往被忽略,最終導致軟件缺陷沒有在早期被及時發現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而符號執行的特點是會盡可能的遍歷每條路徑,每一次符號執行的結果等價於大量的測試案例。符號執行爲軟件的各種情況自動生成了有效的輸入,覆蓋率高,可以更加容易檢測到程序是否存在缺陷和錯誤。所以,其實我們可以運用符號執行生成測試用例。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前學術界有不少的論文研究如何使用符號執行自動化生成更好的測試用例。也有一些有意思的demo,可以讓您體驗:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"C語言:https:\/\/github.com\/Sajed49\/C-Path-Finder"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Java語言:https:\/\/github.com\/kaituo\/sedge"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"總結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以上是我們對符號執行的一些探索,歡迎您與我們一起進行更加深入的研究。隨着大家對安全的越來越重視,基於符號執行的漏洞掃描,自動測試,fuzz測試等越來越受到人們的重視。2019年美國《國防法》National Defense Act的H.R.5515—517 就推薦使用二進制分析和符號執行工具來增強關鍵軟件系統的安全。目前,ThoughtWorks安全團隊正在積極探索符號執行在安全領域的威力,通過自動生成測試用例,再結合模糊測試(fuzz)工具,集成到DevOps的環境中,在整個軟件的開發週期內持續的發現安全漏洞,爲軟件安全保駕護航。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文轉載自:ThoughtWorks洞見(ID:TW-Insights)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"},{"type":"link","attrs":{"href":"https:\/\/mp.weixin.qq.com\/s\/4IYgE3fybBg7vJVlrB6SDg","title":"xxx","type":null},"content":[{"type":"text","text":"符號執行,從漏洞掃描到自動化生成測試用例"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章