使用比给定更多空间的想法,因此溢出到不同的领域很简单,可以想象。但可能尚不清楚这如何导致坏人运行自己的代码。
如果你理解得足够好,这很容易解释。只要确保你击中了重要的背景。或多或少按此顺序:
“堆栈”是您可以存储临时信息的地方。“堆栈指针”确定堆栈的末尾在哪里。当一个函数运行时,它移动堆栈指针以给自己内存以供使用,当它完成时,它将指针移回它找到它的位置。
堆栈向后增长。因此,要在堆栈上给自己 100 个字节,请从堆栈指针中减去100,而不是添加它。如果前一个函数的堆栈从 1000 开始并且我想要 100 个字节,那么我的堆栈从 900 开始。
这意味着,如果您使用的空间比给自己的空间多,您将不会继续写入空白空间,您实际上会开始覆盖以前的堆栈值。
当我的函数启动时,前一个函数为我留在堆栈上的最高值是函数完成后我应该去的返回地址。
这意味着如果我的函数超出了它的堆栈,它首先要覆盖的是返回地址。如果攻击者小心他用什么填充堆栈,他可以指定他想要的任何返回地址。
当我的函数存在时,该返回地址处的任何代码都是接下来将执行的代码。
简单示例
在Smashing the Stack for Fun and Profit中,最初描述了这种技术,介绍了最简单直接的技术。想象一下这个函数读取你的名字然后返回。所以你的堆栈看起来像这样:
Stack Pointer Prev. Stack Ptr
+----------------------------------+--------------+................
| Your Name Here | Return Addr | Old stack ...
+----------------------------------+--------------+................
但是这个坏人的名字足够长,以至于溢出了空间。不仅如此,他没有输入真实姓名,而是输入了一些邪恶代码、一些填充物和那个邪恶代码的地址。
+----------------------------------+--------------+................
| [ Evil Code ]xxxxxxxxxxxxxxxxxxxxxxEvil Address | Old stack ...
+----------------------------------+--------------+................
▲──────────────────────────────────┘
现在不是返回到前一个调用者,而是直接跳转到[Evil Code]
. 现在你正在运行他的代码而不是你的程序。从那里它几乎是游戏结束。
缓解和其他技术
用于降低堆栈粉碎效率的两种技术是 DEP 和 ASLR。
DEP(“数据执行保护”)通过将堆栈标记为不可执行来工作。这意味着[Evil Code]
堆栈上的 不会运行,因为不再允许在堆栈上运行代码。为了解决这个问题,攻击者会找到大量现有代码,这些代码将执行他想要的零碎工作。而不是仅仅覆盖他自己的返回地址,他通过堆栈为他想要依次运行的所有函数创建一个返回地址链。他们称之为“面向返回的编程”或 ROP。返回链称为“ROP 链”。这真的很难做到。但是有一些工具可以提供帮助。
ASLR(“地址空间布局随机化”)通过随机化所有有趣函数的位置来工作。现在创建 ROP 链并不容易——每次程序运行时,所有地址都在不同的位置。所以当攻击者去用自己的邪恶地址覆盖返回地址时,他将不知道使用什么数字,因为代码总是在不同的地方。
DEP 和 ASLR 本身都不能提供太多保护,但两者一起使成功利用变得非常困难。虽然有时存在一些规避措施,但没有一种解决方法可以在任何地方都有效。如果你能绕过 DEP+ASLR,那就是一次性的成功。