Sfuzz论文笔记

Eutopia's Blog

Posted by Eutopia on December 19, 2023

SFuzz: Slice-based Fuzzing for Real-Time Operating Systems

简介

RTOS系统当下并没有很好的分析方式,因此作者提出了sfuzz工具,利用RTOS每一项任务的控制流都是独立的特点,从RTOS系统中切出独立的代码块进行fuzzing。

项目地址:https://github.com/NSSL-SJTU/SFuzz

解决问题

解决了在当时RTOS领域模糊测试没有很好的分析方式的问题。

主要贡献

  • 提出了RTOS系统的特点:每一项任务的控制流都是相互独立的,通过代码切片获取到独立的代码树,分别进行分析

  • 使用了前向切片与后向切片,根据依赖和函数调用关系获取了代码片段以供fuzz

  • 设计了SFuzz,对RTOS进行灰盒测试。

尚存不足

具体内容

sfuzzing一共分为四个模块,分别为Forward slicer,Control Flow Nodes Handler,Micro Fuzzing,Concolic Analyzer。

figure_2

Forward Slicer

由上图可知,forward slicer分为四个步骤,分别为恢复函数语义,根据函数语义构建相关函数调用图,修剪调用图,连接调用图。

恢复函数语义:使用四种方法来恢复函数(1:接受用户输入的函数;2:sink函数;3:设置或接收全局变量的函数)。确定用户输入点,全局变量访问函数,sink函数。

  • Symbol & log Function:通过供应商给出的symbol,log function得出函数名的标签。
  • Virtual Execution:根据将函数接收参数数量和返回值与标准库函数比较,找出可能对应的库函数,然后进行内存分配,初始化寄存器和参数变量,最终模拟函数运行并根据运行结果和内存空间来识别标准库函数
  • Web Service Semantic:通过前后端文件来标记用户输入
  • Open Source firmware:一些供应商的产品是基于开源的RTOS系统改写而成,因此可以根据开源代码来匹配函数。

根据函数语义构建相关函数调用图:根据用户输入函数以及全局变量访问点,以这些函数的调用函数作为根节点,然后根据函数调用关系建立调用图

函数调用图修剪:使用基于语义的污点分析,将相关的函数调用保留下来。

调用图连接:由于某些全局输入的数据流可以被数据共享函数干扰,因此需要将这些有关的连接起来。

  • 对于存取常量的数据共享函数,根据常量值将相关节点连接起来,(<nvram_set, nvram_get>)

  • 对于存取动态变量的函数,如下图wan0_pppoe_username,通过虚拟条件节点连接,在动态运行时根据实际变量值来确定是否跳转到输入点。

    image-20231129090544941

Control Flow Nodes Handler

在通过前向切片获取到函数相关调用图以及基于此生成函数执行树后,control flow nodes handler需要在此基础上补全代码(补充上下文)以便进行后续的fuzzing测试。主要用于引导后续fuzzer fuzz的路径

In other words, because of lacking full context and runtime state of the RTOS, we need strategies to guide the fuzzer to determine how to handle the function call in the snippet and choose which branch of the conditional statement to jump

  • Call Instruction:如果函数的参数不受外界输入影响,那么将其加入PatchedFunc集合以便后续fuzzer识别,从而跳过此函数。
  • Conditional Branch:如果控制流存在条件分支,则根据条件与用户输入之间关系以及分支是否可以到达sink点来分情况讨论
    • 只有一个分支可以到达sink点,如果条件可以被输入影响,那么将无法到达sink的分支地址加入PatchedJMP集合,防止fuzzer探索该分支;否则,如果用户输入无法影响条件,则让将到达sink点分支地址添加到PatchedJMP集合,让fuzzer直接进入该分支。
    • 两条分支都可以进入sink点,若条件可以被输入影响,那么不改变代码,让fuzzer随机生成输入来探索路径;否则将条件指令添加到PatchedJMP集合,让fuzzer将条件判断转换为随机的跳转地址
    • 若没有分支可以到达sink点,那么将两个分支的地址加入PatchedJMP集合,让fuzzer当发现这些地址时退出path exploration

Micro Fuzzing

一种slice_based fuzzing。将代码片段作为输入,探索执行树的执行路径。fuzzer会根据PatchedFunc集合与PatchedJMP集合指导下进行fuzzing。

其中,由于RTOS的缺乏对内存保护的机制,sfuzz提供了内存检查机制来检测是否存在栈溢出等漏洞。

Concolic Analyzer

micro fuzzing提供fuzz成功的输入给concolic analyzer进行验证,concolic会恢复代码块的上下文进行验证crash input是否可以正确触发漏洞。

listing_3

如上图代码示例,通过前向切片可以得出用户输入为line 8 ledClsTime,输出的sink点为line 17 nvram_set,通过前向切片有条件分支

11 if (strcmp(ledCtlType , ledStatus))
12 nvram_set("led_ctl_type", ledStatus);
13 if (!strcmp("2", ledStatus) ) {
14 ledTime = nvram_get("led_time"); // Other input #3
15 sub_800D487C(a2, argbuf);
16 if (strcmp(ledTime , ledClsTime))
17 nvram_set("led_time", ledClsTime); // Global data set
18 }

条件分支涉及到了其他输入ledCtlTypeledStatusledTime,可以通过约束求解器来进行求解。

但是仅依靠前向切片的问题是无法确定其他输入是否真的可以影响sink条件分支。例如line11即无法改变sink点是否可达。因此需要通过后向切片查看是否会对结果产生影响,从而将line11删去。

同时,后向切片也会查看sink函数中被写入对象的大小,从而确定是否可以真的实现溢出。eg: vulnGet

知识点补充

前向切片与后向切片:https://blog.csdn.net/hmysn/article/details/124717162

FDT:https://blog.csdn.net/qq_44370676/article/details/120836743

AFL(基于coverage_guide的fuzzing工具)https://www.freebuf.com/articles/system/191543.html