Windows注册表攻击面分析
安全特性概述
Windows注册表作为本地权限提升的攻击面具有以下关键特性:
- 本地权限提升攻击面:注册表是严格的本地攻击面,低权限进程可能利用它获取更高权限进程或内核的权限
- 复杂的老旧代码库:注册表机制完全用C语言编写,大部分代码已有多年历史,容易出现逻辑和内存安全漏洞
- 位于核心NT内核:注册表实现位于Windows内核可执行文件中,不受win32k锁定等缓解措施的限制
- 大多数代码可由非特权用户访问:绝大多数注册表相关代码无需特殊权限即可访问
- 管理敏感信息:注册表存储安全关键的系统信息,包括全局配置、密码、用户权限等
漏洞类别分析
广泛的漏洞类别
由于注册表既复杂又在系统中以内核模式权限运行,可能出现的漏洞类别包括:
- 配置单元内存破坏:每个侵入性操作都会反映在配置单元结构的内存映射视图中
- 池内存破坏:配置管理器在内核池中存储大量信息
- 信息泄露:注册表实现必须小心不向调用者意外泄露未初始化数据
- 竞态条件:作为多线程环境,注册表实现必须正确同步对所有共享内核端对象的访问
- 逻辑漏洞:注册表实现必须强制执行正确的高级安全逻辑
- 进程间攻击:注册表可作为安全目标,也可作为利用系统中其他应用程序漏洞的手段
手动引用计数
安全描述符在注册表配置单元中由多个密钥共享,因此必须进行引用计数。引用计数机制容易出现的漏洞包括:
- 从磁盘加载的初始引用计数值不可信
- 引用计数操作未受整数溢出保护
- 特殊类型密钥(如预定义密钥和墓碑密钥)的安全描述符处理不当
- 在多步骤操作中过早释放安全描述符
积极的自我修复和恢复
注册表的一个显著特性是自我修复能力,但从安全角度看,这种行为可能不利:
- 修复逻辑构成了额外的攻击面
- 自我修复可能掩盖潜在的注册表错误
- 不一致的配置单元状态可能不会立即导致系统崩溃
模糊的格式要求边界
在regf格式中,存在三类要求:明显必须满足的要求、允许任意格式化的元素,以及似乎合理但不清楚是否正式要求的灰色区域。
攻击入口点
配置单元加载
用户控制配置单元的加载操作只能从磁盘进行,常规程序通常具有此能力,但重度沙盒化进程可能受限。
应用程序配置单元
Windows Vista中引入的应用程序配置单元显著改变了注册表攻击面,允许非特权进程直接与之前仅系统服务和管理员可访问的内核代码交互。
用户配置单元和强制用户配置文件
某些漏洞需要二进制控制配置单元和应用程序配置单元缺乏的特定功能,这时可以直接修改分配给系统中每个用户的两个配置单元之一。
日志文件解析
注册表保证相互依赖的单元级别的一致性,这种"原子性"通过使用与配置单元关联的附加文件实现。
直接注册表操作
对密钥和值的直接操作是注册表的核心,构成大多数相关代码,这些基本操作不需要特殊权限,所有用户均可访问。
高级功能集成
预定义密钥和符号链接
预定义密钥已在2023年弃用,符号链接是需要特殊标志创建的半文档化功能。
注册表虚拟化
Windows Vista中引入的注册表虚拟化确保旧应用程序的向后兼容性,该机制透明地重定向HKLM\Software和HKU<SID>_Classes\VirtualStore子密钥之间的引用。
事务处理
注册表事务有两种类型:KTM和轻量级事务,两者都提供了确保一组注册表操作原子性应用的机制。
分层密钥
分层密钥是Windows注册表中最新的大型变更,颠覆了许多基本假设,使得逻辑密钥不再仅由一个密钥节点和最多一个活动KCB组成。
漏洞利用原语
池内存破坏
池内存破坏可能是Windows内核中最常见的低级漏洞类型,在注册表上下文中,这类漏洞相对较少但仍完全可能发生。
配置单元内存破坏
配置单元内存破坏是注册表中遇到的第二种内存破坏,这类漏洞基于存储在配置单元中的数据具有双重角色的事实。
无效单元索引
这类漏洞在对象中出现不正确的单元索引时直接表现出来,可分为三个子组,具体取决于攻击者对单元索引的控制程度。
低级信息泄露
由于注册表代码用C语言编写并以内核权限运行,在将输出数据复制到用户模式时可能容易受到内存泄露问题的影响。
模糊测试考虑
由于Windows注册表具有严格定义的格式和接口,自动化测试形式的模糊测试当然是可能的,但注册表并不是自动化测试的简单目标。
初始语料库
潜在研究人员可能遇到的第一个问题是收集输入文件的初始语料库,标准配置单元中的所有数据结构实际上从未接近格式本身施加的限制。
变异器
总体而言,变异器的问题与初始语料库的问题非常相似,在这两种情况下,目标是根据某些指标生成最"有趣"的regf文件。
测试工具
虽然拥有注册表相关文件的良好变异器是一个很好的开始,但绝大多数潜在漏洞在加载畸形配置单元时不会表现出来,仅在对所述配置单元进行进一步操作期间才会出现。
错误检测
除了良好的初始语料库、变异器和测试工具外,有效模糊测试会话的第四个也是最后一个支柱是错误检测。