为什么缓冲区不会溢出这段代码?

时间:2017-04-12 09:56:00

标签: c gcc buffer-overflow

这是我正在编译的C代码:

#include <stdio.h>
#include <stdlib.h>

int main(){
long val=0x41414141;
char buf[20];

printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n");
printf("Here is your chance: ");
scanf("%24s",&buf);

printf("buf: %s\n",buf);
printf("val: 0x%08x\n",val);

if(val==0xdeadbeef)
system("/bin/sh");
else {
printf("WAY OFF!!!!\n");
exit(1);
}

return 0;
}

在这里,如果用户输入字符串24个字符长,我希望long val中出现溢出,从而更改val中的值。但即使字符串足够长,它也不会溢出。有人可以解释一下这种行为吗?

我在macOS上。这就是gcc -v吐出的内容:

Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/c++/4.2.1
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.0.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

此外,在谷歌搜索后我尝试使用这些标志gcc:

gcc -g -fno-stack-protector -D_FORTIFY_SOURCE=0 -o overflow_example overflow_example.c

仍然,结果是一样的。

此代码是narniaoverthewire的战争游戏挑战的一部分。我设法在他们的远程shell上破解了这个挑战,它的行为符合预期。现在,我正在尝试在我的本地系统上重现同样的挑战并面对这个问题。请帮忙。

编辑:对于所有关于UB大喊大叫的人:就像我说的那样,这是overthewire要解决的挑战之一,所以它不能拥有UB。有一些博客(here's on I found)提供了针对此挑战的演练,并为为什么代码的行为方式提供了合理的逻辑解释,我同意这一点。我也明白编译的二进制文件是依赖于平台的。 那么,我该怎么做才能在我的本地系统上产生潜在溢出的二进制文件?

3 个答案:

答案 0 :(得分:3)

未定义的行为,因为C函数不检查参数是否对其缓冲区来说太大。

答案 1 :(得分:2)

显然,变量在mac上的堆栈上的布局不同。

将它们包装在结构中将确保它们按您想要的顺序放置。

由于存在填充的可能性,因此请将其关闭。对于gcc,预编译器directe #pragma pack控制struct packing。

int main(){
#pragma pack(1)
  struct {
    char buf[20];
    long val=0x41414141;
  } s;
#pragma pack()
  printf("Correct val's value from 0x41414141 -> 0xdeadbeef!\n");
  printf("Here is your chance: ");
  scanf("%24s",&s.buf);

  printf("buf: %s\n",s.buf);
  printf("val: 0x%08x\n",s.val);

  if(s.val==0xdeadbeef)
    system("/bin/sh");
  else {
    printf("WAY OFF!!!!\n");
    exit(1);
  }

  return 0;
}

答案 2 :(得分:0)

我不确定你的意思。

1)您是否担心输入字符串会创建一个太大而无法存储的数字。这不会发生,数字将简单地包裹。 2)你是否担心自己会读到超出buf界限的内存?在C中,这将产生未定义的行为,不一定是崩溃。

buf在堆栈上(可能在堆上也一样)所以你可以继续从buf开始的地址写入内存。编译器将生成不会为您执行边界检查的代码。因此,如果你超越20字节,你最终会开始覆盖不属于内存块的其他内存部分,而这些部分是你为buf预留的。

相关问题