HXP CTF 2017 - ouchenticated (Crypto 200)
''' | |
CRC is applied before CTR so CTR is not protected and we can bitflip. | |
We can fix MAC randomly and save the difference between admin=0 and admin=1. | |
Since CRC is linear, the same difference will work for any other MAC. | |
''' | |
from sock import Sock | |
def xor(a, b): return "".join([chr(ord(a[i]) ^ ord(b[i % len(b)])) for i in xrange(len(a))]) | |
mac_key = os.urandom(0x10) | |
c1 = authenc(json.dumps({'admin': 0})) | |
c2 = authenc(json.dumps({'admin': 1})) | |
delta = xor(c1, c2) | |
f = Sock("35.198.105.111 32773") | |
ct = f.read_line().strip().decode("hex") | |
ct = xor(ct, delta) | |
f.send_line(ct.encode("hex")) | |
f.interact() | |
# hxp{CRC:_c0mpL3t3ly_r3duNd4nT_crYpT0gr4pH1c4LLy} |
#!/usr/bin/env python3 | |
from Crypto.Cipher import AES | |
from Crypto.Util import Counter | |
import os, binascii, struct, zlib, json | |
enc_key = os.urandom(0x10) | |
mac_key = os.urandom(0x10) | |
def crc(bs): | |
return 0xffffffff ^ zlib.crc32(bs) | |
def authenc(m): | |
s = m + mac_key | |
s = s + struct.pack('<L', crc(s)) | |
print(repr(s)) | |
assert not crc(s) | |
aes = AES.new(enc_key, AES.MODE_CTR, counter = Counter.new(128)) | |
return aes.encrypt(s) | |
def authdec(c): | |
aes = AES.new(enc_key, AES.MODE_CTR, counter = Counter.new(128)) | |
s = aes.decrypt(c) | |
assert not crc(s) | |
assert s[-4-16:-4] == mac_key | |
return s[:-4-16] | |
cipher = authenc(json.dumps({'admin': 0}).encode()) | |
print(binascii.hexlify(cipher).decode()) | |
cipher = binascii.unhexlify(input().strip()) | |
obj = json.loads(authdec(cipher).decode()) | |
if obj['admin']: | |
print('The flag is: {}'.format(open('flag.txt').read().strip())) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment