Ultra baby(pwn, 25 points)
"Reach the flag function!"
nc 9a958a70ea8697789e52027dc12d7fe98cad7833.ctf.site 55000
By reversing the binary in IDA, we can see a buffer being allocated 0x20 (26 bytes), and the pointer for the function lies 8 bytes below the frame pointer. Because we can read 0x19 (25 bytes), we can actually partially overwrite the least significant bit of the function pointer. This is helpful because there are two functions of interest, "Bye" and "Flag". Because they are so close together in memory, their addresses will be extraordinarily similar with the exception of the lowest bit which we can manipulate.
From gdb we can use "print Bye" and "print Flag" and it'll prove our theory.
The only difference in the address between "Bye()" and "Flag()" is 0xE0 is rather 0xF3. This means that if we write the 25th byte to 0xF3 rather than the normal 0xE0, we'll modify the function pointer. Later in execution when the function pointer is called, it'll jump to where we want (which is Flag()) rather than where it's supposed to go, which is Bye(). Now of course this will work on our local version but we won't get a flag because we don't have it, however this very binary is running as a service on a host and port they provide, so if we apply this solution to that service we'll get the flag in stdout. I decided to use a combination of Python and sockets. And yes I use python 2.7 not python 3, if you don't like it sorry.
if __name__ == "__main__": s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Send our stuff for x in range(0, 3): s.send("A"*24 + "\xf3")
# Is our flag here? for x in range(0, 3): print s.recv(1024)
The only reason I made them run in a for loop is to ensure our packet got sent and we received the flag, as just running it once without the loop would sometimes fail. It's quick and dirty and by no means pretty.