nop sled空操作雪橇 CTFshow-pwn入门-pwn67

前言
本人由于今年考研可能更新的特别慢,不能把的pwn入门题目的wp一一都写出来了,时间比较紧啊,只能做高数做累的时候做做pwn写写wp了,当然我之后只挑典型意义的题目写wp了,其余的题目就留到12月底考完之后再写了…-_-…
pwn67(nop sled空操作雪橇)
首先我们先把pwn文件下载下来,托到虚拟机里加上可执行权限,使用命令查看一下文件的保护信息 。
chmod +x pwnchecksec pwn
我们可以看到这是一个32位的程序,并且开启了保护,但是呢没有开启NX和PIE,代表还是可以将我们的写到栈上去执行的 。
我们先将文件拖入IDA反编译一下 。得到的反汇编代码如下:
// main// bad sp value at call has been detected, the output may be wrong!int __cdecl main(int argc, const char **argv, const char **envp){char *position; // eaxvoid (*v5)(void); // [esp+0h] [ebp-1010h] BYREFunsigned int seed[1027]; // [esp+4h] [ebp-100Ch] BYREFseed[1025] = (unsigned int)&argc;seed[1024] = __readgsdword(0x14u);setbuf(stdout, 0);logo();srand((unsigned int)seed);Loading();acquire_satellites();position = query_position();printf("We need to load the ctfshow_flag.\nThe current location: %p\n", position);printf("What will you do?\n> ");fgets((char *)seed, 4096, stdin);printf("Where do you start?\n> ");__isoc99_scanf((int)"%p", (int)&v5);v5();return 0;}
// *query_positionchar *query_position(){char v1; // [esp+3h] [ebp-15h] BYREFint v2; // [esp+4h] [ebp-14h]char *v3; // [esp+8h] [ebp-10h]unsigned int v4; // [esp+Ch] [ebp-Ch]v4 = __readgsdword(0x14u);v2 = rand() % 1337 - 668;v3 = &v1 + v2;return &v1 + v2;}
代码的大概逻辑就是先输出一些信息,然后输出的会有栈中的地址,从函数可以发现函数返回值是v1的地址加上v2的值,而v1是局部变量,那么它的地址就是栈里的地址,加上v2就代表接收函数返回值的变量=v1的地址+v2的值(即&v1+v2) 。然后程序会让我们输入大小为4096的字符串给seed变量,之后再让我们输入一个地址,将其赋给v5,然后使用v5()从我们输入的这个地址执行这个地址的代码 。
由于开启了保护,我们的栈溢出就受到了阻碍,一般的保护开启,我们可以采用泄露的地址来打,但是本题目泄露了栈的地址,而且题目也提示我们是nop sled,所以我们就使用nop sled空操作雪橇来打 。
什么是nop sled
nop是一条不做任何操作的单指令,对应的十六进制编码为0x90 。这里nop将被用作欺骗因子 。通过创建一个大的NOP指令数组并将其放在之前,如果EIP返回到存储nop sled的任意地址,那么在达到之前,每执行一条nop指令,EIP都会递增 。这就是说只要返回地址被nop sled中的某一地址所重写,EIP就会将sled滑向将正常执行的 。
也就是我们现在栈中的某个位置填入大量nop指令,后边再接上我们的,然后我们控制程序的执行流从我们nop指令开始执行,那么程序就会一直执行我们之前填入的nop,执行nop之后就是我们的了,这样程序就成功的被我们pwn掉了 。
计算我们填入nop sled的位置
因为程序最后使用的是v5(),v5又是我们输入的地址,执行v5()就相当于从我们输入的地址开始执行 。
我们输入的nop指令+是通过gets函数放到了seed变量中,那我们输入的地址就必须在之前和第一个nop指令之后 。如果我们输入的数据放在了第一个nop指令之前,那我们就无法执行nop指令了;如果我们放在了之后,那执行的时候,就会从之后执行,这样就不能完整的执行整个 。
大致位置在哪已经清楚,那我们如何具体确定这个地址在哪呢?