APP下载

基于动态污点分析的程序脆弱性检测工具设计与实现

2022-03-23石加玉彭双和石福升

信息安全研究 2022年3期
关键词:污点脆弱性调用

石加玉 彭双和 石福升 李 勇

1(中国地质大学(北京)地球物理与信息技术学院 北京 100083)2(北京交通大学计算机与信息技术学院 北京 100091)3(东华理工大学地球物理与测控技术学院 南昌 330013)4(中国地质科学院地球物理地球化学勘查研究所 河北廊坊 065000) (wtshijiayu@163.com)

本文探讨的动态污点检测方法(dynamic taint analysis, DTA)是动态检测技术中的一种检测方法[1-3].该方法分析程序中由污染源引入的数据是否能够不经过无害处理,而直接传播到污染汇处.如果可以不经过无害处理,说明信息流是安全的;否则,说明系统产生了隐私数据泄露或危险数据操作等问题[4].

libdft库是一个由哥伦比亚大学开发的基于IntelPIN的字节粒度污点跟踪系统. 基于libdft设计的程序脆弱性检测工具可以在一个程序运行的同时进行检测,而不需要检查源代码,具有动态分析特色[5].该工具将来自不受信任的渠道(如来自于网络或用户输入的数据)标记为“污染源”[6-7],这些“污染源”将会在程序中执行一些算数和逻辑操作,由这些操作所生产的数据也会继承原数据的“污染与否”属性[8-9].当然,是否继承污染属性或清除污染属性取决于libdft系统定制的污染传播策略.如果这些被“污染”的数据作为JMP(跳转)指令或CALL(调用)、RET(返回)指令或MOV(移动)的目的地址,或是作为EIP寄存器中的指令数据等,被检测工具检测到[10-11],检测工具就会发送1条警报并展示相关污染源、污染颜色等信息,并终止服务,使针对该数据的操作不会再对系统产生危害[12].

目前libdft不算十分主流的DTA库,国内很少有人涉猎相关研究.由于相关文献较少,官方网址中只提供了库文件源代码,没有关于如何使用这些库文件的说明文档,因此,在此基础上实现真正的检测工具较为困难.本文对libdft库进行了深入研究,在此基础上实现一个对于大部分缓冲区溢出攻击具有检测功能和实际意义的检测工具,并在Linux系统平台上对该检测工具进行了验证.

1 libdft架构相关内容

libdft不仅提供了设定好的污染传播策略,还提供了许多应用程序接口(application program interface, API)供开发者使用.按照功能大致可分为以下几类[13-15]:

1) 初始化库相关;

2) 为指令插装;

3) 为系统调用/函数调用插装;

4) 进行染色取色操作,其中又可以分别对不同长度的数据进行操作;

5) 其他重要数据结构.

2 系统设计与实现

2.1 系统架构

基于污染传播策略设计的动态污点分析检测工具主要包括3个模块:污点标记模块、污点检测模块和信息反馈模块.检测工具的架构如图1所示.

图1 检测工具架构

检测工具的检测流程如下:

1) 通过动态二进制插装框架intelPIN初始化检测工具,指定必要的参数,将检测工具和目标程序同时启动;

2) 插装后的目标程序通过访问检测工具(污点标记、检测和反馈功能)和libdft库文件(主要提供污点传播功能),完成污点信息流的标记、传播和脆弱性攻击检测.

检测工具的检测流程如图2所示:

图2 检测工具的检测流程

2.1.1 污点标记模块

根据污点标记策略,建立外部不可信数据与污点标记的一一映射关系,利用libdft库提供的tagmap_set系列函数,对不同污染源进行不同颜色的标记[16].从实用角度考虑,对以下外部数据进行污点标记操作:

1) 标记指定函数的特定参数;

2) 标记网络I/O数据;

3) 标记文件I/O数据;

4) 标记用户键盘I/O数据.

为实现在上述位置的标记,使用插装代码的方式,在目标程序触发上述操作时,利用libdft库中的syscall_set_post()或ins_set_post() API,对其实现不同粒度的插装.在插装的代码中,根据不同类型外部数据采取不同的染色策略,完成对污染源的处理.

鉴于有些应用需要区别来自不同渠道的数据,该检测工具允许使用8种不同的颜色进行标记,8色标记比单色标记的精确度更高,能够满足大多数程序的脆弱性检测.

2.1.2 污点检测模块

