In this challenge we get a Win32 console binary which just display garbage when started.
Reversing it with IDA, we see it connects to a TCP server.
I had noticed previously that the file being transfered in the Epic Arc 200 challenge was an Erlang BEAM file (compiled erlang)
This BEAM file was a TCP server. You guessed it, this is the server part for this ctf.exe, but not quite exactly the same server that on the challenge box. I will spare you the Erlang disassembly, it’s not really interesting. You can obtain it with erts_debug:df(Module).
We can still reverse enough from this BEAM file to understand what the server is doing and the client is doing in reply.
What the server part will do:
– Send a banner (17 bytes)
– Send a session key (8 bytes)
– Send a CRLF (2 bytes)
– Send “IV” (4 random bytes)
– Wait for our handshake
– Reply in an encrypted form with an error message or the flag if your handshake is correct
A correct handshake needs to be:
– “FlagRequest:omkesey” + IV + “\n\r” (this string can be found in CTF.exe)
– XOR encrypted with “_hackme_” itself XORed with the session key sends by the server
To decrypt the server reply, you use this same XOR key.
host = sys.argv
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
banner = s.recv(17) # banner
print "banner=", repr(banner)
key = s.recv(8)
print "key=", key.encode("hex"), "len=", len(key)
hackme = "_hackme_"
key2 = ''
i = 0
while i < 8:
key2 = key2 + chr(ord(key[i]) ^ ord(hackme[i]))
i = i +1
print "key2=", key2.encode("hex")
key = key2
crlf = s.recv(2) # \n\r
print "CRLF=", repr(crlf)
iv = s.recv(4) # random bytes
print "IV=", iv.encode("hex")
request = "FlagRequest:omkesey" + iv + "\n\r"
print "request=", repr(request), "len=", len(request)
handshake = ''
for i in xrange(0, len(request)):
handshake = handshake + chr(ord(request[i]) ^ ord(key[i % 8]))
print "handshake=", repr(handshake), "len=", len(handshake)
print "handshake=", handshake.encode("hex")
reply = s.recv(128)
print "Raw=", repr(reply)
print "Raw=", reply.encode("hex")
message = ''
for i in xrange(0, len(reply)):
message = message + chr(ord(reply[i]) ^ ord(key[i % len(key)]))
print "message=", repr(message)
print "message=", message.encode("hex")