Classic Game Theory
Category: Reverse Engineering, Crypto
So, in this challenge we are given a 16-BIT DOS Executable.
To run it, we can use DOSBox, with Debugging enabled.
A quick description of how the binary runs based on the disassembly.
-
It has a 672 chars of already calculated string to which our input is compared. All the chars are of the form [0-9aA-F] , so probably hex encoded bytes.
-
Our input is hashed.
-
The hash works as follows :
a. Two characters are taken from the input string. b. The two characters are passed to this
"hasher()"
(self renamed) function. c. The hasher function returns a 16-byte value, which is compared to precalculated values. d. Once the comparison is done, the next two characters are taken from the input string and the process is repeated. e. We need to get all characters correct.
Things we know :
-
The flag starts with
"ARC{"
-
We see
hasher("AR")
maps to"ca6e65703b22403198ffff22bc32e1ca"
-
On disassembling
"hasher()"
I found the two magic numbers0x67452301
and0xefcdab89
-
These values resemble the MD5 hashing function. But,
MD5("AR")
==5b61a1b298a0d06efa6933a97e68d763
So, after further reverse engineering,
MD5 has 4 words in it’s state.
In standard MD5, the state is initialized to the following values :
A = 0x67452301
B = 0xefcdab89
C = 0x98badcfe
D = 0x10325476
But, in our case, the state is initialized to the following values :
A = 0x67452301
B = 0xefcdab89
C = 0xabcdef00
D = 0x12345678
I used this MD5 library and modified the initial state as required to get the hash.
Next is a simple rainbow table attack, with rainbow tables generated using 2 character long strings.
input
has all the precalculated hashes from the binary.
from md5 import md5
input = []
with open("input") as f:
input = f.read().split('\n')
vals = ""
for line in input:
if line:
vals+=(chr(int(line.split('=')[-1][:-1],16)))
#print(vals)
vals = vals.lower()
hashes = []
for i in range(0,len(vals),32):
hashes.append(vals[i:i+32])
rainbow_table = {}
for i in range(0x00,0x7f):
for j in range(0x00,0x7f):
rainbow_table[md5(chr(i)+chr(j))] = chr(i)+chr(j)
for i in hashes:
try:
print(rainbow_table[i],end='')
except:
continue
Output :
┌──(greenpanda999㉿zacian)-[~/Desktop/Hax/game]
└─$ python3 solve.py
ARC{y0u_g0tt4_pl4y_the_l0ng_g4me}