内存分配/布局何时是确定性的?

信息安全 缓冲区溢出 aslr 开发开发 堆溢出
2021-09-02 01:16:23

我正在尝试了解堆栈和堆上的缓冲区溢出攻击。但是,我对何时可以确定缓冲区的地址感到困惑。

经典的“Smashing the Stack for Fun and Profit”提到需要在基于堆栈的缓冲区溢出攻击中使用相当大的NOPsled,以便可靠地跳转到放置在缓冲区中的 shellcode。这似乎是由于在程序的每次运行中缓冲区最终位于不同的内存位置。但是,它不是完全随机的,因为可以通过增加使用NOP雪橇的机会来猜测缓冲区的地址。

相比之下,传递给程序的环境变量每次都放置在相同的地址中,从而使本地攻击更加容易,攻击者将 shellcode 放入环境变量中,然后可以准确地跳转到该环境变量的位置。

malloc对于基于堆的缓冲区(例如由 分配的缓冲区)和其他情况,我仍然一无所知。所以:

  1. 在什么情况下内存布局是确定性的?
  2. 即使不是完全确定的,它的可预测性如何?最后,ASLR 和 PIE 等漏洞利用缓解措施对此有何影响?
2个回答

部分问题与程序初始化时的内存布局以及运行一段时间后内存布局的外观有关,并且您设法让缓冲区溢出。您还必须应对“在我的机器上工作”问题。

所以在初始化时,所有的环境变量都将被加载到同一个地方,因为这是一个合理的固定和早期过程。当涉及溢出缓冲区时,您不能始终确保每次都在同一时间触发它。例如,如果应用程序接收到网络数据包,您就很难一直发送完全相同的数据包。因此,当您触发溢出时,内存布局可能并不完全相同。因此,需要将 NOP 雪橇作为“着陆”的地方。

“在我的机器上工作”的问题是,实际上,你希望你的漏洞利用在其他人的机器上工作,而且他们不太可能像你的机器一样配置。可能有不同版本的库,不同的硬件配置,所有这些都意味着目标溢出地址不太可能和你的相同。

这些问题可能难以确保内存布局始终相同,因此您需要处理一系列可能的值,因此需要 NOP sled。

程序内部的确定性

尽管对已知数据的所有确定性操作都会产生确定性结果,但内存布局并不打算被视为对内核开发人员以外的任何人都是确定性的。尽管布局在数学意义上是确定性的1,但软件行业快速变化和多样化的性质使得应用程序对系统结构的看法实际上是随机的。

便携式安全功能

可移植或可靠的代码都不能依赖于提供的标准化编程模型之外的关于内存的假设。堆栈、动态分配或静态内存头可以更改,并且编译器可以同步更改,以便符合标准的程序可以顺利运行,但是利用特殊操作系统知识的程序可能会破坏并产生比它声称要消除的更多的安全风险.

程序不能依赖于内核结构随时间的一致性。CPU 架构、它们的指令集、执行模型、堆栈处理以及 malloc 和 free 的底层机制可以随时更改。这就是 POSIX 和其他标准的原因。只有通过标准化系统调用提供的外观才能(通常)被信任以表现出可预测的行为。

避免环境变量利用

如果愿意,可以遍历环境变量,复制所需的值,然后在每个变量占用的确切范围内写入零。但这不是最好的策略。

一般有用的系统和源码实践

许多安全团队使用的唾手可得的成果是阻止所有用户执行所有可执行软件,但那些有意义的用户软件组合除外。那些被允许的会被分析潜在的安全漏洞,并应用适当的补丁来最小化它们。

针对缓冲区溢出和下溢的适当的特定漏洞防护措施是在 C 等语言中仔细验证缓冲区索引,或者正确使用旨在防止这些可利用内存模型操作的对象。

熵注入方法

地址空间布局随机化 (ASLR) 是一种操作系统功能,可提供额外的攻击抵抗力。您不会将 ASLR 添加到您的程序中。提供该模型的每个操作系统都有一种机制,在该机制中,可以执行特定程序,而无需通过进程检查提供太多提示,从哪里将可执行指令字节加载到 CPU 中。

与位置无关的可执行文件 (PIE) 是一种支持随机化的机制,它确保可执行文件中的所有地址都是相对的或行为(在指令组中)就好像它们是相对的一样。

您将需要研究如何在您的特定目标操作系统中应用向内存模型定位添加熵。您的代码、要使用的编译或链接标志以及执行所需随机化的容器执行可能存在相关约束。可能会影响速度和资源,因此您可能希望确定可执行的风险级别并有所选择。

它们是如何工作的?在内存位置确定中引入熵使攻击者难以猜测 CPU 指令驻留在内存中的位置,因此在多任务场景中,更难以从另一个时间片内实时确定跳转源和所需目标。

累积安全强度的分层策略

请记住,这些是警卫而不是安全保证。很少有成本有效的策略能像世界一流的系统管理、程序内仔细的内存访问和传入数据的出色卫生的传统组合一样有效。此列表中最近添加的内容是为这些有效策略添加层,以提高系统对攻击的弹性。


[1] 内存布局是确定性的,除非操作系统从鼠标移动、音频输入或其他传感器捕获真正的熵,然后以随机(而不是伪随机)方式来定位内存。