击败 ASLR 的典型策略是同时查找缓冲区溢出错误和信息泄露错误。但是,当攻击在崩溃/死亡时自动重新启动的服务器时,缓冲区溢出错误是否足够?我们是否可以利用缓冲区溢出漏洞也为我们提供信息披露能力?
让我充实一下这个场景。假设我有一个服务器程序处理来自网络的请求,并且会在崩溃时自动重新启动,并且假设我发现了一个缓冲区溢出漏洞(堆分配的缓冲区B) 在服务器中,我可以通过向服务器发送适当制作的请求来可靠地利用它。还假设我可以检测到服务器何时崩溃(例如,它可能会崩溃,因为我向它发送了一个损坏其内存并导致其出现段错误的请求;无论如何,假设我可以向它发送我选择的请求并确定它是否尝试处理该请求时是否崩溃)。服务器正在使用 ASLR,我想对 ASLR 进行去随机化,以便进行代码注入攻击,但我不知道一个单独的信息泄露漏洞——缓冲区溢出漏洞是我必须处理的全部内容。
我可以利用这个缓冲区溢出漏洞进行信息泄露,来学习内存中的内容B吗?
这是我想象的那种攻击的例子:
假设可溢出缓冲区
B的长度为 512 字节,并假设P紧跟其后存储了一个秘密的 8 字节指针B。假设请求的字段 F 被逐字节复制,B没有任何长度检查。如果我发送一个 F 值为 513 字节的请求,它将被复制到
B. 如果我的值的第 513 个字节与 的第一个字节不同P,那么 的值P将被破坏,并且(假设程序稍后取消引用P)然后程序可能会在处理此请求期间崩溃。另一方面,如果我的值的 513 字节与 的第一个字节匹配P,那么P将保持不变,并且程序可能不会崩溃。所以,我可以想象发送 256 个请求,每个请求对于字段 F 的第 513 个字节都有不同的值;如果其中 255 个导致服务器崩溃而一个没有,那么我立即知道
P. 现在我可以继续,直到我了解P. 如果程序使用 ASLR,这可能很有用:通过学习指针的值P,我可以对部分内存进行去随机化。
这只是一个简单的例子。在实践中,我想在堆中存储的下一个对象之后和之前可能会有未使用的空间B,但是您可以想象调整这些技术以处理这种情况的方法(例如,如果之后的字节B未使用, 然后你可以用任何东西覆盖它并且服务器不会崩溃,因此很容易检测到未使用的位置,并继续攻击直到找到下一个对象之后B)。
这种攻击在实践中有效吗?当您在自动重新启动的服务器中出现堆溢出并且您有办法检测崩溃时,它是否提供了一种有效的方法来击败 ASLR?
是否有任何我忽略的障碍阻止了它的工作?例如,我可以想象,如果堆中对象的内存分配是不确定的和随机的,那么攻击就会失败;但是平台会这样做吗?如果您在相同的输入上运行相同的程序两次,堆中对象之间的相对偏移量在实践中是否确定?
我假设缓冲区溢出允许B使用完全在攻击者控制之下的任意二进制数据进行覆盖。(该攻击不适用于与strcpy()或字符串相关的溢出,因为那时数据被强制以 nul 终止。)另外,我们假设服务器使用 fork() 重新启动,或出于其他原因,每次重启服务器时,部分内存布局都是一样的。(例如,这在 Windows 和 Mac 上自动生效,因为每次重新启动服务器时库都位于相同的基地址,并且它适用于 Linux 上的非 PIE 进程。)
信用:我最近读到的一种方法启发了我,该方法利用堆栈分配缓冲区的缓冲区溢出错误来进行信息披露。这在最近发表在 IEEE Security & Privacy 2014 上的 Blind ROP 论文中有所描述。他们展示了如何B在堆栈上分配缓冲区时执行此操作。在这个问题中,我问他们的技术是否可以推广到缓冲区B在堆上的情况。