文章目錄
這是2017年安全頂會 IEEE Symposium on Security and Privacy上的論文。
一句話概括
針對處理高度結構化輸入的程序(比如解析XML的引擎程序),本文提出了一種種子生成方法,通過大量樣本訓練帶概率的上下文有關文法,通過訓練好的文法,自動生成符合程序輸入要求的種子,用於後續的Fuzz。
0x00 背景介紹
模糊測試是一種自動化的測試技術,它通過生成非預期的輸入,監視程序的異常,挖掘程序的漏洞。
在fuzz的過程中,fuzzer對輸入結構的理解會影響fuzz的效果。
怎麼理解這句話呢?我們來看一個例子:
假設圖1是XSLT引擎解析XML文檔的過程。輸入是XML文檔,過程大概可以分爲三個部分:句法分析(Syntax parsing)、語義檢查(Semantic Checking)以及程序執行(Application Exection)。對於現有fuzz的種子生成技術而言,很難到達程序執行階段。
比如基於變異的fuzz它生成的測試用例大部分在句法分析階段便無法通過,而基於生成的fuzz生成的測試用例大部分在語義檢查階段無法通過。由於程序深層次的漏洞一般隱藏在程序執行階段,如果連程序執行階段都無法到達,那麼更談不上挖掘這個文檔解析引擎的漏洞了。
基於上述的問題,本文針對這種結構化輸入的模糊測試提出了一種自動學習輸入結構並且生成種子的方案–Skyfire:
- 收集目標程序的語料庫
- 訓練出一個帶概率的上下文有關文法(Probabilistic Context-Sensitive Grammar,PCSG)
- 利用它來生成新的種子,執行fuzz。
0x01 方法
1.1 方法概述
圖2爲Skyfire生成種子的過程。
輸入:語料庫和語法
輸出:種子
過程: 使用目標程序的語料庫和語法來訓練帶概率的上下文有關文法(PCSG)。通過訓練好的PCSG,從產生式池中選擇產生式來生成種子,並選取和變異。最終輸出種子用於後續的fuzz。
1.2 相關的文法介紹
在講具體的方法之前,先簡單介紹一下相關的文法。
在計算機科學中,形式語言是:某個字母表上,一些有限長字串的集合,而形式文法是描述這個集合的一種方法。
1.2.1 上下文無關文法(context-free grammar, CFG)
上下文無關文法定義爲一個四元組 ,可以通過產生式從起始字符推導到一個句子。
符號 | 定義 |
---|---|
非終結符的有限集合 | |
終結符的有限集合 | |
產生式: 的有限集合 | |
起始字符的有限集合 |
比如圖3,從開始,通過產生式:,…… 可以推導到葉子節點,比如紅框框的部分是,可以把替換成。
樹的內部節點爲非終結符,樹的葉子節點都是終結符。上下文無關文法就是可以用推導式來替換內部節點的非終結符,而不需要管上下文。
但是,顯然在本文處理的這種高度結構化輸入的文件中,我們需要上下文信息,而上下文無關文法不能表達上下文相關的語義信息,因此可以使用上下文有關文法加入語義信息。
1.2.2 上下文有關文法(context-sensitive grammar, CSG)
上下文無關文法定義爲一個四元組:
符號 | 定義 |
---|---|
非終結符的有限集合 | |
終結符的有限集合 | |
產生式: 的有限集合 | |
起始字符的有限集合 |
上下文有關文法是在上下文無關文法的基礎上,增加了上下文 。在本文中,包含的信息有<曾祖父母,祖父母,父類 ,第一個兄弟姐妹的值>。
比如圖4中節點e上下文信息爲:<E, T, T’, null>
,曾祖父節點爲根節點E,然後祖父節點爲下面的T,父節點爲T’,但是沒有第一個兄弟節點,因此爲null。
爲了能夠生成不常見的輸入來觸發程序的漏洞,也就是要選出很少用的產生式,我們除了上下文信息,還需要產生式的概率,因此本文提出的帶概率的上下文有關文法
1.2.3 帶概率的上下文有關文法(Probabilistic context-sensitive grammar, PCSG)
帶概率的上下文有關文法(PCSG)定義爲元組:,它是在CSG的基礎上,對產生式分配了概率,
並且保證對於給定的非終結符,所有上下文下的產生式規則的概率總和爲1,如下面的公式所示。
這個有點繞,看到後面PCSG學習後,輸出的結果(1.3.3部分)
的時候就會懂了。😃
ok,小結一下,爲什麼使用的是PCSG而不是上下文無關文法?
- 上下文無關文法能很好地表達語法信息,但因爲上下文無關,不能表達上下文相關的語義信息。因此,可以用上下文有關文法來加入語義信息
- PCSG中的每一個產生式規則都可以和應用了產生式的上下文相關聯,並且和上下文中應用了產生式的概率相關聯
1.3 PCSG學習
1.3.1 樣本解析爲抽象語法樹(AST)
Skyfire的第一個階段,PCSG的學習階段,首先是基於樣本的語法,將樣本解析爲抽象語法樹(AST)。比如圖6是一個XSL文件樣本
我們可以基於它的語法將其解析爲圖7中的這樣一棵抽象語法樹(Abstract Syntax Tree,AST)。其中,樹的內部節點是非終結符,也就是XSL文件中內容的一個抽象定義,比如根節點document,葉子節點是終結符,也就是XSL文件中的具體的內容。
根據這棵樹,我們可以從中得到一些推導式,比如 ,,這裏的attribute就是一個非終結符,version="1.0"是終結符
1.3.2 計算parent children pair在相應的上下文條件下出現的次數
parent children pair,父子對,也就是產生式規則。這個步驟要計算的是在所有的AST中,當前的產生式在相應的下文條件下出現的次數。
我們來看一個例子。在圖8的紅框框中,Node 9是Node 16的父親,他們形成了一個parent children pair,其實也就是產生式:。它的上下文爲:< null, document, element, <xsl:stylesheel >
曾祖父節點 | 祖父節點 | 父親 | 第一個兄弟 |
---|---|---|---|
null | document | element | <xsl:stylesheel |
那麼,我們要統計的就是在所有的AST中,在上下文< null, document, element, <xsl:stylesheel >
的條件下,產生式 出現的次數,即:
當然,在具體的算法中,需要統計所有的產生式在相應的上下文條件下出現的次數,這裏僅是拿Node9和Node16來舉例。
1.3.3 計算每種產生式規則的概率
最後,我們要計算,給定一個非終結符,也就是AST中的內部節點,我們要計算出在上下文的條件下,它的產生式的概率。
計算公式爲:
也就是給定非終結符,計算在上下文條件下每種產生式規則的概率。 用所有的抽象語法樹中,在上下文的條件下,這個的產生式規則出現的次數,除以所有的抽象語法樹中,非終結符出現的次數。
理解:它計算的是在所有的抽象語法樹中,這個子樹(比如上圖的Node9和16這棵)在當前上下文條件下出現的概率。上下文可以理解爲是用於限制產生式規則的。
以圖9爲例,Node9是16的父親,那麼在這個上下文條件下,這種產生式的概率就等於,在所有的抽象語法樹中,該上下文中這種產生式出現的次數,除以所有抽象語法樹中這個非終結符出現的次數,要計算的概率就是:
參考圖9,比如對於非終結符element
,在AST中可以得出,在某個上下文條件下,比如<null,null,document,prolog>
,它有一些產生式:
element -> <xsl:stylesheet attribute attribute attribute>content</xsl:stylesheet>
element -> <xsl:transform attribute attribute>content</xsl:transform>
...
那麼我們可以根據上面的公式計算出,每個產生式在當前這個上下文<null,null,document,prolog>
條件下的概率分別爲:
- 0.0034
- 0.0001
- …
最終,可以得到非終結符在不同上下文條件下產生式的概率,並保存到產生式池中。可以看到,對於同一個非終結符,比如這裏的element,由於在各個上下文條件下,產生式的概率的計算,分母都是count(element),因此它們的概率和便爲1.
1.4 種子生成
1.4.1 種子的生成
種子的生成採用的是最左推導的方式。
最左推導:
- 從一個起始字符開始
- 每次都用產生式規則替換最左邊的非終結符
- 直到句子中沒有非終結符爲止
圖10爲生成種子的過程,藍色的字符爲非終結符,黑色的字符爲終結符。
圖中的到,就是把最左邊的非終結符attribute替換成終結符version=“1.0”。下一步再把t3中最左邊的非終結符替換成終結符,直到整個句子中沒有非終結符則結束。
但是由於產生式規則存在遞歸的關係,因此,算法可能無法結束,或者得到的種子很複雜文件很大。
爲了解決這兩個問題,同時爲了保證生成種子的正確性多樣性和不常見性,本文提出了四個啓發式:
- 優先選取低概率的產生規則,從而生成樣本庫中很難覆蓋的輸入;(粉色)
- 限制相同一產生規則的使用次數,優先應用頻率低的規則;(黃色)
- 優先使用低複雜度的規則;(綠色)
- 還有就是限制所有規則的應用次數;(藍色)
1.4.2 種子的選取
通過上面的種子生成步驟,可以生成很多的初始種子,但並不是所有種子都是唯一和重要的。本文以覆蓋率作爲選擇種子的標準:
- 對於開源程序使用gcov獲取代碼和函數覆蓋率
- 對於閉源程序使用PIN獲取基本塊覆蓋率
1.4.3 種子的變異
爲了保證種子的多樣性,需要對種子進行變異。
本文采用的是大步變異,簡單地說,就是在AST中選取葉子節點(終結符),並利用同種類型的葉子節點對其進行隨機替換,只用右邊是終結符的產生式進行變異。
好處:可以產生一般Fuzzer的small-step變異難以生成的種子,比如從version=“1.0”到encoding=“utf-8”,通過隨機的按位翻轉是非常困難的。
舉個例子吧,在圖12中,可以把節點22的內容替換成另外的非終結符:omit-xml-declaration= “yes”
0x02 實驗結論
測試目標:XSLT、XML,IE11的JavaScript引擎等
結果:
- 漏洞發現能力強
- 19個新的內存破壞型bug(其中16個新的漏洞)
- 32個拒絕服務bug
結論:
- 優點:
- 生成的種子能有效地發現深層次的漏洞
- 對於XML、XSL語言的應用效果很好
- 缺點:
- 對JS這種較爲複雜的語言,實驗效果有待提高
0x03 未來工作
改進方向
- 使用深度學習的方法學習輸入的結構
應用方向
- 支持更多不同的語言,如:javascript、SQL、C、java等
- 使用生成的種子輸入來查找編譯器錯誤
0x04 參考資料
鳴謝
有什麼理解錯的或是寫錯的還望各位指出
感謝Chris一
的批評指正!