Vulnerability mitigation

less than 1 minute read

Published:

基础概念

漏洞缓解包括事前的安全编程、漏洞挖掘,事后进行补丁,对软件执行状态进行安全检查。

通用原理

防御思路:主动部署安全检查,感知攻击过程或消除攻击危害

解决方案:基于引用监控器的安全不变量检查

  • 在关键的代码/数据引用位置部署引用监控器,实行内生安全检查
  • 在软件执行过程中监测安全不变量,检测、缓解、阻断未知漏洞攻击

部署方式

  • 基于漏洞条件加固(打补丁):运行时代价小,漏洞条件难以准确提取,漏洞无法提前预知、无法保证挖完
  • 基于安全策略加固(安全检查):主动、通用、防御一类漏洞,性能开销大

漏洞缓解策略

完整性保护

阻断:代价大,安全强度较高

软件:Bound check + tag check=完全存储安全性

  • bound check(分配meta->传播metadata->检查metadata)
    • fat pointer: 使用两个指针标记buffer的开头和结束为止,修改buffer内容时首先检查是否超出buffer内容
      • 可以检查子对象的溢出
      • 使用内联的元数据,会改变存储布局,因此资源兼容性低
    • object-based: 将对象插入object table,在修改时在object table中查找是否越界
      • 不关联的metadata,不会改变存储布局,因此资源兼容性高
      • 无法检测子对象的溢出,查找object table的成本不一定
    • SoftBound: 使用不关联的metadata表代替fat pointer,在不改变存储布局的情况下对任意投射安全
  • CPI(code pointer integrity): 将存储分为安全存储和普通存储,之间使用基于硬件的设施级别隔离
    • 安全存储保存敏感指针和元数据,仅对敏感指针进行检查(代码指针和指向敏感指针的指针)
    • 创建元数据时显式获取静态分配的内存对象或函数的地址,在堆上分配新对象,或获取子对象的地址
    • 安全性检查:敏感指针的每次取消引用都会在运行时进行检查,普通指针的取消引用不用进行安全性检查
  • tag check:对存储段打标记,在每次进行修改时对标记进行匹配,如果不匹配则不能进行修改 硬件
  • ARM MTE
  • Intel MPX:intel内存保护扩展
    • 检查所有指针的读取和写入,以确保它们在已声明的内存范围内。这个技术可以检测缓存区的溢出,并且停止正在运行的程序以避免危及系统。

检测:代价小,安全强度相对较低

软件

  • Stack canary:因为大部分buffer溢出都序列性出现
    • 在返回地址附近放置一个随机的canary,在函数退出时检查canary的值来判断是否存在溢出
    • 随机布置,因此攻击者难以猜到正确的cookie,很容易通过编译器支持实现
    • 难以保护无法重编译的老代码,且可以绕过
      • 通过信息泄露漏洞获取cookies/找其他不顺序重写的漏洞/重写返回地址之外的敏感数据/逐字节暴力攻击
  • Shadow stack
    • 在函数开头将返回地址RET和SFP复制到安全栈,在返回时检查RET和SFP是否和备份一致
    • 保护性强,难以重写返回地址
    • 需要保护安全栈,运行成本高,有兼容性问题 硬件
  • ARM PAC:通过keyed-MAC检查是否存在溢出
  • ROLoad:编译时根据方案生成指令,处理器内核检查内存页的权限,被访问的内存页是否只读,内存页标签是否与指令匹配

隐藏漏洞

