Problem
Easy and Peasy
nc 35.200.197.38 8003
Europe: nc 35.205.196.143 8003
Like many of the EvlzCTF challenges, this one was a little light on detail, but good fun to complete.
Solution
Hitting the server from netcat gave me this:
$> nc 35.205.196.143 8003
Your Ciphertext is:1432243928350c2b280d04382b0029 Your key is:7375435858
Enter plaintext in hex:
Sadly I can’t XOR in my head, so I just mashed the keyboard and got:
Thanks for playing
This looks like a simple XOR with a fairly short key. Repeating the request a few times showed that the key and ciphertext length varied quite a bit, so a general purpose XOR decryptor was in order.
The usual telnetlib code does the work of connecting to the server and fetching the message:
import itertools
import re
import telnetlib
host = '35.205.196.143'
port = 8003
conn = telnetlib.Telnet(host, port)
while(1):
msg = conn.read_until("FooBar", 0.5)
A bit of regex does the work of breaking up the message.. We’re splitting on ‘:‘, space and newline to yield an array of the words. Slots 3 and 7 of the array contain the two hex strings and we can gather the data from them using bytearray.fromhex():
words = re.split("[ :\n]+", msg)
ct = bytearray.fromhex(words[3])
key = itertools.cycle(bytearray.fromhex(words[7]))
Because we’ve used the rather handy itertools.cycle(), each next() call will return a key byte, looping if required until we’ve processed all the bytes in the ciphertext:
retStr = ""
for b in ct:
x = b ^ key.next()
retStr += hex(x)[2:]
Then it’s just a case of dumping the result for debugging and sending the data back to the server:
print('Return string: ' + retStr)
conn.write(retStr+'\n')
That should do the trick. Right?
Your Ciphertext is:2f10100a212200103500 Your key is:4d63554d63576e76796f
Enter plaintext in hex:
Return string: 6273454742756e664c6f
Your Ciphertext is:0c243c0d1d3f1b1f380d Your key is:5569
Enter plaintext in hex:
Return string: 594d696448564e766d64
...
Some time later
...
Your Ciphertext is:2e0c0f0c151c000c201633013006 Your key is:6756754a6d7a536570524674
Enter plaintext in hex:
Return string: 495a7a4678665369504475755750
Thanks for playing
All the decrypts check out, where’s the flag?
I ran this a couple of times, the count of questions varied each time, but all the decrypts were good, we just weren’t getting a flag.
Then I remembered the tag line of the CTF from the Organisers: “The name is Evlz, come look for flags where you least expect to find them.”
A quick mod to the decrypt loop builds a regular version of the cleartext as well as the hex version:
retStr = ""
clearStr = ""
for b in ct:
x = b ^ key.next()
retStr += hex(x)[2:]
clearStr += chr(x)
print('Return string: ' + retStr)
print('Clear String: ' + clearStr)
conn.write(retStr+'\n')
Sure enough, the flag was hidden in the decrypt.
Your Ciphertext is:391e3e123736161c0e233c10 Your key is:4a644a45787a4c6b4c
Enter plaintext in hex:
Return string: 737a74574f4c5a774269585a
Clear String: sztWOLZwBiXZ
Your Ciphertext is:1f01160d0107161619121e28091817120d1f1f051f2808161413151a07140e11 Your key is:7a77
Enter plaintext in hex:
Return string: 65766c7a7b706c616365645f736f6d6577686572655f72616e646f6d7d637466
Clear String: evlz{placed_somewhere_random}ctf
Your Ciphertext is:2518193c1e391c14371d3a1a2138 Your key is:71
Enter plaintext in hex:
Return string: 5469684d6f486d65466c4b6b5049
Clear String: TihMoHmeFlKkPI