【问题标题】:Calculating addresses in NOP sleds在 NOP sled 中计算地址
【发布时间】:2015-01-12 02:34:14
【问题描述】:

我目前正在阅读计算机系统简介:程序员的观点 (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 的?一个解释会很有帮助。

【问题讨论】:

  • 啊!赏金将在 5 小时后到期! :D 请检查我的回答,看看它是否对你有帮助。

标签: buffer-overflow aslr nop


【解决方案1】:

他们只是假设 32 位系统上的最大总共享内存 (kbytes) 为 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 sled 的开始处着陆,并一直向下滑动到我们的有效负载。

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

0x8000000 / 500 = 268435 迭代以找到我们的 NOP sled 的起始地址。

这种方法对于 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)。

基于 cmets 的更新

就地址随机化的绕过技术而言,NOP sled 背后的想法不是猜测 NOP sled 的开始 - 它是计算最少数量的地址 这将保证您将降落在您的 NOP 雪橇内,并且使用尽可能少的地址猜测/蛮力。当然,如果您想找到 NOP 雪橇的开头,您可以使用以下等式:

total_mem_size / NOP_size = least_amount_of_guesses_to_land_inside_payload + 1

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

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

索引12 的猜测会将 4 个字节放入 NOP sled,从而在到达有效负载之前只执行 8 个 NOP。对索引24 的猜测将使您进入有效负载的几个字节,从而导致崩溃,而对索引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 雪橇——它只会增加尝试/蛮力/猜测的地址数量。

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

【讨论】:

  • 感谢您的回答。在我希望将此标记为答案之前,我有一些疑问。最后,您说 NOP 雪橇可以从 12、24 和 32 开始,但我认为它也可以从 0 开始。所以在这种情况下,我将有 4 个可能的地址,0、12、24 和 32?另外,最后一行我不清楚你在哪里说“利用”代码是否从开头开始并以 12 为增量计数。开始是指高地址(靠近堆栈顶部)或某个低地址堆栈?
  • 我已更新我的答案以解决您的 cmets。书中的公式和我解释的公式没有计算 4 个地址的原因是因为它计算了 最少 个地址来尝试,这将保证登陆 NOP 雪橇。使用 NOP sled 绕过堆栈地址随机化的整个想法是使您控制的数据更大,以便您的数据可以在内存中的地址更少。当您有数万或数百万个地址要进行暴力破解时,您只需关心最少的猜测即可获得代码执行。
【解决方案2】:

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

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

同样适用于 64 位系统

【讨论】:

  • 为什么我们必须将这两个数字相除而不是相减?
  • 假设您的堆栈任意从地址 0x0000 开始,则起始地址的枚举将从 0x0000 开始,然后是 0x0100,然后是 0x0200,依此类推。以这种方式获得 NOP 雪橇的数量是一个除法运算。对于减法,就像将雪橇放置在 0x0000,然后在 0x0001,然后在 0x0002 等等。这是低效的,因为您的雪橇是 256 字节。我希望我能正确理解你的问题..
猜你喜欢
  • 2013-11-27
  • 1970-01-01
  • 2021-05-21
  • 2015-08-19
  • 2019-06-01
  • 2014-03-24
  • 2012-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多