# [Efficient Greybox Fuzzing of Applications in Linux-Based IoT Devices via Enhanced User-Mode Emulation](https://dl.acm.org/doi/abs/10.1145/3533767.3534414) ## Abstract * 灰盒 Fuzzing 是漏洞挖掘的主流方法,但因 IoT 的環境依賴性而無法對其使用 * 先前的工作利用 full-system 模擬來克服,缺點是巨大的 overhead * FirmAFL 結合 full-system 模擬與 user-mode 來加速 * 本文認為目前 user-mode 的模擬並不完整 * 提出 EQUAFL,自動用 user-mode 模擬嵌入式應用程式 * 先用 system-mode 模擬,抓出會讓程式 crash 的關鍵,再將環境改至 user-mode * user-mode 可回放系統的網路行為 * 在 70 個網路應用程式下評估 EQUAFL,與最先進的其他 fuzz 工具比較 * 比 AFL-QEMU 快 26 倍、Firm-AFL 快 14 倍 * 發現 6 個 CVEs ## Introduction * 現今 IoT 開發注重功能而非安全,造成系統中存在漏洞 * Mirai * 灰盒 Fuzzing 常被用來測試程式,蒐集 PUT(program under test) 的回饋資訊 * 但因缺乏系統與硬體支援,無法直接用於嵌入式設備 * 利用模擬解決 * 模擬有 user-mode 與 full-system * 雖然前者 cost 低,但缺乏 system calls 與 execution context * 大多使用後者執行 * 先前的工作 Firm-AFL 利用切換 user-mode 與 full-system 加速 * 有 system call 跑 full-system * 沒 system call 跑 user-mode * 當 PUT 有一堆 system call 的時候,加速很少 * 希望完全在 user-mode 之下執行 * 提出 EQUAFL,利用強化的 user-mode 模擬跑灰盒 Fuzzing * Linux-based * 強化的 user-mode 指自動化設定執行環境,讓 system call 直接傳到 host 端 * EQUAFL 使用觀察重放策略 1. 在 full-system 模擬 PUT,觀察設定啟動變數、設定文件、設定網路等關鍵行為 2. 重放觀察到的行為去建立環境 * 動態產生設定文件和網路互動是最難的部分 * 在 70 個真實世界的 IoT Linux-based 應用程式評估 * 比 AFL-QEMU 的 full-system 模擬快 26 倍 * 比 Firm-AFL 快 14 倍 * 在 18 個設備上發現 10 個未知漏洞,包含 6 個 CVEs * 貢獻總結 * 提出 EQUAFL,自動建立執行 user-mode 環境來高效 fuzz * 基於 AFL 和 QEMU 實作 EQUAFL * 在 70 個應用程式下評估,發現 6 個 CVEs * [Open-Source](https://github.com/zyw-200/EQUAFL) ## Background ### Emulation-Based Fuzzing * QEMU 是常用的模擬器 * Full-system 模擬 kernel, drivers 和 應用程式 * User-mode 模擬將應用程式的 system calls 委託給 host * 快速、高效 * 缺乏兼容性,當 host 不支援該 system calls 就會失敗 * AFL 支援利用 QEMU 作為模擬引擎去對 PUT 做覆蓋率導向的灰盒 fuzz #### AFL + QEMU user-mode emulation * 預設之下,AFL 用 QEMU user-mode 模擬 * 直接將執行的 system calls 傳給 host * 可能會因 host 與 PUT 相容性問題而失敗 * ex: 執行 D-Link TRENDNet TEW-634GRU series 的 sbin/httpd,會因 "/var/run/httpd.pid: No such file or directory" 而失敗 * 常見失敗的原因 * 錯誤的啟動變數 * 因錯誤或是缺乏啟動變數而在開始就停止 * 缺乏動態產生的文件 * IoT 在開機過程常常會產生文件,缺乏這些文件會使 PUT 很早就停止 * 不一致的 NVRAM 設定 * IoT 設備中的 NVRAM 資料與 host 有衝突時會導致錯誤 * 不一致的網路行為 * 許多 PUT 需要透過網路與 user 互動,當 host 無法提供合適的網路時會就失敗 * 不一致的程式資源限制 * 某些情況下 host 的限制比韌體高得多,導致效率受限 * 缺乏硬體 * 某些情況下 PUT 需要特定的硬體來執行,缺乏硬體可能導致錯誤 * 總結來說,AFL + QEMU user-mode 會因為許多兼容性問題導致錯誤,可以透過 full-system 模擬來避免 #### AFL + QEMU full-system emulation * AFL 加上 full-system 模擬的 QEMU 能 fuzzing 整個 firmware image + application * 但整個 fuzzing 的速度會大幅下降 #### AFL + QEMU hybrid emulation * 為了解決上述問題,Firm-AFL 嘗試結合兩者 * 在 user-mode 下執行 code,並將 system calls 導向到 full-system 中 * 當程式頻繁地出現 system call 時,效率依舊低下 * Firm-AFL 仍然有進步空間 ### Terminology * Guest/Host Machine * 在 full-system 模擬中,guest 指包含韌體的虛擬機器、host 指跑著 OS 的那台實體機器 * host 用模擬器執行 guest * Page Global Directory * PGD 指程式執行時的 top physical page frame * 因為每個程式的 PGD 的開頭是唯一的,可用於識別 user-space 中的程式 ## Overview * 在 user-mode 下 fuzzing 很快但是容易失敗、在 full-system 下 fuzzing 容易成功但是缺乏效率 * 希望有 full-system 的成功率但越快越好 * 提出 EQUAFL(AFL-based Enhanced QEMU User-mode emulation) * ![](https://i.imgur.com/sh74iyt.png) * 主要兩步驟 * observation * replay * observation 階段會用 full-system 模擬,紀錄 * launch variables * file generation * NVRAM related operation * network interaction * process resource limits * replay 階段利用蒐集到的資訊部屬設定在 host 上或是在 user-mode 重跑攔截到的 system-call * 調整 PUT 的 lifecycle 和 fuzzing 的 entry point,可從網路層做 fuzzing ## Approaches ### Launch Variables Settlement * 啟動變數是 PUT 在模擬系統中啟動的參數和環境變數 * PUT 表示為 $P^{*1}$、程式名、參數和環境變數表示為 $p^{name}$, $p^{vars}$ 和 $p^{envs}$ * 這些資訊會用很多種方式存在韌體中,例如配置文件、hard-encoded 在執行檔或是由父 process 傳遞,因此無法用靜態方式提取 * 直接用 full-system 模擬取得 #### Observation * 偵測 kernel function 的 do_execve 來得到程序的 pname pvars penvs * 三種 function call 會能計算這些地址 * 接著找到 QEMU 中最靠近這些指令的 Basic block * 最後在 full-system 模擬時存下這些 block 的值 #### Replay * 經過 Observation 後,我們得到一個集合的 pname pvars penvs(每個 process 就有一組) * 將 pname 設為想要測試的目標 process,並將 pvars penvs 設為對應的 pairs,進行 user-mode 模擬 ### Filesystem State Synchronization * 模擬時通常會掛載一個 filesystem,並在初始化時不斷改變它 * 沒有正確的 filesystem 導致 PUT 在 user-mode 執行錯誤 * observe-replay 觀察與文件相關的 system call,並在 host 執行 * 問題是在 host 上 replay 時可能會出現未知的值,例如下圖 * ![](https://i.imgur.com/uJYCze2.png) * 提出 process-aware observation 的方法去 mapping 這些映射 #### Accurate Process Identification * guest 中需要做 process collection 和 process inference(收集和推斷) * 收集利用檢查 fork 和 execve 來檢測新的 process * 從 task_struct 得到 PGD, PID, PPID 等資訊 #### Process-aware Observation * 蒐集到 process 後,進一步蒐集他們的 system call * 過濾不影響文件的,剩餘的分為兩種 * 直接處理路徑,如 mkdir 等 * 處理 file desciptor(fd),如 open * 將 Process, fd_guest, fd_host 的關係建立起來後即可在 host 上重新執行 #### Replay * ![](https://i.imgur.com/aKdP7Pe.png) * id_sys: 重放的 system call * p*: 目前的 process * obj_arg: id_sys 的主要參數(檔案路徑或是 fd) * other_args: id_sys 其他的參數 * RDIR: host 上韌體的 filesystem 的路徑 ### NVRAM Configuration * Firmadyne 中,使用一般文件紀錄 NVRAM 的配置 * 因為前面已經實現 filesysyem 的同步,所以 NVRAM 的配置也已經在 host 上存在 * 利用 LD_PRELOAD 使用自訂的 library 執行 PUT ### Network Behavior * 網路行為會受到外界互動的影響 * 為了模擬網路行為,觀察與網路有關的 system call 並建立狀態機 * 在 full-system 模擬中監控 socket,並利用 type 參數識別是否與網路有關 * 網路互動的狀態機模型如下 * ![](https://i.imgur.com/HntnNd6.png) * 感覺 Fuzzing 的地方是 read/recv/recvfrom 那 ### Process Resource Limits * RLIMIT_NOFILE 是 PUT 可以打開的 fd 最大值 * 太大會降低 PUT 執行速度 * 通常 host 會超大,所以要重設 * 利用 Linux 中的 setrlimit 和 getrlimit system call 來取得這些值 ## Implementation ### Emulation #### Observation * 首先 EQUAFL 利用 FIRMADYNE 執行 PUT 和 full-system 模擬 * full-system 模擬用於紀錄所有 system call 執行的參數和 return 值 #### Replay * launch variables, filesystem state synchronization, NVRAM configuration 這三點,EQUAFL 直接在 host 上部屬一樣的資源 * launch variables 利用 IDA Pro 實現 * filesystem state synchronization 透過 Binwalk 解包韌體 * 利用 chroot 將提取的 filesystem 當作根目錄,相對路徑才不會錯誤 ### Fuzzing * 將接收網路輸入的 system call 當作入口點 * 輸入會進入到網路的內存區 * 檢測 read, recv, recvfrom 等等 ## Evaluation * 實現基於 QEMU 的 EQUAFL * 有對 full-system 和 user-mode 修改 * 修改 AFL 更改 afl-fuzz 接受的參數,正確加載目標的參數和環境變數 * 評估三點 * Compatibility 兼容性 * Efficiency 效率 * Vulnerability discovery 漏洞發現 ### Experiments Setup Benchmarks * 兩個數據集 * nbench 和 lmbench * 70 個來自 D-Link, TRENDnet, NETGEAR 的韌體 * 在 AFL-Full 和 Firm-AFL 都能成功模擬和測試 * ![](https://i.imgur.com/W3dULJs.png) * 三個比較對象 * AFL-User * 預設的 AFL QEMU mode * AFL-Full * 將AFL 和 QEMU 的 full-system 模擬結合 * 利用 DECAF 中的 VMI 來監控目標 process * Firm-AFL * 交替切換 full-system 和 user-mode * AFL 有使用字典和種子 * 字典來自目標程式的靜態分析 * 種子是一個正常的網路請求 * 兼容性和效率評估的環境 * 12-core Intel(R) Xeon(R) E5-1650 v3 3.50GHz CPU * Ubuntu 18.04.5 LTS * 15.6GB RAM * 漏洞發現評估的環境 * 18-core Intel(R) Xeon(R) CPU E5-2699 v3 2.30GHz CPU * Ubuntu 18.04.5 LTS * 188GB RAM * 為了降低 Fuzz 的隨機性,每個實驗跑五次 ### Compatibility * AFL-Full 和 Firm-AFL 都可以成功 * ![](https://i.imgur.com/kTveQF9.png) * CRA: 用初始的種子就 crash * HAN: 用初始的種子就 hang * ERR: 目標可以由 fuzzer 啟動,但有錯誤(例如找不到文件等) * SUCC: 成功 * EQUAFL 成功了 66 個,而 AFL-User 全失敗 * ![](https://i.imgur.com/nPkxz9w.png) * 與 full-system 的 system call 相似性,不同的部分大多是因為 process 通訊的差異造成 ### Efficiency * 兩種評估 * 與 AFL-Full 和 Firm-AFL 比較吞吐量 * EQUAFL 和 User-mode 比較 cost * 因為 User-mode 很多跑不起來,用第一個資料集來評估 * 吞吐量 * 收集 1188 個種子,計算平均執行時間(跑 5 次) * 平均執行時間的倒數為平均吞吐量 * ![](https://i.imgur.com/nDFUyAm.png) * 比 Full 快 26 倍、比 Firm 快 14 倍 * cost * ![](https://i.imgur.com/0bJuG2R.png) * ![](https://i.imgur.com/0Li4yb5.png) * 基本上沒有額外 cost ### Vulnerability Discovery * ![](https://i.imgur.com/ixwa9zu.png) * 找到 10 個漏洞 * 9 個使用 NULL 指標 * 1 個整數 overflow * 其中 6 個得到 CVE * ![](https://i.imgur.com/ykkdKCp.png) * 24 小時內 unique 漏洞數 * 最快發現漏洞 ## Threats to Validity * 外部設備目前只支援 NVRAM * 與其它 process 互動的部分可能會出錯 * 多個程式交互的漏洞無法發掘 ## Related Work * Static analysis * PIE * Firmalice * DTaint * Karonte * SaTC * Dynamic analysis * Avatar * Firmadyne * FirmAE * Fuzzing * IOTFUZZER * boofuzz * Firmcorn * FirmFuzz * EM-Fuzz ## Conclusion * 提出 EQUAFL,為 Linux-based 韌體的網路應用程式 Fuzzing 的框架 * 透過增強的 User-mode 避免 full-system 的 cost * 發現 10 個漏洞,包含 6 個 CVE --- * [EQUAFL 網頁](https://sites.google.com/view/equafl/home?authuser=0) ###### tags: `paper`