4

我目前正在阅读计算机系统简介:程序员的观点(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 sleds,但我无法理解书中给出的与 NOP sleds 相关的地址计算。我将在这里引用它:-

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

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

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

4

2 回答 2

2

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

计算2^15公式如下:

(8388608 / 256) = 32768 == 2^15

换句话说:

total_memory_size / NOP_sled_length = total_iterations_to_find_NOP_sled_in_memory

他们根据我们的 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

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

40 / 12 = 3给我 3 个可能的地址,我的 NOP 雪橇可以在尽可能少的尝试中找到(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 雪橇)。

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

索引的猜测12会将 4 个字节放入 NOP sled,在到达有效负载之前只给你 8 个 NOP 执行。对 index 的猜测24会让你进入有效负载的几个字节,导致崩溃,而对 index 的猜测32会让你越过有效负载,也会导致崩溃。

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

0000
0000
NNNN
NNNN
NNNN
PPPP
PPPP
PPPP
0000
0000

让我们将 1 添加到我们的等式中,为我们提供 4 个可能的地址,其堆栈布局与之前相同:

40 / 12 = 3 + 1 = 4

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

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

于 2015-01-25T21:49:13.423 回答
0

不确定这是否对您有帮助:

对于 32 位系统,如果您的 NOP 雪橇是 256 字节(即 2^8),并且如果您的堆栈的范围为 2^23 字节,则您只需要 2^15 个实例(即 2^23 / 2^8 = 2 ^15) 的(非重叠)雪橇。

对于 64 位系统也是如此

于 2015-01-19T06:12:12.310 回答