前言
这个实验的示例2的代码没有给出,所以暂时没有做,如果以后要做的话会补上,包括GS保护部分也是如此
实验环境
由于实验需要有Windows和Ubuntu环境,所以我这里准备了两个环境。
- Windows:Visual Studio+Win10+IDA+Ollydbg+gcc
- Ubuntu:Ubuntu 18.04+Vmware+IDA
实验代码
示例一(用于Windows环境测试)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void function2() {
printf("Get Flags!");
}
void function1(char* str) {
char buffer[5];
strcpy(buffer, str);
}
int main(int argc, char* argv[]) {
function1(argv[1]);
printf("Wrong!");
}
示例2
实验过程
示例一
编译
这里我的建议是直接使用GCC编译器进行编译,我尝试过使用Visual Studio编译,但是编译效果不是很好。原因如下:
- Visual对未使用代码进行了优化,直接将Function的代码优化掉了
- GS保护是默认开启的
我尝试过将GS保护和优化选项去掉,但是并没有起到效果,为了方便起见还是直接使用GCC编译吧。GCC编译的命令如下
gcc -m32 -fno-stack-protector 源.cpp
其中参数作用为
- m32:强制gcc编译32位的可执行文件
- -fno-stack-protector:关闭GS保护机制
分析程序
打开我们的静态分析工具IDA,找到对应的function1的地址
这里尝试在不进行动态调试的情况下确认padding的大小。
通过反汇编看到的信息:
- 整个程序栈大小为0x28
- GCC编译程序将buffer局部变量分配在了EBP-0D的这个地方
- EBP下的4个字节储存返回地址(小端存放)
综合以上信息,可以画出栈的构造图
通过栈的保护机制可以知道。
padding的大小为:d+4=11H字节
所以整个payload的结构为:
按照这样的结构进行构造就可以劫持程序流程了,需要注意的有两个地方
- 像0x15这种字节是没办法通过键盘打出来的,解决办法是通过程序打印出来并进行复制。
- Function2这个地址是我自己本地编译出来的地址,不同的人可能不会一样。
尝试payload
我这里给出我自己的payload(0x21字符不在CSDN的字符集支持范围里面),不同的人有不同的答案,条条大路通罗马。
11111111111112222`0x21@
事实证明,我们的推测是正确的。