栈溢出基础
三个重要的寄存器
- EBP : 用来存储当前函数状态的基地址, 在函数运行时不变, 可以用来索引确定函数参数或局部变量的位置
- ESP : 用来存储函数调用栈的栈顶地址, 在压栈和退栈时发生变化
- EIP : 用来存储即将执行的程序指令的地址, cpu 依照 EIP 的存储内容读取指令并执行, EIP 随之指向相邻的下一条指令
栈溢出原理
栈溢出指的是程序向栈中某个变量中写入的字节数超过了这个变量本身所申请的字节数,因而导致与其相邻的栈中的变量的值被改变
用一张图概括就是
简单的例子
篡改返回地址为目的函数地址即可。
实践
1 |
|
上面这样一个c语言程序,success就是一个后门函数,我们通过栈溢出篡改返回地址为success。
编译一下
1 | gcc -m32 -fno-stack-protector -no-pie hello.c -o hello |
其中-m32
是生成32位程序,-fno-stack-protector
是不开启堆栈溢出的保护(不生成canary)-no-pie
是关闭PIE。
没有canary和pie,开启了NX,NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。
放IDA调试
看存在溢出的vulnerable函数,双击s
所以s字符串离当前的栈底有20个字节的距离。
success函数地址为804846B
我们利用gets溢出覆盖返回地址位success地址即可getshell
思路:先用20个字符填满s到ebp之间的内容,然后是4字节ebp的内容。
写EXP
1 | from pwn import * |