codezen.frcode hacking, zen coding

30Apr/12Off

PlaidCTF 2012 – Potpourri 100 – The Game Writeup

Posted by aXs

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

We have a game running on that port:

You have gotten 0 of 75
Choice 1 = 98d00c65d341be04600f915b32c01c81ab
Choice 2 = 7a859a01731c050797ac952d82b895882a
Which one is bigger? (1 or 2)
1
1
Correct!
--------------------
You have gotten 1 of 75
Choice 1 = d6e4fbe0e4cd99e8fac2b40fbaa80ea8b0
Choice 2 = 9535d4c5a1a007f302c3f2cc6d1733989f
Which one is bigger? (1 or 2)
1
1
Wrong 🙁

As you can see, "bigger" is not related to the number expressed in hexadecimal has being really greater than the other. We tried many different things to try to find a relation (modulo, adding the digits, ...) ... until I starred for a few minutes at our script that was playing the game in a loop and noticed the hashes were coming back.. it wasn't random numbers!

My first approach was to "learn" all the possible round. If a similar round comes back, we know the answer. I noticed that if we know only one of the number, if this number has won before, there is a slightly (slightly!) chance that it will won this match again. This approach kinds of worked but was very slow.. after 6 hours of learning, we weren't going higher than ~30-40 winning round in a row.

The next approach was to consider this challenge as a bubble sort: we will maintain an ordered list of the numbers and swap them around depend of which is considered bigger, basically using the service as an oracle.

This version worked much better and can solve The Game in around ~30 minutes.

I'm still learning Python so this isn't anything Im proud of on the point of view of the Python style of whatever 🙂

#!/usr/bin/env python
# -*- coding: latin-1 -*-

import socket
import sys
import re

if len(sys.argv) != 3:
print '\nUsage:\t./bigger.py [host] [port]'
sys.exit(1)

host = sys.argv
port = int(sys.argv)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))

fs=s.makefile()

regex = re.compile(".*= (.*)")

matchs = {}
winner = []
numbers = []

while 1:
print welcome

if welcome == 'Yay you have won!\n':
while 1:
if not line:
break
s.close()
exit(1)

r = regex.search(choice1)
choice1 = r.groups()
num1 = int(choice1,16)

r = regex.search(choice2)
choice2 = r.groups()
num2 = int(choice2, 16)

print 'Choice 1', choice1, 'Choice 2', choice2

key1 = choice1 + choice2
key2 = choice2 + choice1

if key1 in matchs:
choice = matchs[key1]
print 'Send', choice, 'because previous match result'
s.send('%d\n' %choice)
predicted = 'previous'
elif key2 in matchs:
choice = matchs[key2]
print 'Send', choice, 'because previous match result'
s.send('%d\n' %choice)
predicted = 'previous'
else:
if choice1 in numbers and choice2 in numbers:
if numbers.index(choice1) < numbers.index(choice2):
print 'Send 1 because lower index'
s.send('1\n')
predicted = 1
unpredicted = 2
candidate = choice1
notcandidate = choice2
else:
print 'Send 2 because lower index'
s.send('2\n')
predicted = 2
unpredicted = 1
candidate = choice2
notcandidate = choice1
elif choice1 in winner:
print 'Send 1 because previous winner'
s.send('1\n')
predicted = 1
unpredicted = 2
candidate = choice1
notcandidate = choice2
elif choice2 in winner:
print 'Send 2 because previous winner'
s.send('2\n')
predicted = 2
unpredicted = 1
candidate = choice2
notcandidate = choice1
else:
print 'Send 1 because arbitrary'
s.send('1\n')
predicted = 1
unpredicted = 2
candidate = choice1
notcandidate = choice2

print 'Result', result

if result == 'Correct!\n':
if predicted != 'previous':
matchs[key1] = predicted
matchs[key2] = unpredicted
winner.append(candidate)
else:
matchs[key1] = unpredicted
matchs[key2] = predicted
winner.append(notcandidate)
if candidate in numbers:
if notcandidate in numbers:
i = numbers.index(candidate)
j = numbers.index(notcandidate)
numbers[i], numbers[j] = numbers[j], numbers[i]
else:
numbers.append(notcandidate)
else:
numbers.append(candidate)

while 1:
line = s.recv(4096)
if not line:
break

s.close()

After around 30 minutes...

You have gotten 73 of 75

Choice 1 0872b5c42221f31ffadb08e634ab8e5ab6 Choice 2 41b9ffcabc545e4b71b5d9ce1399a145e0
Send 1 because lower index
Result Correct!

You have gotten 74 of 75

Choice 1 dee427827d0b8b54f9545f6e0073c7195f Choice 2 0285648f245ad5c9074defa6800f2b229b
Send 1 because lower index
Result Correct!

Yay you have won!

The key is: d03snt_3v3ry0n3_md5'