软件

  • 随机化代码地址(ASLR)
    • 对地址空间的布局进行随机化,破坏攻击的指向
    • 对代码段整体做随机,代码内部的指针相对位置不变,是对整体进行偏移
    • 性能好(只用在加载时做一次随机化),需要内核支持,不需要重编译,对安全应用透明,安全性保证在32位系统上不佳,但在64位系统上较好,有效防御注入攻击
    • 地址无关代码(PIC):可在存储器中任意位置正确运行,不受绝对地址影响的机器码
      • 使用程序连接表(PLT:procedure linkage table)和全局偏移表(GOT:global offset table)的惰性链接方式,首次调用前全局偏移表调用程序连接表获得函数真实地址,全局偏移表随后将保存的程序连接表地址更新为函数真实地址。
    • 地址独立可执行程序(PIE):ASLR必须,将所有的绝对地址引用替换为相对地址,与PIC相似,可将程序装载在存储器任意的地址
  • 仅可执行存储
    • 程序部署在仅可执行存储分段内,不能进行复制和修改,保护程序避免复制和干预
  • 堆随机化 硬件
  • 仅可执行存储
    • 在普通存储中的程序可以调用在仅可执行存储中的函数(API),但看不到存储中的内容
    • ARM 使用HPROT,ARPROT/AWPROT 信号的总线系统
    • RISC-V 物理存储保护(PMP)

隔离资源

软件

  • 软件错误隔离
    • 目的:将错误隔离在不信任的扩展中,允许有效的跨域调用
    • 主要思路:将进程地址空间按模块划分成不同的段,按不同的id标记
    • 段匹配:按段id查找匹配的存储,提供专用的段寄存器和数据寄存器
      • 段匹配代码必须运行以保证安全性
      • 专用寄存器必须不能被模块修改
      • 修改较多,可以在段id不匹配时精确定位错误
    • 沙箱:强制要求顶层位字匹配段id,不对段id进行查找比较
      • 修改较少,仅保证存储访问停留在区域内
  • CPS
    • 堆/全局隔离:程序存储通过硬件强制的设施级别隔离划分为安全存储和常规存储,安全存储仅保存代码指针,常规存储保存非代码指针,不修改存储布局。接触代码指针的修改使用基于类型的静态分析进行识别。
  • 沙箱 硬件
  • Intel MPK:
    • 引入PKRU寄存器,指明内存页读写权限,需要同时通过页表和PKRU的权限检查
    • 在页表中加入PKEY索引(59-62四个比特),指明在PKRU中的domain,domain指明具体权限
    • PKRU寄存器存储16组权限,可以给不同线程分配不同domain,然后更改PKRU的domain给线程分配不同的权限,实现进程内隔离
  • ARM DACR,Intel SMEP, SMAP

进行访问控制

软件

  • 控制流完整性(CFI)
    • 特点
      • 保护性强:拥有对于全部数据存储的完全控制
      • 应用范围广:语言无关,只需要二进制文件
      • 可信/正确性可证明:有正式语义,容易验证
      • 有效:实验中减少0-45%的攻击成功率?
    • CFI模型:
      • 可以在任意时间修改任意数据存储,可重写当前context的寄存器,但不能删除数据,修改代码,向%ip写入,重写其他context的寄存器
      • 执行必须遵循在运行之前创建的控制流图中的路径执行
    • 方法
      • 在编译时静态创建控制流图
        • 指定函数间的直接调用和非直接调用关系
      • 在安装时调整二进制文件(增加ID和ID check/维护ID唯一性)
        • 为控制流图中的每个调用目的添加唯一的标签,如果控制流图中同一个源节点有指向两个目的的边,则这两个目的等价(标签一样)
        • 标签指明控制可转移的目标
      • 在加载时验证CFI调整(直接跳转目标/ID和ID check是否存在/ID是否唯一)
        • ID Check:跳转前检查目标的label,目标label匹配时才跳转
      • 在运行时执行ID检查(不直接跳转要有匹配的ID)
  • 数据流完整性
    • 编译时计算变量的合法写操作
    • 运行时追踪每个变量最后一次写操作
    • 确保变量使用时写操作是合法的 硬件
  • Intel CET
    • 非直接分支追踪:追踪分支是否结束,防止跳转到任意地址,阻止面向跳转的编程攻击
    • shadow stack:使用shadow stack提供返回地址保护,阻止面向返回的编程攻击
  • Stop Code injection/exec.(NX/DEP):
    • 将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令
    • 有硬件支持时对性能无影响,其他情况小于1%,部署需要内核支持和模块内部算子支持(windows),可以深入合法的程序内部,安全性保证为在NX页的代码永不执行