计算 NOP 雪橇中的地址

use*_*694 5 buffer-overflow aslr no-op

我目前正在阅读计算机系统简介:程序员的视角(http://www.amazon.com/Computer-Systems-Programmers-Perspective-2nd/dp/0136108040/ref=sr_1_2?s=books&ie=UTF8&qid=1421029641&sr=1 -2&keywords=introduction+to+computer+systems)并尝试了解阻止缓冲区溢出的方法。

我理解为什么在使用地址随机化时我们需要 NOP 雪橇以及如何编写漏洞利用程序,但我很难理解书中给出的与 NOP 雪橇相关的地址计算。我在这里引用它:-

(假设程序在堆栈上的起始地址范围在32位系统上为2^23,在64位系统上为2^32)

“如果我们设置一个 256 字节的 NOP sled,那么可以通过枚举 2^15 个起始地址来破解 n=2^23 上的随机化,这对于坚定的攻击者来说是完全可行的。对于 64 位情况,尝试枚举 2^ 24个地址更令人畏惧。”

作者是如何分别为 32 位和 64 位情况得出数字 2^15 和 2^24 的?一个解释真的很有帮助。

Max*_*org 3

他们只是假设 32 位系统上的最大共享内存总量(千字节),这就是8388608他们提出的2^23

2^15计算公式如下:

(8388608 / 256) = 32768 == 2^15
Run Code Online (Sandbox Code Playgroud)

换句话说:

total_memory_size / NOP_sled_length = total_iterations_to_find_NOP_sled_in_memory
Run Code Online (Sandbox Code Playgroud)

他们计算得出的结果是基于这样的假设:我们的 NOP 雪橇可以位于从0x0一直到0x800000(即83886082^23)的范围内的任何位置。因为我们的 NOP sled 长 256 字节,所以我们不需要为每次猜测/迭代/暴力增加 1,而是每次增加 256,从而得到上面等式的结果0x800000 / 256 = 32768 == 2^15。因此,我们只需要暴力破解 32768 个可能的地址,因为其中一个地址将使我们到达 NOP 雪橇的起始位置,并一路滑落到我们的有效负载。

如果我们的 NOP sled 是 500 字节(假设我们的漏洞利用允许我们安装那么大的 NOP sled),则等式将是:

0x8000000 / 500 = 268435迭代找到 NOP 雪橇的起始地址。

这种方法对于 64 位系统不太适用的原因是以下等式:

2^32 / 256 = 16,777,216(我们的 NOP sled 可以从超过 1600 万个可能的地址开始!即使您的 NOP sled 是 500 字节并且除以 500,您仍然会有超过 850 万个可以开始 NOP sled 的地址!)

0000
0000
NNNN
NNNN
NNNN
PPPP
PPPP
PPPP
0000
0000
Run Code Online (Sandbox Code Playgroud)

如果你想象上面是我的堆栈,我的总内存大小为 40。我有一个 12 字节的 NOP sled(N)和一个 12 字节的有效负载(P)。所以我对这个可利用场景的方程式是:

40 / 12 = 3给我 3 个可能的地址,在尽可能少的尝试中可以找到我的 NOP sled(12、24、32 或十六进制 0x0c、0x18 和 0x20)。

因此,如果我的漏洞利用只是从堆栈的开头开始并以 12 为增量计数,那么它将在第一次尝试时找到我的 NOP sled(将 4 个字节放入我的 NOP sled)。

根据评论更新

NOP sled 背后关于地址随机化旁路技术的想法不是猜测NOP sled 的开始- 它是计算最少数量的地址 ,以保证您将通过尽可能少的地址猜测登陆到NOP sled 中/尽可能使用蛮力。当然,如果您想找到 NOP 雪橇的起点,您可以使用以下等式:

total_mem_size / NOP_size = least_amount_of_guesses_to_land_inside_payload + 1

但请记住,通过添加额外的地址来尝试,您不再计算在执行有效负载之前要猜测的最少地址量(这是我自己和您正在阅读的书正在计算的,因为这是使用NOP 雪橇)。

如果我们重新审视上面的小“堆栈”,NOP 雪橇可以启动的总地址确实可能有 4 个,但该方程计算出保证找到NOP 雪橇的 3 个地址(尽可能少的猜测是钥匙)。为了更清楚地说,您可以说漏洞开发人员将尝试通过增加 NOP 雪橇的大小(如果可能)来使这个数字尽可能小,这样他们就不会担心找到 NOP 雪橇的开始 -他们只想降落在 NOP 雪橇内。

索引的猜测12将使您将 4 个字节放入 NOP 雪橇中,从而在到达有效负载之前只需要执行 8 个 NOP。对索引的猜测24将使您进入有效负载中,从而导致崩溃,对索引的猜测32将使您超出有效负载,从而导致崩溃。

让我们使用您的方法(使用总共 4 个地址)来演示为什么等式中没有考虑额外的地址:

0000
0000
NNNN
NNNN
NNNN
PPPP
PPPP
PPPP
0000
0000
Run Code Online (Sandbox Code Playgroud)

让我们在方程中加 1,得到 4 个可能的地址,其堆栈布局与之前相同:

40 / 12 = 3 + 1 = 4

所以现在我们有 4 个地址可以暴力破解到我们的 NOP sled 中0, 12, 24, 32。因为我们有一个 12 字节的 NOP sled,所以仍然只有 1 个地址(索引 12 处的地址,其地址是原始方程找到的)将落在我们的 NOP sled 中,让我们在 shellcode 的开头开始执行 shellcode。索引 0 使我们在 NOP 雪橇之前无法控制的数据处进入堆栈。因此,在混合中添加 1 个地址并不能帮助我们找到 NOP 雪橇 - 它只会增加尝试/暴力/猜测的地址数量。

是的,你是对的 - 我只是递增地址,这对于示例来说更直观,以便更有意义,但在实际执行期间堆栈上的“计数”或“递增”地址将从高地址开始。