---
# System prepended metadata

title: '[Fuzzware: Using Precise MMIO Modeling for Effective Firmware Fuzzing](https://www.usenix.org/system/files/sec22summer_scharnowski.pdf)'
tags: [paper]

---

# [Fuzzware: Using Precise MMIO Modeling for Effective Firmware Fuzzing](https://www.usenix.org/system/files/sec22summer_scharnowski.pdf)

## Abstract

* 在 IoT 裝置上做模糊測試並不簡單，容易有效率低下的問題，因此最新的方法是透過 re-hosting 跑 firmware
* 現有的 fuzzing 方法使用簡化的硬體行為模型或是手動 re-hosting
    * 本論文提出 FUZZWARE，新的輕量化程式分析、rehosting 和 fuzzing 的組合來面對這些挑戰
* FUZZWARE 透過確認硬體如何生成值來自動生成模型，幫助 fuzzing 集中在重要的輸入上，而提高有效性
* 評估 19 個硬體平台和 77 個 firmware
* 和最新的技術比較，FUZZWARE 有高達 3.25 倍的覆蓋率，建模將輸入空間減少 95.5%
* 樣本中包含 66 個對各種硬體互動的單元測試，FUZZWARE 是第一個自動化通過所有測試的方法
* 發現 15 個全新 bug，確認了 12 個 CVE

## Introduction

* fuzzing 是安全檢測常見的方式，但在 IoT 設備上常因有限的資源而降低速度
    * 透過 rehosting 在模擬環境執行來解決
* 大多數使用 rehosting 動態分析 based on Unix Firmware 的方式都不適用於單片 Firmware(monolithic firmware)；而現有能跑單片 Firmware 的方式通常需要分析人員手動查找外部設備，相當耗時
    * 最近的研究轉向自動化，有各種方法開始出現
        * HAL: 把外部設備的實作重新連到已知 lib 上
        * P2IM: 建模，匹配暫存器
        * Laelaps, uEmu: 符號執行解出執行路徑
* 上面這些方法在使用模糊測試的時候都會遇到一些限制，因此他們提出新的自動化建模方法，可與受到引導的 fuzzer 一起使用
* 大多是對外部設備的存取都是短暫的，與 firmware 整體運作無關(檢查外部設備的狀態或配置等等)
* 會影響 firmware 執行的輸入，通常大部分都沒有使用到
    * 可能一次讀取 32-bits，但只用了其中幾個 bits
    * 每次存取造成多餘的 cost
* 為了降低這種 cost，使用局部的動態符號執行(DSE)分析哪個部分的值是有意義的
    * 不使用 DSE 引擎來求具體解，而是利用生成的約束條件來推斷模型
    * 這些模型會用於配置模擬器，具體值則由 fuzzer 提供
* 模擬過程中，模型不會選擇路徑或偏好路徑，目標是用最少 cost 有最高的覆蓋率
* 評估表明雖然需要多 0.5%~2% 的計算時間，但消除 95.5% 的輸入 cost，和其他工具相比有 3.25 倍的覆蓋率和找到額外的 bug
* 貢獻
    * 提出新的建模法，保留路徑，讓 fuzzer 專注在有意義的值
    * 實現 FUZZWARE，可以用與 OS 無關的方式模糊測試單片 firmware
    * 實驗中優於其他工作
* 發現 12 個以前未知的漏洞並回報
* https://github.com/fuzzware-fuzzer/fuzzware
    * 還未公布

## Technical Background

### Monolithic Embedded Systems

* 這種 firmware 可能不包含 OS，且不會有傳統 binary executables 中的 metadata

### Memory-mapped IO

* 現在的 CPU 透過 MMIO 訪問外部設備，外部設備被分配到內存空間中的區域
    * 例如可以透過讀取 MMIO 暫存器來得知按鈕是否被按下