污点检测模块根据定制的安全策略规则,对程序脆弱性进行检测.在需要进行检测的位置(污染汇位置),目标程序会进行敏感操作,而之前标记过的污点数据可能会作为这些操作的参数,导致安全危害发生.该检测工具主要对以下敏感操作进行插装,以检测参数是否被污染:

1) 通过网络发送信息;

2) 使用execve函数创建新进程;

3) 使用printf函数输出数据;

4) 执行RET指令,进入返回地址;

5) 执行JMP指令,实现跳转;

6) 执行write函数,写入文件;

7) 执行read函数,对用户的输入数据进行合法性检查和处理.

为了在上述位置进行插装,利用libdft提供的syscall_set_pre()或ins_set_pre() API,在敏感操作之前进行回调.根据不同操作,采用不同的策略进行污点检查,最主要的是使用tagmap_get系列函数对可疑参数进行取色操作.若检查到数据被污染,说明存在脆弱性,将采取相应措施阻止操作继续进行,防止危害系统.

2.1.3 信息反馈模块

图3 检测工具的具体工作流程

为了让用户对目标程序的运行情况及侦查到脆弱性后及时了解问题来源,信息反馈模块主要嵌入在2个位置:一是在执行插装代码时,向用户实时报告目前的操作和污染检测情况;二是在检测到脆弱性后向用户发送报警信息,并告知用户具体的污染源和污染颜色,便于用户进行后续处理.

为了能实时地在终端上显示信息,而不必让用户去打开日志文件重新检查,本文利用stderr的性质,采用fprintf(stderr, “your information”)语句实时输出信息.

而在检测工具发送警报时,只需要单独用1个alert()函数完成.该函数在发现污染时被调用.在终端警告当前污染的污染地址和污染来自哪个文件,并显示是哪个污染颜色.然后调用exit()函数来停止应用程序并防止攻击.

2.2 系统实现

对于不同的脆弱性模式,虽然检测的方法不同,但总体的工作流程是一致的,如图3所示.各种脆弱性检测都是在此原理基础上进行细节修改实现的.

2.2.1 针对心脏滴血攻击的检测

攻击者通过socket套接字输入过长的数据覆盖服务器的合法数据.服务器使用execve系统调用某个设定好的子程序,然而指令参数被攻击者输入的代码所覆盖,服务器利用execve调用的子程序更改成攻击者指定的恶意程序,将造成恶劣后果[17].此过程中的污染源是socket的recv操作,污染汇是execve调用.

如图4所示,在服务器的执行过程中,检测工具会对socket调用添加插装并对接收到的数据染色.在服务器要执行date程序时对该execve调用插装代码,对指令取色.接着检测指令是否被染色,若被染色则报警并终止程序.

图4 心脏滴血攻击检测原理

2.2.2 针对数据泄露攻击的检测

实际应用中,数据泄露事件时常发生.通过对不同污染源实施不同颜色标识得到数据泄露的源头[18].模拟服务器打开所有请求的文件,然后随机选择2个打开的文件,利用XOR(异或)操作合并成1个文件并通过网络发送,人为地提供1个“数据泄露”.检测工具可以识别出泄露的文件来自于哪些文件的结合.

在污染源部分,工具为open调用添加插装,为每个打开的文件分配1个颜色.若在之后的read调用中读取了某个文件,则可以取出文件对应的颜色,使用tagmap_set()将文件染色,然后更新打开文件列表.而在污染汇处理部分,针对socket的send调用操作安装插装,检查服务器将要发送的数据是否被污染过.若发现污染,循环所有可能的污点颜色,并检查导致警报的污点字节的标记中存在哪种颜色,从打开文件列表中读取结构,警报打印颜色和相应的文件名[19].

针对数据泄露攻击的检测原理如图5所示:

图5 数据泄露攻击检测原理

2.2.3 针对用户输入敏感信息泄露的检测

在某些情况下,系统需要保证用户输入的敏感信息不被直接读取显示在终端上,即保证用户敏感信息不被泄露.在污染源处增加对于用户输入数据的特别标识,而将终端输出作为污染汇,检测是否含有之前标记过的数据,防止泄露用户输入的敏感信息.

需要重点监控read和write调用.在read调用上插装,在read调用之后对从stdin文件读出的数据进行污染;最后在write调用上插装,在write调用之前对将要输入stdout文件的数据进行检测,数据流走向及插装位置如图6所示.实现方法为:对文件标识符fd是否为0设置条件判断,若fd=0,则为读取到的数据进行污染.增加针对write的插装函数pre_write_hook()作为污染汇,对于所有即将写入stdout文件的数据进行检测颜色操作.

图6 敏感数据泄露检测原理

