返回介绍

介绍

发布于 2025-01-03 23:32:54 字数 1882 浏览 0 评论 0 收藏 0

为什么要学习 ROP? 人们滥用堆栈溢出很多年. 为了减轻攻击带来的损失. 微软从 WIN XP SP2 和 WIN SERVER 2003 开始引进了一项新的安全措施对抗从不可执行区域范围执行代码. DEP(数据执行保护) 包含两部分:

硬件 DEP: CPU 置内存为不可执行

软件 DEP

支持硬件 DEP 的 CPU 会拒绝执行被标记为不可执行的(NX) 内存页的代码. 这么做的目的是防止攻击者将恶意代码注入的另外一个程序执行. 尤其是基于栈溢出的漏洞,由于 DEP, 上的 shellcode 将不会被执行. 但 DEP 有时会造成程序意外错误,因为程序有时候可能需要在不可执行区域执行代码. 为了解决这个问题,微软提供了两种 DEP 配置。

Opt-In Mode:DEP 只对系统进程和特别定义的进程启用

Opt-Out Mode:DEP 对系统所有进程和服务启用,除了禁用的进程。

这对漏洞利用意味着什么?当我们尝试在启用 DEP 的内存执行代码,程序将会返回一个访问冲突” STATUS_ACCESS_VIOLATION (0xc0000005)" . 然后程序就终止了. 对于攻击者来说这显然不是好事. 但是有趣的是 DEP 可以被关闭,这意味着调用某个 Windows API 可以把某段不可执行区域设置为可执行. 主要的问题仍然是,如果我们不能执行任何代码的话又怎么去调用这个 API 呢?

开始我们的 ROP(返回导向编程). 这项技术最早由 Sebastian Krahmer 在 2005 的 SUSE Linux 提出. 你可以在这里找到这篇文档. ROP 基本的思想是借助已经存在的代码块(也叫配件), 这些配件来自程序已经加载的模块,用这些配件为我们的目标 API 设置参数. 我们可以在已加载的模块中找到一些列以 retn 结尾的配件,把这些配件的地址布置在堆栈上,当控制 EIP 并返回时候,程序就会跳去执行这些小配件,而这些小配件是在别的模块代码段,不受 DEP 的影响. 这就是 ROP 的原理,下面的这个例子可以帮助我们更好的理解它:

(1) 指针直接执行 retn          (2) 指针指向一些指令+retn

ESP -> ???????? => RETN           ESP -> ???????? => POP EAX # RETN
     ???????? => RETN               ffffffff => we put this value in EAX
     ???????? => RETN             ???????? => INC EAX # RETN
     ???????? => RETN             ???????? => XCHG EAX,EDX # RETN
(1) 这里 retn 仅仅是增加 esp       (2) 用配件将 EDX 清 0

相信你已经理解 ROP 的思想了. 下面我们列举所有的 ROP 配件一会会用它们布置目标 API 的参数,目标 API 才是真正关闭 DEP 的函数. 这项技术成功的关键在于我们需要在未启用 ASLR 的模块去寻找这些小配件。

下面是不同的 API 在不同的系统下可用情况。

可以看到不止一种方法可以达到目的. 有些方法更普遍. 不同的 API 有不同的参数,详细的参数请看 MSDN. 一般而言系统模块都启用了 ASLR. 所以我们从软件自身加载的模块看是否包含这些 API 的指针。

基本上有两种方式写 ROP

(1) 把 API 需要的参数都放到寄存器,用一个 push 指令把他们压入栈(这是下面我们要做的)

(2) 直接把 API 需要的参数布置到栈然后跳去这个 API 执行,这种方法有点难。

最后我要提一点,对 payload 创建一个完整的 ROP 也是可以的。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文