Robots enjoy some strange games and we just can’t quite figure this one out. Maybe you will have better luck than us. 23.22.16.34:6969

The game offers a choice between two hex strings asking for the “bigger” one. Anyway, it doesn’t appear to be a way to determine which one is bigger just by looking at the values.

The challenge consists in winning at this game for 75 times in a row.

0 $ nc ec2-23-21-19-72.compute-1.amazonaws.com 6969
You have gotten 0 of 75
Choice 1 = 68af489d11366a85e755d95f516c48c50f
Choice 2 = 9795b347f0ceb9aa35f6127cdfb7145810
Which one is bigger? (1 or 2)
2
2
Correct!
--------------------
You have gotten 1 of 75
Choice 1 = 77c99d06baea4f703316e683a25264e3ba
Choice 2 = 2dcccbe6467658ed37b35167eb9f6e3318
Which one is bigger? (1 or 2)
1
1
Wrong :(

After several attempts, it’s possible to see some recurrent values. Indeed, it turns out to be a finite set of hex-encoded random 17-byte strings with a strict total ordering on them. We counted 500 different strings during our experiments.

The strategy for winning is to play while keeping track of the values and sorting them on a list. The following multithread script succeeded in winning for 75 times in a row in just 1 minute and 30 seconds performing a total of 13000 requests.

#!/usr/bin/python

import re
import sys
import time
import socket
import threading

strings_file = "/tmp/the_game_list.txt"

# order: small ----> big
strings = []
run = True
lock = threading.Lock()
flag = ""
requests = 0

def recv_tillreturn(sock, times=1):
"""Receive times lines of data from a socket"""

total_data = []
while times > 0:
times -= 1
data = ""
while 1:
char = sock.recv(1)
data += char
if char == "\n":
break
total_data.append(data)
return ''.join(total_data)

def insert(c1, c2):
"""Insert a pair of ordered value in the strings list, where c1 > c2."""
global strings

i_c1 = -1
i_c2 = -1
for i in range(len(strings)):
if strings[i] == c1:
i_c1 = i
if strings[i] == c2:
i_c2 = i
if i_c1 == i_c2 == -1:
# c1 and c2 not found: insert c2 in front of the list and append c1
strings.insert(0,c2)
strings.append(c1)
elif i_c1 != -1 and i_c2 == -1:
# c1 found but not c2: insert c2 just before c1
strings.insert(i_c1, c2)
elif i_c1 == -1 and i_c2 != -1:
# c2 found but not c1: insert c1 after c2
strings.insert(i_c2 + 1, c1)
else:
# both c1 and c2 found: if they are already ordered in the list leave
# them where they are, otherwise remove the old location of c1 and put
# c1 after c2
if i_c2 > i_c1:
strings.remove(c1)
strings.insert(i_c2, c1)

def isbigger(c1, c2):
"""Check whether c1 is bigger than c2."""

i_c1 = -1
i_c2 = -1
for i in range(len(strings)):
if strings[i] == c1:
i_c1 = i
if strings[i] == c2:
i_c2 = i
return i_c1 > i_c2

def play():
"""Play until victory."""

global run, requests, flag

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(3)
s.connect(("ec2-23-21-19-72.compute-1.amazonaws.com", 6969))
wins = 0

while run:
junk = recv_tillreturn(s, 1)
choices = range(2)
c1 = recv_tillreturn(s, 1)
c2 = recv_tillreturn(s, 1)
print("{}{}{}".format(junk, c1, c2))
c1 = c1.split()[3]
c2 = c2.split()[3]
with lock:
if isbigger(c1, c2):
guess = 1
else:
guess = 2
s.send("%s\n" % guess)
answer = recv_tillreturn(s, 4)
print(answer)
with lock:
requests += 1
if "Correct" in answer:
if guess == 1:
insert(c1, c2)
else:
insert(c2, c1)
wins += 1
else:
if guess == 1:
insert(c2, c1)
else:
insert(c1, c2)
wins = 0
if wins > 74:
run = False
flag = recv_tillreturn(s, 2)
s.close()

def main():
global strings, run

if len(sys.argv) < 2:
sys.stderr.write('Specify the number of threads\n')
sys.exit(1)

try:
f = open(strings_file, 'r')
strings = eval(f.read())
f.close()
except IOError:
strings = []

threads = []
for i in range(int(sys.argv[1])):
t = threading.Thread(target=play)
threads.append(t)
t.start()

main_thread = threading.currentThread()
for t in threading.enumerate():
if t is main_thread:
continue
t.join()

f = open(strings_file, "w")
f.write(str(strings))
f.close()
print("Flag: {}\nCompleted after {} requests.".format(flag, requests))

if __name__ == "__main__":
main()

Key: d03snt_3v3ry0n3_md5