2.2.4 针对格式化字符串攻击的检测

诸如“printf(str);”语句,由于没有标准地使用printf函数,存在格式化字符串漏洞.如果用户输入“%d%x”等格式化字符串,则会将内存的数据读取出来,造成内存泄露.如图7所示,为了防御该攻击,在read调用之后进行插装.在判断到用户终端输入后,对输入数据的合法性进行判断.将“%”作为非法标识,将输入字符串中所有的%符号作删除处理,以避免可能的内存泄露.

2.2.5 针对ReturnToLibc攻击的检测

ReturnToLibc攻击可以绕过操作系统的“栈不可执行”防御,通过脆弱程序返回时跳转到内存中本来就存在的代码(比如libc库中的system()函数等)地址来实现攻击.

具体的插装位置如图8所示,检测工具在read调用后进行函数级插装,对程序读取到的数据进行污染;同时对每一个RET指令进行指令级插装,以确保返回地址不是污染的,从而防御ReturnToLibc攻击.

图7 格式化字符串攻击检测原理

图8 ReturnToLibc攻击检测原理

其中对于RET指令的插装需要使用intelPIN提供的1对API:INS_InsertIfCall()和INS_InsertThenCall()来共同完成检测工作[20].这2个API也可以分别插装函数,从而对内存中指令目的地址进行检验和警示.针对RET操作目的地址的检测流程如图9所示:

图9 RET指令处插装操作流程

图10 心脏滴血攻击检测结果

3 系统测试

检测工具设计完成后进行程序脆弱性检测,表1为系统测试所搭建的实验平台环境.

对于心脏滴血攻击,libdft-dta动态污点检测工具生成如图10所示检测报告.

程序检测出了execve调用的参数是被污染过的,因此发送警报,指明来源(execve command)和颜色(tag=0x01)后退出.

表1 系统测试平台环境

对于数据泄露事件,libdft-dta工具生成如图11所示的检测报告.

在数据泄露情况下,发送的可疑数据被检测到并发现存在污点,打印警报,显示污染颜色(0x09)并指明污染来源(0x01和0x08),程序结束.

在需要检测用户输入敏感数据是否泄露的情况下,用户输入了password字符串.如图12所示,在程序输出时,检测工具发现输出数据含有用户输入的敏感字符,则立刻报警并终止程序.

如图13所示,在含有格式化字符串漏洞的程序中,用户输入格式化字符串%d%d%x.经过检测工具的合法性检测后,发现输入的数据中含有%,因此提示并进行处理.在终端输出时,输出字符串是去掉所有%的“ddx”,从而避免了内存泄露事件.

在ReturnToLibc攻击的情况下,工具检测到RET操作的返回地址被污染,输出当前的内存地址和目标地址,如图14所示,RET的目的地址正是0xf7e3fda0,即放入恶意文件中的system()函数地址.最后成功阻止攻击.

图11 数据泄露攻击检测结果

图12 敏感信息泄露检测结果

图13 格式化字符串攻击检测结果

图14 ReturnToLibc攻击检测结果

测试结果表明,该检测工具对于心脏滴血攻击、格式化字符串攻击、数据泄露、ReturnToLibc攻击等多种程序脆弱性能做到及时检测并报警,从而保护了计算机系统的安全.

4 结 论

本文就动态分析技术在程序脆弱性检测方面的应用开展了深入研究,对动态污点分析的原理、国内外研究现状及动态污点库libdft的工作原理等进行了详细分析,开发了基于动态污点分析的程序脆弱性检测工具,自定义了污染源和污染汇,以适应不同的脆弱性模式.测试结果表明,该工具可有效检测出心脏滴血攻击、格式化字符串攻击、数据泄露、ReturnToLibc攻击等多种程序脆弱性.该工具可以在未修改的二进制文件上工作,运行在常见的操作系统和硬件平台上,使用方便快捷.

由于动态分析的测试集覆盖范围小,以及libdft的局限性,该工具尚未穷尽所有类型的脆弱性模式,后续研究中还需进一步改进和完善.

猜你喜欢

污点脆弱性调用
Kaiser模型在内科诊疗护理风险脆弱性分析中的应用研究
工控系统脆弱性分析研究
基于代码重写的动态污点分析
农村家庭相对贫困的脆弱性测量及影响因素分析*
黑蚂蚁
基于PSR模型的上海地区河网脆弱性探讨
污点
系统虚拟化环境下客户机系统调用信息捕获与分析①
基于属性数据的系统调用过滤方法
利用RFC技术实现SAP系统接口通信