[BSidesSF2020]haystack
附件 # uncompyle6 version 3.2.4 # Python bytecode 3.7 (3394) # Decompiled from: Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)] # Embedded file name: /home/david/Projects/BSidesCTF/2020/challenges/haystack/challenge/chaffing.py # Size of source mod 2**32: 2094 bytes import hmac, hashlib, random, struct CHAFF_SIZE = 32 SIG_SIZE = 16 ALL_BYTES = set((c for c in range(256))) KEY = b'af5f76f605a700ae8c0895c3e6175909' def byte(v): return bytes([v]) def sign_byte(val, key): return (hmac.new(key, val, digestmod=hashlib.sha256)).digest()[:SIG_SIZE] def chaff_byte(val, key): msgs = {} msgs[val[0]] = sign_byte(val, key) while len(msgs) < CHAFF_SIZE: vals = list(ALL_BYTES - set(msgs.keys())) c = random.choice(vals) if c == val: raise ValueError('Chose duplicate!') fake_sig = bytes(random.choices(list(ALL_BYTES), k=SIG_SIZE)) msgs[c] = fake_sig pieces = [] for k, v in msgs.items(): pieces.append(b'%s%s' % (byte(k), v)) random.shuffle(pieces) return b''.join(pieces) def chaff_msg(val, key): if not isinstance(val, bytes): val = val.encode('utf-8') msg_out = [] for b in val: msg_out.append(chaff_byte(byte(b), key)) outval = b''.join(msg_out) return struct.pack('>I', len(val)) + outval def winnow_msg(val, key): if not isinstance(val, bytes): val = val.encode('utf-8') msglen = struct.unpack('>I', val[:4])[0] val = val[4:] chunk_len = (SIG_SIZE + 1) * CHAFF_SIZE expected_len = chunk_len * msglen if len(val) != expected_len: raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val))) pieces = [] for c in range(msglen): chunk = val[chunk_len * c:chunk_len * (c + 1)] res = winnow_byte(chunk, key) pieces.append(res) return b''.join(pieces) def winnow_byte(val, key): while val: c = byte(val[0]) sig = val[1:SIG_SIZE + 1] if sign_byte(c, key) == sig: return c val = val[SIG_SIZE + 1:] raise ValueError('No valid sig found!') def main(): inp = b'This is a test message!' msg = chaff_msg(inp, KEY) ret = winnow_msg(msg, KEY) if inp != ret: print('Wrong ret: %s' % ret) if __name__ == '__main__': main() # okay decompiling .\chaffing.pyc
#exp.py import hmac, hashlib, random, struct from collections import Counter CHAFF_SIZE = 32 SIG_SIZE = 16 ALL_BYTES = set((c for c in range(256))) def extract(val): if not isinstance(val, bytes): val = val.encode('utf-8') msglen = struct.unpack('>I', val[:4])[0] val = val[4:] chunk_len = (SIG_SIZE + 1) * CHAFF_SIZE expected_len = chunk_len * msglen if len(val) != expected_len: raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val))) pieces = [] for c in range(msglen): chunk = val[chunk_len * c:chunk_len * (c + 1)] res = extract_byte_sig_pairs(chunk) pieces.extend(res) return pieces def extract_byte_sig_pairs(val): res = [] while val: c = (val[0]) sig = val[1:SIG_SIZE + 1] res.append((c, sig)) val = val[SIG_SIZE + 1:] return res msg = open('1.txt', 'rb').read() ret = extract(msg) c = Counter(ret) real = c.most_common(256) print(real) def decode(val, d): if not isinstance(val, bytes): val = val.encode('utf-8') msglen = struct.unpack('>I', val[:4])[0] val = val[4:] chunk_len = (SIG_SIZE + 1) * CHAFF_SIZE expected_len = chunk_len * msglen if len(val) != expected_len: raise ValueError('Expected length %d, saw %d.' % (expected_len, len(val))) pieces = [] for c in range(msglen): chunk = val[chunk_len * c:chunk_len * (c + 1)] res = decode_byte(chunk, d) pieces.append(res) return b''.join(pieces) def decode_byte(val, d): while val: c = (val[0]) sig = val[1:SIG_SIZE + 1] if sig in d and d[sig] == c: return c val = val[SIG_SIZE + 1:] raise ValueError("WTF") d = {s: b for (b, s), c in real} print('\n') print('\n') print('\n') print(d) print(decode(msg,d))