Rating:
The idea is simple - let's try to revert the computation (with an assumption that it would be non-ambiguous), e.g. knowing that K1 should be true try to compute J1/J2 and so on.
This would give us expected binary values of B1-B336, and, after assembling and ASCII decoding, the expected key.
1. Import the file to Google Sheets, navigate to the sUpErSeCrEt sheet, enable `View -> Show formulas`. Press `Ctrl + A`, and copy paste formulas into a tsv file.
2. Run the exploit:
```bash
% cat exploit.py
import sys
import csv
import re
def parse(filename):
with open(filename, 'rt') as fin:
reader = csv.reader(fin, delimiter='\t')
return list(reader)
def e(pattern):
return pattern.replace('(', '\(').replace(')', '\)')
def get_expected(formula, is_enabled):
if is_enabled: # expected result = True
if re.match(e(r'=AND(NOT(\w+);NOT(\w+))'), formula):
return False, False
if re.match(e(r'=AND(NOT(\w+);\w+)'), formula):
return False, True
if re.match(e(r'=AND(\w+;NOT(\w+))'), formula):
return True, False
if re.match(e(r'=AND(\w+;\w+)'), formula):
return True, True
else: # expected result = False
if re.match(e(r'=OR(\w+;\w+)'), formula):
return False, False
if re.match(e(r'=OR(NOT(\w+);\w+)'), formula):
return True, False
if re.match(e(r'=OR(\w+;NOT(\w+))'), formula):
return False, True
if re.match(e(r'=OR(NOT(\w+);NOT(\w+))'), formula):
return True, True
raise Exception('what the hell is even that?: `{}` [is_enabled={}]'.format(formula, is_enabled))
def bytes(bits, n=8):
for i in range(0, len(bits), n):
yield int(''.join(map(str, bits[i:i + n])), base=2)
if __name__ == '__main__':
parsed = parse(sys.argv[1])
# all lines parsed with the same size
assert set(map(lambda x: len(x), parsed)) == {26}
expectations = [[None for _ in range(1024)] for _ in range(1024)]
expectations[0][10] = True
for col in range(10, 1, -1):
for row in range(2 ** (10-col)):
if parsed[row][col] == '=FALSE()':
assert expectations[row][col] is False
continue
if parsed[row][col] == '':
continue
e1, e2 = get_expected(parsed[row][col], expectations[row][col])
expectations[2 * row ][col - 1] = e1
expectations[2 * row + 1][col - 1] = e2
result_bits = [0] * 336
for i in range(336):
result_bits[i] = int(expectations[i][1])
print('Key is: {}'.format(''.join(map(str, map(chr, bytes(result_bits))))))
% python3 exploit.py sUpErSeCrEt.tcv
Key is: flag{0h_g33z_th4t5_a_l0t_sp3nt_0n_L3Cr0ix}
```