2

所以我有这个功能:

void print_usage(char* arg) 
{
    char buffer[640];
sprintf(buffer, "Usage: %s [options]\n"
        "Randomly generates a password, optionally writes it to /etc/shadow\n"
        "\n"
        "Options:\n"
        "-s, --salt <salt>  Specify custom salt, default is random\n"
        "-e, --seed [file]  Specify custom seed from file, default is from stdin\n"
        "-t, --type <type>  Specify different encryption method\n"
        "-v, --version      Show version\n"
        "-h, --help     Show this usage message\n"
        "\n"
        "Encryption types:\n"
        "   0 - DES (default)\n"
        "   1 - MD5\n"
        "   2 - Blowfish\n"
        "   3 - SHA-256\n"
        "   4 - SHA-512\n", arg);
    printf(buffer);
}

我希望利用格式字符串漏洞攻击(我的作业)。这是我的尝试:

我有一个漏洞利用程序,它用 noops 和 shell 代码填充缓冲区(我已经使用这个程序来缓冲溢出相同的函数,所以我知道它很好)。现在,我对文件进行了对象转储以找到 .dtors_list 地址,得到 0x0804a20c,添加 4 个字节得到 0x804a210。

接下来,我使用 gdb 在运行程序时查找我的 noops 开始的地址。使用它我得到了 0xffbfdbb8。

所以到目前为止,我觉得我是对的,现在我知道我想使用格式字符串将 noop 地址复制到我的 .dtors_end 地址中。这是我想出的字符串(这是我作为用户输入提供给函数的字符串):

"\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%%.168u%%1$n%%.51u%%2$ n%%.228u%%3$n%%.64u%%4$n"

这对我不起作用。程序正常运行,%s 被我输入的字符串替换(减去前面的小端内存地址,由于某种原因,两个百分号现在变成了一个百分号)。

无论如何,我在这里有点难过,任何帮助将不胜感激。

4

1 回答 1

0

免责声明:我不是专家。

你传递"\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%%.168u%%1$n%%.51u%%2$n%%.228u%%3$n%%.64u%%4$n"的价值是arg? 这意味着buffer将包含

"Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%.168u%1$n%.51u%2$n%.228u%3$n%.64u%4$n [options]\x0aRandomly..."

现在让我们进一步假设您在 x86-32 目标上(如果您在 x86-64 上,这将不起作用),并且您正在使用不会在print_usage's中添加任何内容的优化级别进行编译堆栈帧,640 字节buffer数组除外。

然后printf(buffer)将按顺序执行以下操作:

  • 压入 4 字节地址&buffer
  • 推送一个 4 字节的返回地址。
  • 调用printf...
  • 打印出来"Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08"(23 个字节的序列)。
  • %.168u: 将下一个参数解释printf为无符号整数并将其打印在宽度为 168 的字段中。由于printf没有下一个参数,这实际上是在堆栈上打印下一个东西;即 ; 的前四个buffer字节 即"Usag"( 0x67617355)。
  • %1$n: 将第二个参数解释printf为指向 int 的指针并将 23+168 存储在该位置。这家店0x000000bf的位置0x67617355。所以这是你的主要问题:你应该使用%2$n而不是%1$n在你的arg. (顺便说一句,请注意 GNU 说“如果任何格式都有参数位置的规范,那么格式字符串中的所有格式字符串都应该有一个。否则行为是未定义的。”所以你应该通过并将1$s 添加到你的所有%us只是为了安全起见。)
  • %.51u: 打印另外 51 个字节的垃圾。
  • %2$n:将第三个参数解释printf为指向 int 的指针并存储0x000000f2在该垃圾位置。如上所述,这应该是%3$n.
  • ……等等……等等……

因此,您的主要错误是您忘记考虑"Usage: "前缀。

我假设您试图将四个字节存储0xffbfdbb8到 address0x804a210中。假设你已经让它工作了。但是你的下一步是什么?您如何让程序将四字节数量0x804a210视为函数指针并跳过它?

利用此代码的传统方法是利用缓冲区溢出sprintf,而不是更复杂的"%n"漏洞printf。您只需要使您的arg大约 640 个字符长,并确保它对应于print_usage的返回地址的 4 个字节包含您的 NOP 雪橇的地址。

不过,即使部分也很棘手。您可能会遇到与ASLR相关的问题:仅仅因为您的雪橇0xffbfdbb8在一次运行中存在于地址并不意味着它会在下一次运行中存在于同一地址。

这有帮助吗?

于 2013-06-20T23:29:33.593 回答