承蒙前来宣讲前辈们的指引和各种震天响的牛逼,决定接下来一段时间把CTF一搞起。
然后百度了下各个方向,打算直接搞pwn(听说搞过ACM的上手会快一点?),环境弄好后开始上手,研究一下pwn要怎么搞。
First step
栈溢出原理从入门到放弃
参考资料:www.blog.csdn.net/DRondong/article/details/94500556
简单尝试了一个栈溢出原理:
#include<stdio.h> int fun1() { int a; gets((char *)&a); return 0; } int fun2() { printf("stackflow success!\n"); return 0; } int main(int argc, char *argv[]) { fun1(); return 0; }
我们向栈中写入了超出限定长度的数据,溢出的数据会覆盖栈中其它数据,从而影响程序的运行。
所以,如果我们计算好溢出的长度,编写好溢出数据,让我们想要的地址数据正好覆盖到函数返回地址,那么被调函数调用完返回主函数时,就会跳转到我们覆盖的地址上。
gets()它不进行边界检查,我们可以利用它达成目的。在我们的例子中,a是int型只有4字节大小的空间,所以当输入的字符大于4字节时,就会发生溢出。而我们的目标就是,让我们的溢出数据覆盖fun1函数的返回地址,具体就是覆盖为fun2函数的地址,使程序的流程跳转到fun2函数去执行。
按照上链的方法,用gcc对这段代码进行编译:
gcc -z execstack -fno-stack-protector -o stackflow-example ./stackflow-example.c
(其中-z execstack开启堆栈可执行机制,-fno-stack-protector关闭堆栈保护机制)
用gdb进行调试,可以直接在gets()函数下断点,也可以使用next、step指令快速调试到gets()函数这,在输入AAA后,查看堆栈数据。
在执行完gets()函数并输入AAA后,程序的栈分布情况如下所示,0x00007fffffffe110即是上一函数(调用者main函数)的ebp,0x4005b4是fun1函数的返回地址。
在输入AAAAA后呢,溢出的数据就会存在0x00007fffffffe0f0开始的栈上
所以,我们只需要输入AAAA+AAAAAAAA(覆盖上一函数ebp)+fun2地址(覆盖返回地址),就可以达到我们的目标。
(开启了新世界的大门)
静待更新。。。。。。