Details

Crystal Clear was a reversing CTF where we had to reverse a program compiled in Crystal, a completely unknown language to me.

Anyways we find two separate arrays of bytes in memory that are xor’d against our input, byte by byte the result of the xor is stored in some cpu register and if != 0 at the end of the check the “password” was no good

So, we throw those byte arrays into z3 and solve away:

Writeup

solve.py

#!/usr/bin/env python3

from pwn import *
import z3

x1 = [0xb7, 0xe2, 0x3f, 0xd2, 0x34, 0xec, 0x7b, 0xdf, 0x3e, 0x98, 0x32, 0x6f, 0xb4, 0xbf, 0xf2, 0xfd, 0x37, 0xb5, 0xbc, 0xe2, 0x21, 0xc5, 0xc3, 0xb3, 0xcb, 0xa8, 0x1e, 0x11, 0xb7, 0x32, 0x0f, 0x47]
x2 = [0xf1, 0xa4, 0x7c, 0x86, 0x72, 0x97, 0x38, 0xad, 0x67, 0xeb, 0x66, 0x5b, 0xd8, 0xd3, 0xc3, 0x87, 0x04, 0xd1, 0xe3, 0xba, 0x11, 0x97, 0x9c, 0x82, 0xa5, 0xf7, 0x4c, 0x22, 0xc1, 0x13, 0x2e, 0x3a]

s = z3.Solver()
min_v = 0x21
max_v = 0x7e

lst = [z3.BitVec(f"{i}", 8) for i in range(0x20)]
for v in lst:
    s.add(v >= min_v, v <= max_v)

i = 0
while i < 0x20:
    s.add(lst[i] ^ x1[i] ^ x2[i] == 0x0)
    i += 1

if s.check() == z3.sat:
    m = s.model()
    r = [m[v].as_long() for v in lst]
    f = ""
    for v in r:
        f += chr(v)

    print(f)