Box
2 minutes to read
We are given this Python source code that encrypts the flag:
from Crypto.Util.number import bytes_to_long
flag = open("flag.txt", "rb").read().strip()
TABLE = [
lambda a, b: f"({a}+{b})",
lambda a, b: f"({a}-{b})",
lambda a, b: f"({a}*{b})",
]
def build_box(s: bytes):
e = "(x)"
for b in s:
e = TABLE[b % len(TABLE)](e, b)
return eval(f"lambda x: {e}")
box = build_box(flag)
ct = box(bytes_to_long(flag))
print(ct)
print(box(1337))
print(box(0x1337))
"""
Output:
5545457088879574964209613711409478327714366805681091501255101702161458272094830554232779120250
3011454617406654839679120250
10002638090931457241529120250
"""
It is a strange way to encrypt a message. Basically, box
is a set of operations that contain a single x
, and then calling box
with a given value means to substitute that value inside x
and get the final result.
We can see how this box
works:
$ python3 -q
>>>
>>> TABLE = [
... lambda a, b: f"({a}+{b})",
... lambda a, b: f"({a}-{b})",
... lambda a, b: f"({a}*{b})",
... ]
>>>
>>>
>>> def build_box(s: bytes):
... e = "(x)"
... for b in s:
... e = TABLE[b % len(TABLE)](e, b)
... return f"lambda x: {e}"
...
>>> box = build_box(b'ictf{fake_flag}')
>>> box
'lambda x: ((((((((((((((((x)+105)+99)*116)+102)+123)+102)-97)*107)*101)*95)+102)+108)-97)-103)*125)'
Since all operations are sums and products, we can express box
as a linear function $\mathtt{box}{(x)} = mx + n$ for some values $m, n \in \mathbb{Z}$.
We are provided with $\mathtt{box}{(\mathtt{flag})}$, $\mathtt{box}{(1337)}$ and $\mathtt{box}{(0\text{x}1337)}$. These values are enough to find $m$ and $n$ using a system of linear equations:
$$ \begin{cases} \mathtt{box}{(1337)} = 1337 \cdot m + n \newline \mathtt{box}{(0\text{x}1337)} = 0\text{x}1337 \cdot m + n \newline \end{cases} $$
So,
$$ m = \frac{\mathtt{box}{(0\text{x}1337)} - \mathtt{box}{(1337)}}{0\text{x}1337 - 1337} \qquad n = \mathtt{box}{(1337)} - 1337 \cdot m $$
Once we have found $m$ and $n$, we can find the flag:
$$ \mathtt{box}{(\mathtt{flag})} = m \cdot \mathtt{flag} + n \iff \mathtt{flag} = \frac{\mathtt{box}{(\mathtt{flag})} - n}{m} $$
Let’s do the above operations in Python:
>>> c = 5545457088879574964209613711409478327714366805681091501255101702161458272094830554232779120250
>>> c1 = 3011454617406654839679120250
>>> c2 = 10002638090931457241529120250
>>> m = (c2 - c1) // (0x1337 - 1337)
>>> n = c1 - 1337 * m
>>> x = (c - n) // m
>>> hex(x)
'0x696374667b776f775f737563685f6c696e6561725f736f5f656173797d'
>>> bytes.fromhex(hex(x)[2:])
b'ictf{wow_such_linear_so_easy}'