【论文阅读笔记】Securing software by enforcing data-flow integrity

Securing software by enforcing data-flow integrity是一篇2006年发表的论文,首次提出了DFI数据流完整性的概念,对今后防御不改变控制流的攻击形式有启发意义。

本文是对该文的部分核心内容的整理,其中也有一些本人自己的思考。如文中有不当和有误之处,敬请指出,谢谢。

欢迎转载交流,但请注明出处。


Data-flow Integrity,数据流完整性,简称DFI。数据流完整性执行(DFI enforcement),可以分为三个阶段。

第一阶段,对程序使用静态分析计算数据流图(Data flow graph,DFG)。

第二阶段,给程序装载保护机制,确保程序在执行中的数据流被控制流图所允许。

第三阶段,运行装载了保护机制的程序,当程序的数据流完整性被破坏时,抛出异常。

我们使用一个简单的例子说明这三个阶段的工作。


int authenticated = 0;
char packet[1000];

while (!authenticated) {
    PacketRead(packet);

    if (Authenticate(packet))
        authenticated = 1;
}

if (authenticated)
    ProcessPacket(packet);

图1 示例漏洞C代码,模拟了SSH认证登录的过程。PacketRead函数读取客户端的数据并解析,如果认证通过则调用ProcessPacket函数处理。


我们假设PacketRead函数没有对输入的packet长度做检查,因此这段代码有明显的缓冲区溢出漏洞。攻击者可以对这个程序执行两种攻击:

  1. 覆盖返回地址RET。这是典型的Control-data attack控制数据攻击,允许攻击者获得修改执行控制流。
  2. 覆盖局部变量authenticated。这是Non-control-attack,攻击者因此可以绕过认证,使其发送的packet被ProcessPacket函数处理。

我们接下来可以看到,DFI执行可以防御上述两种攻击。

第一阶段

我们使用可达定义(到达-定值)分析(RDA,Reaching definitions analysis,这是代码分析学里数据流分析的一种方法,请参见论文AHO, A. V., SETHI, R., AND ULLMAN, J. D. Compilers: Principles, Techniques and Tools. Addison Wesley, 1986.。还可以看看南大的软件分析课程)来计算静态数据流图。使用可达定义分析的术语,我们称呼:一个向某内存位置写数据的指令,“定义”(Define)了该内存位置的值;一个读取该值的指令,“使用”(Use)了这个值。RDA计算了每个use(为了表意清楚,下文都会使用英文)的可达定义(Reaching definition)集合,并给每一个definition都赋给了一标识符作为标记。RDA最终返回了一个从指令到definition标识符的映射和一个包含每个use的可达定义标识符集合,我们称之为“静态数据流图”。

还是以图1为例。变量authenticated在第4行和第11行被Use。如果我们对源代码使用RDA,它可能会告诉我们第1行和第8行的definition可达这两个use(想要理解这句话最好还是详细了解RDA)。因此,这两个use的可达definition标识符的集合可表示为{1, 8}——如果我们使用行号作为定义的标识符的话。

这种分析不一定是精确的,换言之,它有些保守。我们在代码分析学里把RDA划分为“may analysis”一类。简单说,RDA要求所有可能在运行时到达一个指定use的definition,都应当被包含到集合当中去,这可能导致集合里有些冗余的元素。还是以图1为例,不难看出,在实际执行中,如果authenticated不为1,程序不可能跳出循环,因此事实上只有第8行的定义才能到达第11行的use。但在RDA分析里,集合必须包含第1行的标识符。这说明,RDA的分析可能导致漏报(假阴性),但不可能有误报(假阳性)。因此,数据流完整性执行可能会漏报攻击,但不可能在没有错误的情况下报警。从作者的观点看,这是一件好事。因为大多数用户并不喜欢误报,即在没有错误的情况下让程序崩溃。

第二阶段

我们为程序装载能够保证DFI的防御机制。在此作者为DFI给出了高度概括的定义:无论何时一个值被读取,写值的语句的definition标识符都必将在被读的语句(use语句)的可达定义集合当中。

程序装载的防御机制,会在运行时计算到达每个read的definition,检查definition是否在静态分析计算出来的可达定义标识符集合当中。为了在运行时计算可达定义,我们维护了一个数据结构:运行时可达定义表,runtime definition table,简称RDT。RDT可以记录每个内存位置最后一个写入指令的标识符。每一个写入指令都将会被用于更新RDT。我们用被读值的存储地址来从RDT种检索标识符。然后,我们检查这个标识符是否在之前静态分析计算出来的可达定义标识符集合当中。

以图1为例,在程序运行到第8行的时候,防御机制会将RDT[&authenticated]赋值为8,表示目前最后一个define变量authenticated的指令在第8行;当程序运行到第11行时,则会执行检查,看看RDT[&authenticated]是否属于集合{1, 8}。

在文中,我们假设攻击者可以向任何内存地址写入任何数据,并且拥有执行权限。因此,DFI的防御机制必须能够避免攻击者篡改RDT,篡改代码,或者用其他手段绕过我们的防御机制。

如何避免上述bypass呢?为了避免攻击者篡改RDT,我们将检查写指令的目标地址是否在给RDT所在的内存空间范围中,任何企图写入RDT内存的尝试都会触发异常;至于其他的bypass,交给DEP和ASLR等等现有防御机制即可。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大学生参加学科竞赛有着诸多好处,不仅有助于个人综合素质的提升,还能为未来职业发展奠定良好基础。以下是一些分析: 首先,学科竞赛是提高专业知识和技能水平的有效途径。通过参与竞赛,学生不仅能够深入学习相关专业知识,还能够接触到最新的科研成果和技术发展趋势。这有助于拓展学生的学科视野,使其对专业领域有更深刻的理解。在竞赛过程中,学生通常需要解决实际问题,这锻炼了他们独立思考和解决问题的能力。 其次,学科竞赛培养了学生的团队合作精神。许多竞赛项目需要团队协作来完成,这促使学生学会有效地与他人合作、协调分工。在团队合作中,学生们能够学到如何有效沟通、共同制定目标和分工合作,这对于日后进入职场具有重要意义。 此外,学科竞赛是提高学生综合能力的一种途径。竞赛项目通常会涉及到理论知识、实际操作和创新思维等多个方面,要求参赛者具备全面的素质。在竞赛过程中,学生不仅需要展现自己的专业知识,还需要具备创新意识和解决问题的能力。这种全面的综合能力培养对于未来从事各类职业都具有积极作用。 此外,学科竞赛可以为学生提供展示自我、树立信心的机会。通过比赛的舞台,学生有机会展现自己在专业领域的优势,得到他人的认可和赞誉。这对于培养学生的自信心和自我价值感非常重要,有助于他们更加积极主动地投入学习和未来的职业生涯。 最后,学科竞赛对于个人职业发展具有积极的助推作用。在竞赛中脱颖而出的学生通常能够引起企业、研究机构等用人单位的关注。获得竞赛奖项不仅可以作为个人履历的亮点,还可以为进入理想的工作岗位提供有力的支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值