Tags: racket python lambda 

Rating: 2.5

Use byte-by-byte brute force with `lambda.py` as an oracle. We first make a backup copy of `lambda.py` because we will need to run it **and** make changes to it. In the copy that we are going to run, we replace all mentions of `__file__` with the `lambda.py` we are going to change. We now write a brute force script to iterate over all bytes [1, 128) on `flag.txt` and the first 24 bytes for `lambda.py`. Here's the script:

```python
import subprocess as sub

ENCRYPTED_FLAG = 2692665569775536810618960607010822800159298089096272924
ENCRYPTED_FLAG = bytes.fromhex('{:x}'.format(ENCRYPTED_FLAG))

FLAG_FILE = 'flag.txt'
LAMBDA_PY = 'lambda.py' # we will be overwrite this file
COPY_LAMBDA = 'lambda.py.bak' # backup file for copying and pasting each character

WHAT_WE_HAVE = 'actf{3p1c_0n' # the script runs pretty slowly; don't want to wait that much
# actf{3p1c_0n3_l1n3r_95}

print('solved: %s' % WHAT_WE_HAVE)

with open(COPY_LAMBDA, 'r') as f:
PLAINTEXT = f.read(len(ENCRYPTED_FLAG))

for i in range(len(WHAT_WE_HAVE), len(ENCRYPTED_FLAG)):
solved = False

with open(LAMBDA_PY, 'wb') as f:
f.write(bytes([ord(PLAINTEXT[i])]))

# try most sensible ascii values (zero doesn't work and errors out)
for flag_i in range(1, 128):
with open(FLAG_FILE, 'wb') as f:
f.write(bytes([flag_i]))

res = sub.run(['python', 'lambda-annotated.py'], capture_output=True)

if int(res.stdout.decode('ascii')) == ENCRYPTED_FLAG[i]:
if flag_i > 126 or flag_i < 32:
print('0x{:x}'.format(flag_i))
else:
print(chr(flag_i))
solved = True
break

if not solved:
print('Could not solve this character. Skipping.')
```

We guess 2 of the characters and obtain the flag `actf{3p1c_0n3_l1n3r_95}`. Read blog post for full thought process.

Original writeup (https://cheuksblog.ca/writeup/2021/04/07/lambda-angstrom2021.html).