缝合线是基于LLVM IR并建立在Checker博士(非常感谢其创建者!)的静态点对点和高级污点分析工具(对于C),两个亮点是:
我们将其命名为缝合线,希望它能在手术上精确,同时能够将多个SYSCALL/输入功能缝合在一起以构建高阶数据流。有关更多详细信息,请参阅我们的论文:在ACM CCS'21中的OS内核中静态发现高阶污染样式漏洞。
首先克隆回购:
~$ git clone https://github.com/seclab-ucr/SUTURE.git suture
然后设置缝合线的LLVM环境:
~$ cd suture
~/suture$ python setup_suture.py -o ../suture_deps
选项(用于setup_suture.py ):
-b指定要为缝合线设置的LLVM的分支名称,在此LLVM Mirror Repo中默认为“ Release_90”(即LLVM 9.0)。-o指定该文件夹托管缝合线(例如LLVM)所需的所有内容,请使用您喜欢的任何文件夹。根据您的硬件,LLVM设置可能需要一段时间。完成后,将在缝合根文件夹下生成一个名为env.sh的SRCIPT文件,它包含命令来设置缝合线使用的环境变量。
重要的是:请确保在构建/使用缝合线之前每次都要激活此env.sh (您还可以将其包含的命令添加到.bashrc中,以在外壳登录时自动激活)!
~/suture$ source env.sh
接下来,我们将建造缝合线:
~/suture$ cd llvm_analysis
~/suture/llvm_analysis$ ./build.sh
成功的构建后,缝合线就可以使用了。
缝合线可用于发现现成的高阶污点漏洞,在本节中,我们将浏览此过程的示例(例如,我们的论文第2.1节所示的激励示例)。
要发现漏洞缝合线需要两种输入:(1)编译为LLVM比特代码(例如, .bc文件)的程序模块,以及(2)模块的配置文件,显示其输入功能和用户控制的参数。
让我们首先准备LLVM比特码用于我们的激励示例:
~/suture$ cd benchmark
~/suture/benchmark$ ./gen.sh motivating_example
注意:为方便起见,我们提供了gen.sh ,以-O1优化级别将.c汇编为.bc和.bc和.ll (人类可读LLVM比特码)。
现在,我们应该在同一基准文件夹下将Motivating_example.bc放在缝合线的同一基准文件夹下。
然后,它涉及配置文件,我们已经为激励示例准备了一个:
~/suture/benchmark$ cat conf_motivating_example
entry0 MY_IOCTL 1
entry1 NULL_ARG
entry2 NULL_ARG
说明:配置文件中的每一行描述了一个输入函数的信息(例如,带有呼叫者的顶级函数,通常用作外部接口),在程序模块中,它包含多达3个空格分隔的令牌:
entry_x MY_IOCTL 0_2中指定它。因此,如上所述, conc_motivating_example指定suptivating_example.c : entry00 (参数1是用户控制), entry1和entry2 (没有用户控制的参数)中有三个输入函数。这符合激励示例的代码。
一旦准备好的比特代码和输入配置文件,我们就可以运行缝合线以发现污点漏洞:
~/suture$ ./run_nohup.sh benchmark/motivating_example.bc benchmark/conf_motivating_example
说明: run_nohup.sh是一个简单的脚本,调用了缝合的llvm分析通过:
~/suture$ ./run_nohup.sh [path/to/program.bc] [path/to/entry_func_config]
一旦开始,根据目标程序的实际硬件和复杂性,缝合线完成分析和脆弱性发现所需的时间差异很大。但是,像我们激励示例这样的简单程序通常会立即完成。
确定分析是否完成:在执行过程中,缝合线在输入配置文件的相同目录下继续登录文件,假设配置文件路径为/路径/to/conf_program ,日志文件将为/path/to/to/conf_program.log 。我们可以通过监视日志来确定分析是否完成:
~/suture$ grep "Bug Detection Phase finished" benchmark/conf_motivating_example.log
上述日志文件也是缝合线的输出,缝合线将其发现的潜在漏洞嵌入日志文件中,分析完成后可以将其提取并组织到最终的警告报告中:
~/suture$ ./ext_warns.sh benchmark/conf_motivating_example.log
说明: ext_warns.sh将提取嵌入给定日志文件中的所有警告(在JSON中),重新组织并精心打印到最终的警告报告中。警告报告将在日志文件的相同路径下放入文件夹中,假设日志文件为/path/path/to/conf_program.log ,警告报告文件夹将为/path/to/to/to/warns-conf_program-yyyy-mm-dd 。
~/suture$ ls benchmark/warns-conf_motivating_example-2021-11-10/
all int_overflow taint_data_use taint_loopbound taint_ptr_def
在文件夹中有5个警告报告,所有报告都包含根据其数据流关系分组在一起的所有类型的警告,而其他报告仅包含特定类型的警告(例如,整数溢出,污染的指针解答等),有关如何在论文中找到我们如何分组警告的更多详细信息(第4节)。我们通常只使用统一报告。
~/suture$ cat -n benchmark/warns-conf_motivating_example-2021-11-10/all
1 =========================GROUP 0 (2 - 2)=========================
2 #####Warned Insts#####
3 (u'motivating_example.c', 30, [u'IntegerOverflowDetector'])
4 ######################
5
6 ++++++++++++++++WARN 0 (2 - 2)++++++++++++++++
7 IntegerOverflowDetector says: motivating_example.c@30 (bar : %add = add i8 %0, -16, !dbg !31)
8 ********Trace 0(2)********
9 #####CTX##### entry0
10 entry0 (motivating_example.c@18)
11 #####INSTS#####
12 >>>>>>>>>>>>>>>>>>tag: 0x55b206570420 tf: 0x55b20695b1b0 (2)>>>>>>>>>>>>>>>>>>
13 motivating_example.c@18 ( %cond = icmp eq i32 %cmd, 0, !dbg !31)
14 motivating_example.c@21 ( store i8 %user_input, i8* getelementptr inbounds (%struct.data, %struct.data* @d, i64 0, i32 1, i64 0), align 4, !dbg !32, !tbaa !34)
15 #####CTX##### entry1 -> bar
16 entry1 (motivating_example.c@35)
17 ----> (motivating_example.c@35 : %call = tail call i32 @bar(i8* bitcast (%struct.data* @d to i8*)), !dbg !27)
18 bar (motivating_example.c@30)
19 #####INSTS#####
20 >>>>>>>>>>>>>>>>>>tag: 0x55b2065e7050 tf: 0x55b2068174f0 (1)>>>>>>>>>>>>>>>>>>
21 motivating_example.c@30 ( %0 = load i8, i8* %add.ptr, align 1, !dbg !31, !tbaa !32)
22 motivating_example.c@30 ( %add = add i8 %0, -16, !dbg !31)
23
说明:在高级别,警告报告包含一些警告组,每个组包含多个警告,每个警告包含几个污点痕迹,这些痕迹源自用户输入和接收器到相同的敏感程序语句。换句话说,针对特定类型和特定类型(例如,整数溢出)提出了一个警告,而一组从数据流角度包含多个密切相关的警告(请参阅本文中的第4节),因此,一组可能具有多个警告程序语句,并包含不同的警告类型。
以上述警告报告为例:
===GROUP No. (min_order - max_order)=== ,其中min_order是最小订单(例如,简单地说,订单,订单是污点传播中所需的输入函数的时代,请参见第3.2节中的第3.2节,以max_order本组的更正式定义。WARN No.是其组的本地。***Trace No. (order)*** ,污点痕迹总是具有可以计算的唯一顺序(例如,不是范围)。警告报告指出了有效的整数溢出漏洞在激励示例中,同时避免了可能生成不太精确的静态分析工具的潜在错误警报,可以在我们的论文第2.1节中找到详细信息。
此存储库还包含一些您可能会发现有用的其他工具/脚本。
~/suture$ python llvm_analysis/AnalysisHelpers/EntryPointIdentifier/entry_point_identifier.py /path/to/prog_module.bc
~/suture$ cat /path/to/prog_module.bc.all_entries
说明:此脚本可以在Linux设备驱动程序模块(例如ioctl() , read() , write()等)中识别一些常见的输入功能,这些功能有助于构建输入配置文件作为缝合的输入。该实用程序主要由原始Dr. Checker基于某些内核域知识实现(例如,用于定义驱动程序的特定数据结构(例如用于定义驱动程序入口点的File_operations ),然后我们进行了一些改进(例如,使启发式术更强大)。
~/suture$ python flt_warns.py /path/to/warn_report [Regex] > /path/to/filtered_warn_report
说明:根据我们的经验,警告报告中的许多虚假警报通常共享相同的有问题的子污染跟踪(请参阅第6.3节中的第6.3节)。只要警告审稿人检查一个错误警报并识别出FP引起的子跟踪,她自然可以尝试自动排除所有包含相同子跟踪的所有其他类似的错误警报,从而降低了审阅者感知的错误警报率。为此,我们提供了以原始警告报告和Python正则表达式为输入的简单flt_warns.py ,然后将其与报告中的每个污点相匹配,一旦匹配,污点痕迹将被视为误报。该脚本将生成一个新的过滤警告报告,不包括所有匹配的污点痕迹。
您可能有兴趣将缝合线用作通用静态分析(例如,在某个程序位置获取变量的点数/污点),这肯定是可行的,但是与漏洞发现不同,您需要弄脏并深入研究缝线守则以熟悉缝线的主要数据结构IT和某些重要功能。我希望以下技巧可以帮助:
LLVM很快发展,无法保证向后兼容。因此,在尝试使用较新的LLVM版本(例如,> 9.0)构建缝合线时,您很可能会遇到一些汇编错误。但是幸运的是,这种汇编错误通常很容易解决(例如,通常我们只需要用较新的情况替换过时的LLVM API)即可。因此,基本上,要将缝合物调整到更新的LLVM版本中,首先我们需要在0x0中设置一个较新的LLVM(例如,需要将setup_suture.py修改为从活动源中克隆llvm repo,并指定新的分支名称),然后尝试构建suture,以构建suture,以弥补索引的汇编编辑错误。