这是我正在编译的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
仍然,结果是一样的。
此代码是narnia
对overthewire的战争游戏挑战的一部分。我设法在他们的远程shell上破解了这个挑战,它的行为符合预期。现在,我正在尝试在我的本地系统上重现同样的挑战并面对这个问题。请帮忙。
答案 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预留的。