【问题标题】:Example of Buffer Overflow?缓冲区溢出示例?
【发布时间】:2021-09-16 14:11:25
【问题描述】:

我正在阅读我的书中有关缓冲区溢出的内容并看到:

字符串加载到内存的顺序是否正确?在 little endian 中,我读到我们在较低地址的较低索引处加载位,但此示例显示相反。

现在给出这段代码:

如何将 auth_flag 设置为 1? ascii 值为 1 的字符串不可打印,因此这似乎无法利用,对吗?

【问题讨论】:

  • 任何非零值都被解释为true,因此您实际上不需要将auth_flag 设置为1。任何非零值都可以。更大的问题是auth_flag 可以存储为寄存器值,也可以在缓冲区之前存储在内存中,因此超出缓冲区不一定会影响auth_flag。
  • 字节序不适用于字符串
  • 您是否尝试在关闭优化的情况下进行编译并输入一个 17 字符的密码,例如“slithy toves mome”?使用调试器查看地址和值。
  • @user3386109 如果我想要 1 怎么办?
  • 能否将 ASCII 字符 0x01 通过终端,通过 shell,进入argv,这是值得怀疑的。

标签: c memory buffer endianness buffer-overflow


【解决方案1】:

代码示例 1:

在 little endian 中,我读到我们在较低地址中加载较低索引的位,但此示例显示相反。

当使用简单的 C 风格字符串时,字节序不适用。 Endianess 与多字节值相关,但与 char 值无关。

代码示例 2:

ascii 值为 1 的字符串不可打印,所以这似乎无法利用,对吗?

不,你在这里有一个基本的误解。您不需要将数值 1 放入 auth_flag。您只需要一个非零值。

记住

if (check_authentication(argv[1])) {

真的

if (check_authentication(argv[1]) != 0) {
                                  ^^^^

因此,对于任何非零返回值,if 条件都将为真。

为了打破身份验证检查,编译器将auth_flag 放置在内存中的某个位置之后 password_buffer。在这种情况下,您可以为程序提供一个长度超过 16 个字符的起始参数,这样多余的字符就会溢出缓冲区并在 auth_flag 的位置结束。

这是对您的代码的重写。原理是一样的。我只是使用了较短的名称并删除了一些(不必要的)代码以使示例变得简单。我还打印了变量的位置。

int ca(char* pw)
{
    int af = 0;
    char pw_b[16];
    printf("af   location: %p\n", (void*)&af);
    printf("pw_b location: %p\n", (void*)pw_b);

    strcpy(pw_b, pw);
    return af;
}

int main(int argc, char *argv[])
{
  if (argc < 2)
  {
      printf("wrong usage\n");
      return 0;
  }
  if (ca(argv[1]))
  {
      printf("Did it...\n");
  }
  else
  {
      printf("Failed to break in\n");
  }
  return 0;
}

使用 gcc -O0 编译时,我会在像 ./prog abc 这样开始时得到这个输出

af   location: 0x7ffd579e13cc
pw_b location: 0x7ffd579e13b0
Failed to break in

从这里我可以看到af 位于 0x1c 字节(或十进制 28)之后 pw_b。所以如果我给程序一个超过 28 个字符的参数,它可能会覆盖af(如果它没有因为其他原因崩溃......)。

所以我尝试了./prog 1234567890123456789012345678b(注意字符串中有 29 个字符),我得到了:

af   location: 0x7ffc63312f8c
pw_b location: 0x7ffc63312f70
Did it...

所以我成功了...我确实破解了身份验证检查代码。

但请注意...在另一个系统上,使用另一个编译器,使用其他编译器选项等,情况可能会有所不同。所以你不能确定在你的系统上重现这个。也许您需要不同的输入,也许在您的系统上甚至不可能。首先检查变量的位置,然后计算所需的输入。

【讨论】:

  • Q1) 关于答案的第一部分(第 1 部分),字符也是字节。还是没听懂
  • Q2) 关于 2,如果我真的希望 auth_flag 保持值 1 我该怎么做或者不可能?请联系所有问题,提前致谢
  • @Daniel Re Q2:所有普通字符都有十进制值,如使用的 ascii 表中定义的那样。所以你不能使用普通字符。但是,可以在命令行中使用一些转义序列来输入十进制值 1。通常以 ` (e.g. \01` 开头),但这可能取决于您的 shell。所以我无法回答。
  • @Daniel Re Q1:一个字符串保存在内存中,第一个字符在最低地址。总是......所以字节序与字符串无关。
  • @Daniel “我知道,但字符仍然是十进制......” 是的,但没有字节可以交换,所以字符没有字节序
猜你喜欢
  • 1970-01-01
  • 2017-04-08
  • 2012-01-31
  • 2019-04-17
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
  • 2010-11-11
相关资源
最近更新 更多