因此,我使用以下代码遵循tutorial关于缓冲区溢出的信息:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
然后我用gcc对其进行编译,并事先运行sudo sysctl -w kernel.randomize_va_space=0
以防止出现随机内存并允许堆栈粉碎(缓冲区溢出)漏洞利用
gcc protostar.c -g -z execstack -fno-stack-protector -o protostar
-g允许在gdb('list main')中进行调试
-z execstack -fno-stack-protector删除堆栈保护
然后执行它:
python -c 'print "A"*76' | ./protostar
再试一次?
python -c 'print "A"*77' | ./protostar
您已更改“修改”变量
所以我不明白为什么缓冲区溢出会在77应该是65的情况下以77发生,所以它会产生12位的差异(3个字节)。我想知道为什么有人能给出清楚的解释吗?
从77到87仍然如此:
python -c 'print "A"*87' | ./protostar
you have changed the 'modified' variable
从88开始,它增加了段错误:
python -c 'print "A"*88' | ./protostar
you have changed the 'modified' variable
Segmentation fault (core dumped)
致谢
答案 0 :(得分:1)
要完全了解正在发生的事情,首先要注意程序是如何布局内存的。
根据您的评论,对于此特定运行,buffer
的存储从0x7fffffffdf10
开始,然后modified
的存储从0x7fffffffdf5c
开始(尽管randomize_va_space
可能会在每次运行中保持一致,但我不确定)。
所以你有这样的东西:
0x7fffffffdf10 0x7fffffffdf50 0x7fffffffdf5c
↓ ↓ ↓
(64 byte buffer)..........(some 12 bytes).....(modified)....
基本上,您有64个字符的缓冲区,然后在结束时,有12个字节用于其他堆栈变量(可能是4个字节argc
和8个字节用于argv
),然后修改后,缓冲区开始后精确地开始64 + 12 = 76个字节。
因此,当您在65到76个字符之间写入64字节缓冲区时,它会越过并开始写入缓冲区和modified
之间的那12个字节。当您开始编写第77个字符时,它将开始覆盖modified
中的内容,这会导致您看到“ you have changed the 'modified' variable
”消息。
您还问“如果我升至87,然后在88时出现段错误,为什么会起作用?答案是因为这是未定义的行为,因此,一旦您开始写入无效的内存并且内核能够识别它,它就会会立即终止您的进程,因为您尝试读取/写入您无权访问的内存。
请注意,在实践中几乎应该永远不要使用gets
,这是一个很大的原因,因为您不知道要读取多少字节,因此有机会覆盖。还要注意,您看到的行为与运行机器时在计算机上看到的行为不同。这是正常现象,因为这是未定义的行为。无法保证运行时会发生什么。在我的计算机上,modified
实际上在内存中buffer
之前,因此我从未见过modified
变量被覆盖。我认为这是一个很好的学习示例,可以理解为什么这样的未定义行为是如此不可预测。