* 不同暫存器代表的資訊不同、大小和讀寫操作也不同
* ![](https://i.imgur.com/BaPGaMj.png)

### Interrupts and DMA

* 硬體可以透過中斷來告訴軟體發生事件
* CPU 透過 interrupt service routines(ISR) 來維護中斷事件
    * CPU 可以決定中斷的優先度
* 另一個硬體與軟體溝通的方式是 DMA，他透過 MMIO 完成
* 透過 DMA，外部設備可以執行和 memory controller 溝通而不用經過 CPU
* 中斷較普遍，DMA 主要用於 USB 等需要高吞吐量的設備

### Re-Hosting Embedded Systems

* Re-hosting 是不需要實體設備執行 firmware binary image 的方式
* 為了正確模擬，需要處理 MMIO 的存取
    * QEMU 完全重新實現 MMIO 暫存器的行為，但需要完整的硬體文檔(資訊)
    * 另一種方式是用 fuzzer 處理 MMIO；只要 firmware 存取 MMIO 暫存器，就由 fuzzer 提供值回傳
        * 好處是不用知道 MMIO 到底如何處理回傳
        * 壞處是前面說過的，fuzzer 要提供許多不相關的輸入

## MMIO Access Handling

### Input Overhead

* 對於 MMIO 的存取，可以分為兩類
    * Full input overhead: fuzzer 提供的值完全不影響 firmware 執行
    * Partial input overhead: 一位或多位會影響運作邏輯
        * 如果存取了 32-bits 但實際上只有 8 bits 會被使用，那就有 24-bits 的 input overhead
* 範例一：
    * 假設要從外部設備讀取值，通常要先等待 MMIO 中某區塊出現一個特定的值，代表資料已經準備好
        * 沒有建模的話 fuzzer 要找到特定值就要很久
    * 接著會對 MMIO 進行寫入，代表對 GPIO 寫入以開啟指示燈
        * 這個寫入對 firmware 程式不會影響，Full input overhead
    * 最後讀取實際上要的資料
        * 因為 MMIO 暫存器是 4-bytes 寬，因此你就算只要 1 byte 也會多讀資料，Partial input overhead
        * 針對這個部份去限縮 fuzzer 就可以減少開銷
* 範例二：
    * 如果出現 switch case 的結構，MMIO 的值被當作決定路徑的變數時，如果分支不多，但依然一次寫入 4-bytes 的長度就會造成 Partial input overhead

### Previous MMIO Modeling Approaches

* 目前的 MMIO 建模方式
    * 完全避開 MMIO 存取
        * HAL，替換成抽象層
    * 建模處理
        * P2IM，基於對暫存器不同的存取方式來減少輸入空間
    * 符號執行來建模
        * Laelaps, uEmu，把對外部設備的存取視為符號值，當需要存取時再求具體解
* 目前都有這些問題
    * 需要手動的工作(HAL)
    * overhead
    * path elimination

## Design

* FUZZWARE 為了分析 firmware 行為，使用 DSE 來得到硬體產出的所有可能值
* 直接用符號執行建模會導致成本太高，因此 DSE 僅用於特定存取 MMIO 的 code

### Prerequisites and Threat Model

* 先決條件
    * 能得到設備的 binary firmware image
    * 要能提供基本的 memory mapping
* 威脅模型
    * 攻擊者能控制給 firmware 的輸入

### FUZZWARE's Emulator

* 使用 ISA Emulator 加上覆蓋率引導的 fuzzer
* 目標是消除 partial input overhead，因此引入存取模型
* 設置了 harness 可以攔截所有 MMIO 存取
* emulation run: 進行 firmware 模擬，MMIO 存取發生時，會檢查是否有為這裡建立模型
    * 模糊引擎會生成一堆輸入，這些輸入會經由模型轉換為合適的大小給模擬的 firmware 使用
    * 模擬結束後會把覆蓋率反饋給模糊器
    * 每次看到新的 MMIO 存取，就會對 memory 做 snapshot，然後用符號執行來產生模型
    * 每次重新配置模擬器就會因為新模型而減少 overhead

### Modeling Approach

* 對於每個不同 PC 和存取的 MMIO 地址都會做一個模型
* 把存取前的暫存器和記憶體狀態給 DSE 建模
* 分析範圍
    * 以下事情發生就停止符號執行
        1. 所有 MMIO 存取的符號變數都死亡
        2. 當前 function return
        3. 符號被寫入全域變數或上層 stack 等等
        4. 定義的資源以用完(時間、符號狀態數、DSE 步數)
    * 停止時會生成當前路徑的符號約束範圍，提供給模型
* 模型設計注意事項
    * 同樣的輸入經過模型後給 firmware 要有一樣的結果
    * 盡量保留路徑
* 錯誤處理和執行停止
    * 允許執行錯誤的路徑，增加覆蓋率

### FUZZWARE Model Definitions

* 5 種模型
    * Constant Model
        * 將常數和 MMIO 存取的值做比較，滿足條件才會繼續做
    * Passthrough Model
        * MMIO 的值根本不影響 firmware 執行
    * Bitextract Model
        * firmware 只使用讀取的部分 bits 時使用
    * Set Model
        * 根據不同的值會執行不同操作時使用
    * Identity Model
        * 所有位元都是有意義的時候使用

### Interrupt, Timer and DMA Handling

* ISA emulator 沒有中斷，因此由 FUZZWARE 觸發
* 一定 basic-block 後觸發
* FUZZWARE 可以把 buffer 定義為 MMIO 區段來支援 DMA，但沒自動化建模

## Implementation

* 實現了一個支援 ARM Cortex-M 的 prototype

### FUZZWARE's Emulator

* Unicorn Engine 作為模擬器，AFL 作為模糊器
* 用 Unicorn API 來 hook MMIO 存取事件
* 擴展 Unicorn 實現中斷控制器

### MMIO Access Modeling

* 使用 angr 作為引擎
* 達到退出條件時，檢查符號和約束來選擇模型
    * Constant Model
        * 不再引用被追蹤的變數，而是直接約束結果
    * Passthrough Model
        * 不再引用被追蹤的變數，也不約束結果
    * Bitextract Model
        * 上特定的 Mask 後，所有約束和符號表達都沒變
    * Set Model
        * 不同分區有不同的約束結果
    * Identity Model
        * 以上都不符合時
    * 可能同時符合多個模型，選擇開銷減少最多的模型
* DSE 最多每個模型執行 5 分鐘、1000 個 basic-blocks 就會強制退出

## Evaluation

* 5 個評估
    * 基於符號執行的建模，計算成本多高
    * 因為保守的範圍界定，錯失多少優化建模的機會
    * MMIO 模型適用於各種 firmware 和硬體平台嗎
    * 和以前的方法比較，fizz 單片 firmware 的表現如何
    * 可以發現現實世界以前未知的錯誤嗎
* 針對 19 個不同的硬體平台、77個不同的 firmware image 實驗

### Access Modeling for Fuzzing

* 在 10 個不同的板子編譯相同的應用程式
    * 輸入密碼，如果對了會開啟一個漏洞
* P2IM 66 個單元測試
* 24 小時模糊測試，有用 MMIO 建模和沒有的都有做
* 40-core Intel Xeon Gold 6230 CPU @ 2.10 GHz machine running Ubuntu 18.04.4 LTS
* ![](https://i.imgur.com/PwQBLdl.png)
    * 算出幾個字元 - 所花費的時間
    * 藍色有建模、橘色沒有
* 模型生成花費的成本
    * 平均而言，每個 firmware 生成 62 個模型，每個模型花費 6 秒，總花費 6.34 分鐘
* Input overhead 消除
    * ![](https://i.imgur.com/otjR4me.png)
    * M: 減少的 overhead
    * F: 耗費的模糊輸入
* MMIO 模型通用性
    * P2IM 的單元測試跑了 10 分鐘，有 100% 的通過率

### Comparison with the State of the Art

* 和 uEmu 和 P2IM 比較
* Dataset 使用 uEmu 的 21 個樣本
    * 其中四個禁止中斷，其中一個手動定義 DMA
    * P2IM 跑不動 11 個樣本(和 uEmu 寫的一樣)
    * 跑五次的 24 小時
* ![](https://i.imgur.com/NIu8m87.png)
    * 程式碼覆蓋率平均比 P2IM 高 44%，比 uEmu 高 61%
        * uEmu 會比 P2IM 低，可能是因為無效引導消除了路徑
    * 發現 3 個以前沒報告過的 bugs

### Fuzzing New Targets

* 額外測試了兩個和 core network 有關的 firmware framework
* 發現了 12 個錯誤並發布 CVE
    * ![](https://i.imgur.com/099C24R.png)

### False Positive Crash Analysis

* 61 個 unique crashes 中，42 個和安全有關，16 個和初始化有關，剩下 3 個是誤報
    * 誤報是因為真實的設備不會有問題(e.g. 初始化前就觸發中斷)

## Discussion

* DMA
    * 目前沒自動化
* 在 FUZZWARE 之外的地方使用模型
    * 成功移植到 avatar2 和 PANDA framework 中
* 路徑消除的優點
    * 就比較不容易出錯，但如果把錯誤的路徑當成正確的反而需要人工修復
    * FUZZWARE 允許卡住，透過 Timeout 和回饋模糊引擎來避免
* Implicit Peripheral Semantics
    * firmware 會對某些外部設備的行為有隱含的假設

## Related Work

* AFL
* QEMU
* HALUCINATOR
* PRETENDER
* P2IM
* uEmu
* LAELAPS

## Conclusion

* 提出了對 MMIO 建模的方式，可對 monolithic firmware binary 做 fuzzing
* 這種建模可以消除 fuzzing 的 overhead 並提高有效性

###### tags: `paper`