先决条件: GDB(分步介绍)
当将定义的变量内的内容复制到另一个变量而没有进行边界检查或考虑缓冲区的大小时,通常会发生BufferOverflow 。让我们使用每个Linux系统内置的帮助GNU调试器(GDB)分析缓冲区溢出。
此练习的目的是使自己熟悉调试代码并了解缓冲区溢出如何实际起作用。
#include
#include
#include
int main(int argc, char** argv)
{
volatile int cantoverflowme;
char buffer[64];
cantoverflowme = 0;
gets(buffer);
if (cantoverflowme != 0) {
printf("You OVERFLOW'ed Me\n");
}
else {
printf("Can't Overflow Me\n");
}
}
- 步骤1
让我们使用以下标志编译此代码:
gcc overflow.c -o overflow -fno-stack-protector -z execstack -no-pie
上面的代码将创建一个禁用各种堆栈保护的已编译二进制文件
-z execstack : Disables Executable Stack -fno-stack-protector : Disables Stack Canaries -no-pie : Disables Position Independent Executables
- 第2步
现在已禁用堆栈保护,我们可以通过键入以下内容将代码加载到GDB中:
gdb ./overflow
- 第三步
打开代码后,我们可以使用以下命令查看二进制文件中的函数
info functions
我们可以看到有一个正在使用的gets调用,它本质上很脆弱,因为它不执行任何绑定检查。
- 第四步
让我们输入
disas main
并分解主要函数
- 第5步
让我们输入一个断点
b * main+39
这样我们就可以在程序到达断点时分析堆栈的内容。
- 第6步
类型
r
从上面的代码中我们已经知道运行代码并输入任意数量的A。
让我们输入63 A和78 A并查看结果的变化。 - 步骤7
您可以在离开GDB后通过键入Python代码来打印A。
python -c "print 'A' * 63"
- 步骤8
现在我们有63个A,让我们运行代码,并在要求我们提供输入时将其粘贴。
让我们再次尝试整个过程,这次我们输入任意数量的A,例如78。
做到这一点的一种很酷的方法是
python -c "print 'A' * 78" | ./overflow
正如我们看到的那样,一旦溢出发生,它就会更改变量,因为内存在堆栈上泄漏并且更改了变量的值
- 步骤9
让我们检查一下它覆盖的堆栈,因此我们必须在以下位置设置一个断点
main+39
然后输入
r
然后我们可以输入
x/20s $rsp
x : eXamine 20s : 20 values in string $rsp : for register RSP (Stack Pointer)
因此,我们可以看到如何在堆栈上写入78个A,并使内存溢出。
想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。