TetCTF 2022 - all crypto challenges
Setup:
from sage.all import *
import ast
from binteger import Bin
from sock import Sock
Shares
In this challenge, we have a linear secret sharing scheme, based on random matrices modulo $P=37$. The secret password $s$ is 16 symbols long. In the $i$-th query, we are given $$(A_i, B_i, c_i = A_i\times s + B_i \times r_i),$$ where $A_i,B_i \in \mathbb{F}_P^{16\times16}$ are random matrices and $r_i \in \mathbb{F}_P^{16}$ is a random vector.
If the matrix $B_i$ is always invertible, then $c_i$ is useless, as it contains full entropy from $r_i$. However, the coefficients are sampled uniformly at random, and so, the matrix can be singular with probability about $1/P=1/37$. In this case, there exists at least one bector $b_i$ such that $b_i\times B = (0,\ldots,0)$. Then, $$ b_i\times c_i = b_i\times A_i\times s + b_i\times B_i \times r_i = (b_i\times A_i) \times s. $$ We get a pure linear equation on $s$!
Collecting enough equations (16), we can solve for $s$. For this, we need about $16 \times 37 = 592$ queries.
import string
ALLOWED_CHARS = string.ascii_lowercase + string.digits + "_"
P = len(ALLOWED_CHARS)
INT_TO_CHAR = {}
CHAR_TO_INT = {}
for _i, _c in enumerate(ALLOWED_CHARS):
INT_TO_CHAR[_i] = _c
CHAR_TO_INT[_c] = _i
F = GF(P)
known = []
target = []
f = Sock("139.162.61.222 13371")
f.send("x\n" * 1000)
for i in tqdm(range(1000)):
entry = ast.literal_eval(f.read_line().decode())
mat = matrix(F, [
[CHAR_TO_INT[v] for v in row]
for row in entry
])
A = mat[:16,:16]
B = mat[:16,16:32]
c = mat.column(-1)
if B.rank() != 16:
for ker in B.left_kernel().matrix():
known.append(ker * A)
target.append(ker * c)
if matrix(known).rank() >= 16:
sol = matrix(F, known).solve_right(vector(F, target))
pw = "".join(INT_TO_CHAR[int(v)] for v in sol)
print("got pw!", pw)
f.send_line(pw)
f.shut_wr()
print(f.read_all().splitlines()[-1])
break
else:
continue
break
57%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████▉ | 573/1000 [00:02<00:01, 317.42it/s]
got pw! 4epfhiql50wgj2so
60%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▊ | 598/1000 [00:03<00:02, 171.46it/s]
b'TetCTF{m0r3_sh4r3s____m0r3_m0r3_m0r3_fun}'
Shares2
In the second variant of the challenge, the password length is 32, there are no random symbols added and we are given all 32 equations (i.e., the matrices $A_i$ are 32x32 each). However, the output $c_i$ is masked by adding a random binary vector (multiplied by $P//2=18$).
I misread the challenge details, and assumed that the setting is the same as in Shares, except that the binary vector is added. That is, I assumed that the password is 16 symbols long and 16 other symbols are random each time. I will describe how to solve this variant, as it is harder and can anyway be used to solve the correct variant.
Assume that in the $i$-th query, we are given $$(A_i, B_i, c_i = A_i\times s + B_i \times r_i + 18\cdot e_i),$$ where $A_i,B_i \in \mathbb{F}_P^{32 \times16 }$ are random matrices, $r_i \in \mathbb{F}_P^{16}$ and $e_i \in \mathbb{F}_2^{32}$ are random vectors.
Similarly to Shares, we can eliminate $r_i$. Since we have 32 equations now, we get 16+ equations on each query: let $\tilde{B_i} = \text{left ker}(B)$, then $$\begin{split} c'_i &= \tilde{B}_i\times c_i \\ &= \tilde{B}_i\times A_i\times s + \tilde{B}_i\times B_i \times r_i + \tilde{B}_i \times 18\cdot e_i \\ &= (\tilde{B}_i\times A_i) \times s + \tilde{B}_i \times 18\cdot e_i \\ &= A'_i \times s + C'_i \times e_i. \end{split}$$
We have linear equations with a small error vector. Clearly, we should try LLL.
We will use two queries and build the following lattice:
$$ \left( \begin{array}{rrrrrr} \color{gray}c'_1 & \color{gray}c'_2 & \color{gray}s & \color{gray}e_1 & \color{gray}e_2 & \color{gray}* \\ -&-&-&-&-&- \\ A_1'^T & A_2'^T & 1 & & & \\ C_1'^T & & & 2 & & \\ & C_2'^T & & & 2 & \\ P &&&& & \\ & P &&& & \\ c'_1 & c'_2 & & 1 & 1 & D \\ \end{array} \right) $$ Here, the last row corresponds to the target vector. We are doing CVP but using the Kannan embedding method to reduce it to SVP, with an appropriate bound $D$.
def split(mats):
As, Cs, cs = [], [], []
for mat in mats:
A = mat[:,:16]
B = mat[:,16:32]
C = identity_matrix(GF(P), 32) * (P // 2)
c = mat[:,32:]
ker = B.left_kernel().matrix()
A, C, c = ker * A, ker * C, ker * c
As.append(A.transpose())
Cs.append(C.transpose())
cs.append(c)
return As, Cs, cs
f = Sock("139.162.61.222 13372", timeout=100000)
f.send("x\n" * 5)
data = []
for i in range(5):
entry = ast.literal_eval(f.read_line().decode())
mat = matrix(F, [
[CHAR_TO_INT[v] for v in row]
for row in entry
])
data.append(mat)
def solve(data):
t = len(data)
I = ZZ(1)
O = ZZ(0)
As, Cs, cs = split(data)
bm = []
bm.append(As[:t] + [I] + [O] * t)
for i, C in enumerate(Cs[:t]):
row = [O] * t
row[i] = C
row2 = [O] * t
row2[i] = 2*I
bm.append(row + [O] + row2)
for i in range(t):
row = [O] * t
row[i] = P*I
bm.append(row + [O] * (1 + t))
target = []
for c in cs[:t]:
target.extend(c.list())
target.extend([0] * 16 + [1] * 32 * t)
target = vector(target).change_ring(ZZ)
m = block_matrix(ZZ, bm)
assert m.ncols() == 16 * t + 16 + 32 * t
weights = [10**20] * 16*t + [1] * 16 + [10**10] * 32*t + [1]
D = ZZ(t * 32 * 10**8)
m = m.stack(matrix(ZZ, [target]))
m = m.augment(matrix(ZZ, [O] * (m.nrows()-1) + [D]).transpose())
assert len(weights) == m.ncols()
# make server busy to keep connection
f.send("a\n" * 1000)
for i, wt in enumerate(weights):
m.rescale_col(i, wt)
print("BKZ...")
m = m.BKZ(block_size=24).change_ring(QQ)
print("BKZ done")
for i, wt in enumerate(weights):
m.rescale_col(i, QQ(1)/wt)
m = m.change_ring(ZZ)
for row in m:
if row[:16*t] == 0 and row[16*t+16:-1] != 0 and row[-1] != 0 and row[-2] % 2 and abs(row[-1]) == D:
print(row[-1], D)
vals = row[16*t+16:-1]
print(min(vals), max(vals))
if -1 <= min(vals) <= max(vals) <= 1:
if row[-1] == -D:
row = -row
sol = -row[16*t:16*t+16]
pw = "".join(INT_TO_CHAR[int(v) % P] for v in sol)
print("pw", pw)
return pw
Fail
mat1, mat2 = data[:2]
pw1 = solve([mat1, mat2])
mat1 = mat1[:,16:32].augment(mat1[:,:16]).augment(mat1[:,32:])
mat2 = mat2[:,16:32].augment(mat2[:,:16]).augment(mat2[:,32:])
pw2 = solve([mat1, mat2])
f.send_line(pw1 + pw2)
f.shut_wr()
print(f.read_all().splitlines()[-1])
BKZ... BKZ done 6400000000 6400000000 -1 1 pw sxaxwxjjkkv71zv4 BKZ... BKZ done 6400000000 6400000000 -1 1 pw d9hf5ctbub0av3bi b'TetCTF{but_th3_m4st3r_sh4re_1s_n0t_fun_4t_4ll}'
Algebra
Here, we are given some group implementation, and we need to find an efficient homomorphism to $\mathbb{F}_p^*$.
p = 50824208494214622675210983238467313009841434758617398532295301998201478298245257311594403096942992643947506323356996857413985105233960391416730079425326309
C = 803799120267736039902689148809657862377959420031713529926996228010552678684828445053154435325462622566051992510975853540073683867248578880146673607388918
INFINITY = "INF"
def op(x1, x2):
"""Returns `(x1 + x2 + 2 * C * x1 * x2) / (1 - x1 * x2)`."""
if x2 == INFINITY:
x1, x2 = x2, x1
if x1 == INFINITY:
if x2 == INFINITY:
return (-2 * C) % p
elif x2 == 0:
return INFINITY
else:
return -(1 + 2 * C * x2) * pow(x2, -1, p) % p
if x1 * x2 == 1:
return INFINITY
return (x1 + x2 + 2 * C * x1 * x2) * pow(1 - x1 * x2, -1, p) % p
assert op(op(2020, 2021), 2022) == op(2020, op(2021, 2022))
Confusingly, INFINITY
here is a usual group element, not the group identity (which is 0).
Further, note that op
computes something very similar to the tangengt of the sum:
$$
\tan(x+y) = \frac{\tan(x) + \tan(y)}{1-\tan(x)\tan(y)},
$$
$$
op(x,y) = \frac{x + y + 2\cdot C \cdot x\cdot y}{1-x \cdot y}.
$$
Note that the tangent formula can be interpreted simply as adding angles, which clearly form a group.
Usually, homomorphisms from curves to $\mathbb{F}_p^*$ are linear rational maps. Let's try to check this here directly.
We want a non-degenerate rational map $\pi(x)=\frac{x+a}{x+b}$ such that $\pi(op(x, 2022)) = g\cdot \pi(x)$. That is, multiplying by $2022$ in the group is equivalent to multiplying by some $g$ in $\mathbb{F}_p^*$.
n = 10
a, b, g = GF(p)['a,b,g'].gens()
x = 2022
y = op(x, x)
eqs = []
for i in range(n):
x = op(x, 2022)
y = op(y, 2022)
# (y + a) / (y + b) = g (x + a) / (x + b)
eq = (y + a) * (x + b) - g * (x + a) * (y + b)
eqs.append(eq)
Ideal(eqs).variety()
verbose 0 (3837: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation. verbose 0 (1080: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation.
ValueError: The dimension of the ideal is 1, but it should be 0
Ooh, the system is underdetermined! But why?
It turns out, that there exists a 1-dimensional solution space: $g=1, a=b$ leads to $$(y+a)/(y+a)=1\cdot(x+a)/(x+a) = 1,$$ which is obviously true.
How can we encode the fact that we want $a \ne b$? Here, we can do a simple trick. We multiply the variable $g$ of the equation by $a-b$: it corresponds to a simple change of variables, but makes $a=b$ a wrong solution!
eqs = []
for i in range(n):
x = op(x, 2022)
y = op(y, 2022)
# (y + a) / (y + b) = g (x + a) / (x + b)
eq = (y + a) * (x + b) - (a - b) * g * (x + a) * (y + b)
eqs.append(eq)
sols = Ideal(eqs).variety()
sols
verbose 0 (3837: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation. verbose 0 (1080: multi_polynomial_ideal.py, dimension) Warning: falling back to very slow toy implementation. verbose 0 (2270: multi_polynomial_ideal.py, variety) Warning: falling back to very slow toy implementation. verbose 0 (3837: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation. verbose 0 (3837: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation.
[{a: 22028781193260601150215372852743243072534054369034373355826026755141703972839605913903845829450804221333172177888152011390316978343515577032315535048272856, b: 30403025541489493604800988683343385662063299229646452236323267699080879682775308287796866138143113667746438130490796553103815494624941972144707891591831289, g: 45402017495049849725596416041010660568087572919781453522482002870895129994557342220899801511502853600885466780271951723888133792819135097058341909311476364}, {a: 30403025541489493604800988683343385662063299229646452236323267699080879682775308287796866138143113667746438130490796553103815494624941972144707891591831289, b: 22028781193260601150215372852743243072534054369034373355826026755141703972839605913903845829450804221333172177888152011390316978343515577032315535048272856, g: 3778598816224028730365547047535206079472473753181851253732207806576394233991895639470685374537933502872454119905634788555826768305217156939182119999868005}]
a, b, g = sols[0][a], sols[0][b], sols[0][g]
g /= (a - b) # undo variable replacement
proj = lambda x: (x+a) / (x+b)
proj(0)
37291755603778762952446086021127083965370188491320744451482250160284045677238313859983256323428449624529668045685695172227464589652991653757342205880081966
Note that we solved the multiplicative effect, but we didn't solve the base case. For this, we simply need to always divide by the image of the group element 0.
pie = lambda x: proj(x) / proj(0)
f = Sock("139.162.61.222 13374")
q = int(f.read_line())
w = int(f.read_line())
e = int(f.read_line())
f.send_line(str(pie(q)))
f.send_line(str(pie(w)))
f.send_line(str(pie(e)))
print(f.read_line())
b'TetCTF{1_just_l0v3_th3_un1t_c1rcl3_s0_much}\n'
Fault
In this challenge, we are given access to a faulty RSA decryption oracle. It always decryps encrypted flag with the secret 128-bit exponend $d$, but it also introduces a random 128-bit fault $e$ which is xored to the exponent before the decryption. In other words, we obtain $$ (e, b=c^{d\oplus e} \mod{n}) $$ in one query.
We are not even given the value of $n$ here.
I didn't notice that we can ask to decrypt a constant instead of the flag. In this case, sending $c=-1$ reveals $n-1$ if the exponent is odd.
Instead, I will describe how to recover $n$ using only the flag decryption oracle.
The main observation for this challenge is that each bit of $e$ simply defines a multiplier to the final product. Let $c^d$ to be the "base" value. If the $i$-th least significant bit of $d$ is 0, the resulting product contains $c^{2^i e_i}$. Otherwise, the resulting product contains $c^{-2^i e_i}$, as flipping the 1 bit to 0 corresponds to dividing by $c^{2^i}$. This can be written as: $$ b = c^{d\oplus e} = c^d \cdot \prod_i c^{(-1)^{d_i}2^i e_i} = a \cdot \prod_i c_i'^{e_i}. $$
Now, we can let all 128 (unknown) values $c'_i$ to be the multiplicative basis, together with the base value $a=c^d$. Multiplication corresponds to addition of exponents, so we have linear algebra in the exponents on the known vectors $e$. Since we don't know the group order, we have to work over $\mathbb{Z}$ (or $\mathbb{Q}$ in intermediate steps).
First, in order to recover $n$, we need to find different ways to obtain the same value modulo $n$. Since we can collect more than 129 samples, there is linear redundancy, which can be used to find zero-vectors in the exponent: $$\frac{b_1^{k_1}\cdot\ldots b_t^{k_t}}{b_{t+1}^{k_{t+1}}\cdot\ldots\cdot b_{t+t'}^{k_{t+t'}}} \equiv 1 \pmod{n},$$ $$\Rightarrow b_1^{k_1}\cdot\ldots b_t^{k_t} \equiv b_{t+1}^{k_{t+1}}\cdot\ldots\cdot b_{t+t'}^{k_{t+t'}} \pmod{n}.$$ Unfortunately, if we simply perform Gauss elimination over $\mathbb{Q}$, the coefficients (= powers) will become huge. Since we don't know $n$, we can not afford huge exponents.
So, we need small solutions in a linear system, pointing to... LLL!
f = Sock("139.162.61.222 13373")
data = []
f.send("c\n" * 250)
for i in tqdm(range(250)):
data.append(ast.literal_eval(f.read_line().decode()))
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 250/250 [00:01<00:00, 188.09it/s]
mat = matrix(ZZ, [
Bin(e, 128).tuple + (1,) # 1 for the base b = c^d
for e, c in data
])
m = mat.augment(identity_matrix(mat.nrows()))
W = 2**64 # we want it zero
for i in range(129):
m.rescale_col(i, W)
m = m.LLL()
# not need to scale back since those are zeroes
m[0]
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, -3, -12, 2, 11, -4, -2, -1, 1, 4, 13, 2, -3, 8, 1, -4, -1, 10, -5, -3, 0, -2, -2, -7, 3, 8, 10, -9, 6, 3, -4, 2, -12, -4, -8, -3, -3, 2, 2, -3, 2, -5, -2, 5, 4, 0, -4, 1, -2, 1, -6, -4, 10, -7, 5, -6, -1, -9, -1, 2, 2, 6, 5, 3, -1, -9, -1, -7, -1, -2, 1, 7, 3, -6, 5, 1, 2, 10, -7, 0, 6, 3, -7, 6, -6, -8, 4, 3, 3, -4, 4, 4, 0, -3, 2, 2, 1, -2, -3, 8, -2, -1, 6, 9, -1, -3, 1, 7, 1, 2, -2, 1, -3, -1, -1, -1, 4, 2, 0, 1, 1, 4, -1, 4, -12, 7, -4, 5, 5, -2, -1, 0, 0, 6, -11, 7, -6, -1, -5, 0, 3, 1, 6, 1, 1, -2, 1, 5, 0, 3, -3, -4, -13, -3, 6, 5, 0, 0, -1, 1, -9, 2, -4, -2, -2, -2, 7, -2, 11, -3, 9, -7, 13, 9, 1, 1, -9, -1, 1, 7, -3, 4, 0, -11, -1, -3, -4, -4, -1, -6, -3, -3, -3, -1, -1, -3, -4, 5, 2, 3, 2, -1, -2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
n = 0
for row in m:
if row[:129] != 0:
continue
take = row[129:]
assert take * mat == 0
total = sum(map(abs, take))
print("total exp", total)
if total > 1000:
continue
l = 1 # positive exponent
r = 1 # negative exponent
for i, coef in enumerate(take):
if coef < 0:
r *= ZZ(data[i][1])**int(-coef)
elif coef > 0:
l *= ZZ(data[i][1])**int(coef)
was0 = n == 0
n = gcd(n, l - r)
if was0:
for d in primes(10**6):
while n % d == 0:
n //= d
print(int(n).bit_length, "bits")
n
total exp 788 total exp 956 total exp 992 total exp 940 total exp 1020 total exp 1134 total exp 1012 total exp 1010 total exp 964 total exp 956 total exp 1174 total exp 964 total exp 866 total exp 1066 total exp 1162 total exp 1212 total exp 1058 total exp 1076 total exp 1108 total exp 968 total exp 916 total exp 1088 total exp 1038 total exp 1024 total exp 1150 total exp 1106 total exp 874 total exp 1014 total exp 864 total exp 968 total exp 954 total exp 1030 total exp 988 total exp 1066 total exp 956 total exp 972 total exp 1122 total exp 940 total exp 920 total exp 878 total exp 892 total exp 972 total exp 874 total exp 1002 total exp 850 total exp 1000 total exp 822 total exp 1010 total exp 1006 total exp 1032 total exp 994 total exp 826 total exp 946 total exp 1006 total exp 766 total exp 972 total exp 1000 total exp 916 total exp 1006 total exp 880 total exp 948 total exp 994 total exp 908 total exp 946 total exp 1020 total exp 964 total exp 1066 total exp 1046 total exp 1026 total exp 776 total exp 872 total exp 1098 total exp 1016 total exp 1172 total exp 984 total exp 1062 total exp 1084 total exp 954 total exp 1092 total exp 924 total exp 1004 total exp 892 total exp 1144 total exp 1162 total exp 1004 total exp 956 total exp 1060 total exp 1162 total exp 1006 total exp 878 total exp 892 total exp 1056 total exp 950 total exp 934 total exp 982 total exp 1136 total exp 900 total exp 1046 total exp 976 total exp 944 total exp 980 total exp 870 total exp 1106 total exp 1082 total exp 990 total exp 1126 total exp 950 total exp 1090 total exp 894 total exp 962 total exp 892 total exp 1104 total exp 964 total exp 1126 total exp 1044 total exp 1064 total exp 910 total exp 1002 total exp 1198 total exp 1022 total exp 1176 <built-in method bit_length of int object at 0x7f3829afedf0> bits
124217875017693981438373889994606129923304968946265334335977917823588507715221733762831898609731538619253209136618903634779460007760209936134075290899530703320032114878851957436031470983264365504490701904507160973127049540844631212367371313377707894526617065409095533368660793349328274804862198629524390018631
Now, to recover the flag, we want to recover $b=c^d$, which corresponds to the vector $(0,\ldots,0,1)$ in the exponent. We can repeat the procedure but allowing small values in the last component. Then, either we hit 1 by chance or we can use extended GCD to get 1 from several coprime exponents.
m = mat.augment(identity_matrix(mat.nrows()))
W = 2**64 # we want it zero
V = 10 # smaller
for i in range(128):
m.rescale_col(i, W)
m.rescale_col(128, V)
m = m.LLL()
m = m.change_ring(QQ)
m.rescale_col(128, QQ(1)/V)
m = m.change_ring(ZZ)
for row in m:
if row[128] == -1:
row = -row
if row[:128] == 0 and row[128] == 1:
print(row)
msg = 1
for i, v in enumerate(row[129:]):
msg *= pow(int(data[i][1]), int(v), n)
print(Bin(msg).bytes)
break
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 6, -1, 1, -4, 10, 0, 1, -1, -1, -2, -1, -2, -3, -3, -10, -5, 4, -4, -3, 0, -5, -3, -4, -5, 1, 4, 8, -12, 12, -11, -7, -4, 4, 5, 4, 2, -5, -3, 0, -12, 4, -4, 6, 8, 12, -8, -9, -8, -8, 10, -7, -9, -10, 12, 4, -3, 11, 5, -6, -8, 1, 7, 3, 2, 1, 11, 0, -6, 0, 7, -15, -3, -1, -9, -2, 6, 3, -4, 1, 11, 11, 7, -8, -12, 9, 1, -11, -5, -4, 5, -7, -7, -2, 6, 4, -4, 3, 4, -1, 5, -10, 1, -4, -6, 4, 20, 11, -3, 7, -5, 7, 0, -11, 3, -3, 15, 2, -4, -5, -4, -6, 1, 2, 9, 3, 2, -8, 18, -2, 0, 6, -2, -9, -7, 3, -4, -4, 0, -2, -11, -1, 5, 6, 6, -6, 9, 0, -2, -11, -5, -5, 1, 3, 7, 0, 2, -1, 1, 0, 1, -3, -7, -8, 3, 3, -1, 1, 11, 14, 2, 0, 8, 8, -7, 8, 3, 6, 6, -13, -8, 10, -3, -2, -3, 0, -4, -2, 1, -1, 8, -2, 0, 0, -4, 1, 5, 0, 3, 1, 0, -1, 0, 1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) b'TetCTF{4n_unr34l1st1c_f4ult____1_th1nk}'