Last active
February 7, 2020 13:58
-
-
Save kivikakk/c510b82a6ad828c3c5d3 to your computer and use it in GitHub Desktop.
recover key from CodeIgniter homegrown crypto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# CodeIgniter pre-2.2 non-mcrypt Encrypt reverser. | |
# Finds the key by partially-known plaintext attack. | |
# Written by Ashe Connor. Placed in the public domain. | |
import codecs | |
import re | |
import sys | |
import time | |
def decode(s, key): | |
r = bytearray() | |
for i in range(len(s) // 2): | |
r.append(s[i*2] ^ s[i*2+1] ^ key[(i*2)%40] ^ key[(i*2+1)%40]) | |
return bytes(r) | |
def find_key(known, encrypted): | |
key = bytearray(b'0') * 40 | |
confirmed = [False] * 20 | |
hexstr = b'0123456789abcdef' | |
ix = 0 | |
while not all(confirmed): | |
if confirmed[ix%20]: | |
ix += 1 | |
continue | |
kcompb = known[ix::20] | |
for k in range(256): | |
key[(ix*2)%40] = hexstr[k&0xf] | |
key[(ix*2+1)%40] = hexstr[k>>4] | |
r = decode(encrypted, key) | |
kcomp = kcompb | |
rcomp = r[ix::20][:len(kcomp)] | |
while True: | |
try: | |
j = kcomp.index(b' ') | |
except ValueError: | |
break | |
kcomp = kcomp[:j] + kcomp[j+1:] | |
rcomp = rcomp[:j] + rcomp[j+1:] | |
if kcomp[0] == rcomp[0]: | |
confirmed[ix%20] = True | |
break | |
if not confirmed[ix%20]: | |
return None | |
ix += 1 | |
return key | |
with open(sys.argv[1], 'r') as f: | |
encrypted = f.read().split("\n", 2)[0] | |
encrypted = codecs.decode(encrypted.encode('ascii'), 'base64') | |
# Try each of these; space represents an unknown value. Here we account for | |
# the unknown size of the session array in general. We just need one byte of | |
# known plaintext for each index of the key, i.e. as long as there's at least | |
# one value in each 'column'. | |
knowns = ([ | |
b'a: :{s:10:"session_i' + | |
b'd";s:32:" ' | |
, | |
b'a: :{s:10:"session_' + | |
b'id";s:32:" ' | |
, | |
b'a: :{s:10:"session' + | |
b'_id";s:32:" ' | |
]) | |
key = None | |
for known in knowns: | |
key = find_key(known, encrypted) | |
if key: | |
break | |
if not key: | |
print("Could not recover key.") | |
exit(1) | |
print(key.decode('ascii')) | |
print(decode(encrypted, key)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment