freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

CFI技术新探索,struct_san今日登场
云鼎实验室 2021-10-27 11:26:48 238319

一、背景

C/C++开发的应用程序,长久以来存在内存破坏类的安全问题。当攻击者掌握了目标程序的漏洞后,就可以开发漏洞利用程序劫持目标程序的控制流。早期的漏洞利用是采用代码注入的方式,通过在缓冲区置入一段代码(shellcode),然后控制pc寄存器跳入到缓冲执行这段代码。为了阻止此类攻击,后来计算机系统部署了DEP(Data Execution Prevention)机制,通过配置内存页属性,将缓冲区设置成不可执行,起到了很好的防御效果。为了绕过DEP,攻击者探索出了代码重用技术,在目标程序中搜索出一些攻击者期望的操作的代码片段,通过组织这些片段最终完成实现对目标机器的控制。这类攻击技术有Return-to-libc、ROP(Return OrientedProgramming)、JOP(Jump OrientedProgramming)等。如下图所示,代码有两条动态路径,在路径1存一个含有漏洞的节点。当攻击者通过漏洞修改这个节点的跳转逻辑,如果没有可靠的合法性验证机制,那么攻击者最终可以完全控制目标机器。

为了抵御上面的代码复用攻击,加州大学和微软公司于2005年提出了控制流完整性(Control-Flow-Integrity, CFI)的防御机制。Control-Flow-Integrity (CFI) 是一种确保软件必须在先前确定的控制流图上执行的安全策略。其核心思想就是在函数在发生不确定的跳转时,验证跳转的合法性。

CFI分为Forward Edges CFI和Backward Edges CFI。前者是在间接调用前验证控制流,而后者是在函数返回时验证返回地址是否属于调用者。下面罗列了Linux下相关实现,如下:

目前还有硬件实现的Backward CFI

* Intel CET 基于硬件的只读影子调用栈

* ARM V8.3a Pointer Authentication("signed return address")

二、struct sanitizer

我们通过分析一些常见的内核漏洞POC,发现这些POC对控制流的修改都集中在几种结构体内置函数指针的修改上。而上面的CFI的方案需要对所有代码进行插桩验证控制流,这样势必会带来明显的性能下降问题。所以我们提出了struct-sanitizer(struct_san)这种新的控制流完整性检测机制。

struct_san与上面的CFI方案相比,struct_san在对结构体指针的验证要比已有的CFI技术更严苛。当前主流的CFI技术主要是验证函数指针的类型,而struct_san在此基础上还要验证此函数指针是否还属于当前结构体实例。struct_san还可以做到非全量插桩,以减少一些非不必要的性能损耗。

三、实现原理

struct_san工作原理如下:

struct san 通过对在结构体里的函数调用前加入校验函数__sanitizer_struct_guard__(),来验证此函数指针是否属于当前结构体实例,如果验证合法则继续运行下面的间接调用函数,否则抛出ud2。

四、使用方法

struct_san为了避免非全量插桩,新增一个GNU Attributes __attribute__ ((sanitize_struct)) 。

使用方法是在想要保护的结构体类型声明处和调用此结构体的函数指针的函数前加入此关键字,例如想要保护内核中的pipe_buf_release()代码中的pipe_buf_operations->release()函数。

1.在结构体类型声明时加入此关键字

在类型声明完成以后,struct_san会将此类型的所有结构体实例保存到.sanitize_struct段内。

2.在需要保护的函数中也要加入上面的关键字。例如在pipe_buf_release()函数的声明和定义处加关键字,加入关键字后会在调用pipe_buf_operations->release()前插入校验函函数__sanitizer_struct_guard__()

下面是插桩前后在gcc的gimple IR中的不同表示:

插桩前

插桩后

五、检测算法

struct_san目前只在内核中完成了相关实现。其算法是在内核中开辟一个128M大小shadow memory用来保存结构体和结构指针的对应关系。__sanitizer_struct_guard__()在调用时会检测传入的struct和函数指针是否在shadow memory中,如果不在则抛出一个ud2异常,否则返回函数指针。实现方案如下:

这个算法参考了AddressSanitizer的实现,兼顾了效果和效率。

六、效果

以漏洞CVE-2021-22555的攻击代码为例,在启用struct_san的情况下,CFI阻断了攻击代码的执行,起到了有效的防御。

七、开源地址

我们对struct_san进行了开源,期望和业界一起探讨CFI技术的改进。后续我们也会推出一些其它的漏洞缓解技术。

https://github.com/YunDingLab/struct_sanitizer

# 云安全
本文为 云鼎实验室 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
云安全技术研究
云鼎实验室 LV.7
腾讯云鼎实验室 定期更新行业深度见解,由实验室专家倾力撰写 欢迎业内人士与热爱关注云安全领域的朋友关注 感受腾讯前沿科技~
  • 119 文章数
  • 123 关注者
腾讯董志强出席全国信安标委“标准周”:数字化转型需要高安全等级架构
2023-06-06
CSA GCR大会正式发布全球首个云渗透测试认证专家课程,腾讯安全获评“特别贡献单位”
2023-04-19
全球首个云渗透测试认证专家课程发布!腾讯安全领衔编制
2023-02-23
文章目录