CryptoCTF
Authors
We're thinking of creating a CryptoHack blog post for the writeup of this CTF. If you would like to be credited as an author, please include your name below. Each solved challenge will also include the name(s) of those who first solved it.
- name(s)
- Robin_Jadoul
- rkm0959
- TheBlueFlame121
Current Progress
Trailing Bits
Challenge
Solved by: Willwam
Points: 30
Solution
From the challenge description, we can guess that the binary data provided has a couple bits removed from either end. Not to worry however, since the removed bits won't affect the rest of the data at all.
We know that some bits have been removed, so we can just replace those with some decoy bits, and then try decoding from binary until we get readable text.
Output:
basic unit of information in computing and digital communications. The name is a portmanteau of binary digit.[1] The bit represents a logical state with one of two possible values. These values are most commonly represented as either 0or1, but other representations such as true/false, yes/no, +/−, or on/off are common.
The flag is CCTF{it5_3n0u9h_jU5T_tO_sH1ft_M3}
The correspondence between these values and the physical states of the underlying storage or device is a matter of convention, and different assignments may be used even within the same device or program. It may be physically implemented with a two-st
Flag
CCTF{it5_3n0u9h_jU5T_tO_sH1ft_M3}
Amsterdam
Challenge
Solved by: rkm0959
Points: 55
Is it normal to have such encoding?
Solution
We see that there are two steps into solving this problem. First, we have to retrieve the value of from the encryption result. Then, we calculate the plaintext from .
The first part can be done with recursion. By dividing cases on , we can find which 'if' statement we entered on the first 'while' iteration. This also gives our value of . We continue this until we have our original value of .
Now we calculate the plaintext. Notice that was initially a bit string, which was then converted to an integer. Therefore, we start by changing into a bit string.
It can be proved with induction that after a successful (one that does not return ) call of encrypt(), the value of 'msg' must be . The key idea is Pascal's Triangle.
If we know the value of at the end of encrypt(), we can reverse engineer the plaintext since we know the result . Brute force all possibilities for , and we are done.
Implementation
Flag
CCTF{With_Re3p3ct_for_Sch4lkwijk_dec3nt_Encoding!}
Three Ravens
Challenge
Solved by: TheBlueFlame
Points: 90
There were three ravens sat on a tree, Downe a downe, hay downe, a downe, They were as black as they might be.
Solution
The challenge encrypts the flag with a modulus
and gives the output , . To totally break the cryptosystem, we would want to find the totient of the modulus
but we can simplify this when the encrypted message is small enough. If we have , we can instead find , and find , and solve!
Observe that for any , as long as , any equivalence also holds mod : (but note that the other way around does not necessarily hold).
To fully see this, we can write
So, since , we can solve as if it was a single-prime RSA problem. And because , the residue (the rest when dividing by ) is exactly equal to .
Implementation
Flag
CCTF{tH3_thr3E_r4V3n5_ThRe3_cR0w5}
Butterfly Effect
Challenge
Solved by: rkm0959, Robin_Jadoul
Points: 209
Have you heard of the butterfly effect in chaos theory?
We have a very clear sample!
Solution
We start by realizing that the given value of is not actually a generator of .
In reality, generates a very small subgroup, having order of . This can be easily computed with sage or brute force in Python.
This implies that there are at most possible values for the outputs for the PRNG.
We calculate them all, then sort. Denote the result as .
We now want to find a pair such that , where is the smallest prime larger than . This gives a solution with approximately calls to the function. This is too slow to solve the problem.
To optimize, we use two tricks. First, due to small prime gap, one may assume that
holds true. This cuts the number of pairs to compute. Also, if we fix , the values of that satisfy this inequality forms an interval. Therefore, one can use binary search to efficiently compute this interval. This is efficient enough for the task.
Implementation
Flag
CCTF{r341Ly_v3ryYyyyYY_s3cUrE___PRNG___}
Mad Hat
Challenge
Solved by: rkm0959
Points: 217
A dream is not reality, but who's to say which is which?
Solution
By analyzing the dimensions of the ciphertext, it's straightforward to find .
Since the matrix part of the secret key is only determined by and the parity of , we have two possible matrices to consider. Also, if we fix , we can compute the plaintext by solving a system of linear equations. We proceed this way.
If we iterate over simply as integers, the solution of the equation may contain rational, non-integer numbers. This is slow and prone to floating-point errors, (unless we take proper care) so we will use another trick.
Since all the ord values in the plaintext are between and , we will take this entire problem into . This way, we can try different values of , solve the system without worrying about floating error, and retrieve our answer.
Implementation
MAT0 = keygen(0)
MAT1 = keygen(1)
MM0 = Matrix(GF(257), MAT0)
MM1 = Matrix(GF(257), MAT1)
adv = [1]*76
adv = vector(GF(257), adv)
AD0 = MM0.solve_right(adv)
AD1 = MM1.solve_right(adv)
cipher = [-3459749918754130611, -3459749918754138177, -3459749918754137803, -3459749918754138385, -3459749918754138025, -3459749918754138097, -3459749918754138073, -3459749918754138245, -3459749918754138183, -3459749918754138445, -3459749918754137991, -3459749918754138597, -3459749918754138309, -3459749918754138309, -3459749918754138279, -3459749918754138771, -3459749918754138327, -3459749918754138485, -3459749918754138233, -3459749918754138389, -3459749918754138207, -3459749918754138555, -3459749918754138141, -3459749918754138501, -3459749918754138677, -3459749918754138297, -3459749918754138563, -3459749918754138439, -3459749918754138429, -3459749918754138041, -3459749918754138611, -3459749918754138469, -3459749918754138217, -3459749918754138585, -3459749918754138403, -3459749918754138177, -3459749918754137777, -3459749918754138587, -3459749918754138231, -3459749918754138677, -3459749918754138127, -3459749918754138679, -3459749918754137789, -3459749918754138305, -3459749918754138025, -3459749918754138301, -3459749918754137941, -3459749918754138489, -3459749918754137583, -3459749918754138297, -3459749918754137949, -3459749918754138475, -3459749918754137879, -3459749918754138813, -3459749918754137981, -3459749918754138395, -3459749918754138201, -3459749918754138459, -3459749918754138195, -3459749918754138617, -3459749918754138003, -3459749918754138557, -3459749918754138429, -3459749918754138499, -3459749918754137951, -3459749918754138673, -3459749918754137975, -3459749918754138341, -3459749918754138121, -3459749918754138375, -3459749918754137869, -3459749918754138459, -3459749918754137739, -3459749918754138405, -3459749918754137921, -3459749918754138775]
res = vector(GF(257), cipher)
XX = MM0.solve_right(res)
YY = MM1.solve_right(res)
for i in range(0, 257):
stX = ""
stY = ""
for j in range(0, 76):
XX[j] += AD0[j]
YY[j] += AD1[j]
for j in range(0, len(XX)):
if (int)(XX[j]) <= 255:
stX = stX + chr((int)(XX[j]))
for j in range(0, len(YY)):
if (int)(YY[j]) <= 255:
stY = stY + chr((int)(YY[j]))
if "CCTF" in stX:
print(stX)
if "CCTF" in stY:
print(stY)
Flag
CCTF{TH13_i3_Hadamard_rip_y0ung_&_bri11iant_Paley!}
Heaven
Challenge
Solved by: Q7, Robin_Jadoul
Points: 226
Solution
After some renaming and minor reverse engineering of the challenge logic, we see that a jpg image has been xor'ed with a keystream generated from an LFSR. Each time a key-sized block is xored, and the key is forwarded one step in the LFSR.
Xor the encrypted file with a JFIF jpg file header to try to recover the current state of the LFSR.
Then we can get
Since we know from the source code that encryptions under consecutive keys share almost the entire key (x...xa
and bx...x
), we can recover the length of the key from this. We can observe this rotation already in the above listing of the bits, thanks to our insertion of newlines in the right positions.
Finally we can brute force the polynomial to recover the origin image file.
Implementation
Flag
CCTF{0Ne_k3y_t0_rU1e_7hem_A11_4Nd_7o_d3crYp7_th3_fl4g!}
Model
Challenge
Solved by: TheBlueFlame121, rkm0959, joachim
Points: 112
Solution
The key to solving this challenge is that
So encrypting a message m
we have, for some integer ,
Looking at the second term, it can be reduced using Fermat's Little Theorem as follows:
can have only two roots here, namely . Therefore the encryption becomes
and we can compute to factorize because is a multiple of .
One last step that needs attention is that we recover , not , which matters for the recovery of , as the primes are not interchangeable there.
Implementation
Flag
CCTF{7He_mA1n_iD34_0f_pUb1iC_key_cryPto9raphy_iZ_tHa7_It_l3ts_y0u_puBli5h_4N_pUbL!c_k3y_wi7hOuT_c0mprOmi5InG_y0Ur_5ecr3T_keY}
Gambler
Challenge
In this challenge, we have access to a server with the following options
Where the encrypttion function is given by
Solved by: Cryptanalyse
Points: 87
Solution
The goal is to decrypt the flag by recovering the hidden parameters and then solving the polynomial used in encrypt
.
We can recover all parameters quite easily with the encrypt our own message function.
We can obtain from the server the value of
for any input .
We can recover by encrypting 0 as
Where we are assuming that .
With the value of , we can calculate
Finally, with both recovered, we need to find the modulus . If we encrypt a fairly small message, such that we can use that
Since we know a and b, we can compute all the terms on the right hand side of this equation and recover . All that remains is solving for , which is pretty fast as is so small.
With all parameters known, we can request the encrypted flag from the server and solve the cubic equation
with anything you like (probably sage).
Implementation
Flag
CCTF{__Gerolamo__Cardano_4N_itaLi4N_p0lYma7H}
Classic
Challenge
Solved by: Tux, hyperreality
Points: 226
Classic is Easy but Essential!
Solution
Taking trigrams from the ciphertext, this becomes a classic monoalphabetic substitution cipher. See the script for more comments.
Implementation
Flag
CCTF{The_main_classical_cipher_types_are_substitution_ciphers}
Complex to Hell
Challenge
Solved by: pcback, joseph, UnblvR
Points: 300
I Already Know I'm Going to Hell
At This Point, It's Really Go Big Or Go Home!
Solution
tldr;
- Use flag format to set up system of equations.
- Bruteforce the first two entries on the 2nd row.
- Many keys allow decryption of the first row.
- Use last entries in first row, with knowledge of padding to bruteforce the full, correct key.
plain_to_matrix(msg, n)
takes a message string as input and a row count n
, and returns a matrix with n
rows that has the characters of msg
as complex numbers as entries (one complex number represents two characters). If the message doesn't fill the matrix completely, it is padded with 0
s.
encrypt(msg, key)
encrypts the given message by left multiplying the message (as a matrix) by the key. The size of the key space is which is infeasible to bruteforce.
We can use the flag format to reduce the amount of bruteforce required. Let the key be
where
Write the plaintext flag matrix as
and the ciphertext matrix as
(all coefficients in ).
So .
From this we get the equations
so
We'll bruteforce values for and and solve for the 8 key values with the 8 equations. We already know and from the flag format.
Doing this quickly reveals the first row of the plaintext: CCTF{This_0n3_Is_State_0f_th3_4rt_
.
With this, we can reduce the bruteforce amount to at most . Fortunately for us, it turns out that the last 4 characters of the plaintext are }000
, so we have enough information to enumerate possible keys with minimal bruteforce. We can use the exact same setup as above, except instead of bruteforcing and , we take them to be }000
. Solving the system will give us a vector , but this might not be the correct key.
Any vector of the form where is in the kernel of the coefficients matrix, , will satisfy the system. We can find all vectors in the kernel of by finding a basis for the kernel modulo each of the prime factors of , and then combining them with the Chinese Remainder Theorem. In this case, the nullity of in and is , and the nullity of in is . This means we'll need to enumerate at most possible keys.
Note on inv(key)
: I couldn't find a way to use Sage's built-ins to find the inverse of a matrix with complex entries so I just used the following theory:
Suppose exists. Write
Then, by definition
so
which is a system of 8 equations in 8 unknowns that can be easily solved.
Implementation
from itertools import product
mapstr = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!{}_"
cipher = [ [(24+36j), (41+47j), (3+27j), (36+41j), (57+58j), (11+24j), (33+7j), (52+64j), (26+23j), (30+35j), (64+39j), (52+19j), (39+45j), (33+31j), (3+17j), (21+32j), (15+55j)], [(33+44j), (15+39j), (64+50j), (44+41j), (39+20j), 42j, (16+12j), (63+27j), (9+52j), (39+64j), (5+18j), (53+25j), (47+31j), (5+49j), (24+8j), (57+9j), (38+16j)] ]
F = IntegerModRing(66)
def multiply(A ,B):
ac,ar,bc,br = len(A[0]), len(A), len(B[0]), len(B)
if ac != br:
return None
result = []
for i in range(ar):
r = []
for j in range(bc):
r.append(0)
result.append(r)
for i in range(ar):
for j in range(bc):
for k in range(br):
result[i][j] += A[i][k] * B[k][j]
return result
def inv(key):
a,b,c,d,e,f,g,h = key
M = [[a,-b,0,0,c,-d,0,0],
[b,a,0,0,d,c,0,0],
[0,0,a,-b,0,0,c,-d],
[0,0,b,a,0,0,d,c],
[e,-f,0,0,g,-h,0,0],
[f,e,0,0,h,g,0,0,],
[0,0,e,-f,0,0,g,-h],
[0,0,f,e,0,0,h,g]]
M = Matrix(F,M)
t = vector(F,[1,0,0,0,0,0,1,0])
i = M.solve_right(t)
a,b,c,d,e,f,g,h = map(ZZ, i)
I = [[a+b*1j, c+d*1j],[e+f*1j, g+h*1j]]
return I
def cong(z):
a = z.real() % 66
b = z.imag() % 66
return a + b*1j
def decrypt(key):
Kinv = inv(key)
key = [[cong(Kinv[i][j]) for j in range(2)] for i in range(2)]
M = multiply(key, cipher)
res = []
flag = ''
for i in range(2):
for j in range(17):
a = cong(M[i][j]).real()
b = cong(M[i][j]).imag()
flag += mapstr[int(a)] + mapstr[int(b)]
return flag
c0, c1, c2, c3 = 21, 32, 15, 55
c34, c35, c36, c37 = 57, 9, 38, 16
m0, m1, m2, m3 = 4, 27, 29, 65
m34, m35, m36, m37 = 64, 0, 0, 0
A = [[m0,-m1,m34,-m35,0,0,0,0],
[m1, m0, m35, m34,0,0,0,0],
[m2, -m3,m36,-m37,0,0,0,0],
[m3,m2,m37,m36,0,0,0,0],
[0,0,0,0,m0,-m1,m34,-m35],
[0,0,0,0,m1,m0,m35,m34],
[0,0,0,0,m2,-m3,m36,-m37],
[0,0,0,0,m3,m2,m37,m36]]
v = [c0,c1,c2,c3,c34,c35,c36,c37]
A = Matrix(F, A)
v = vector(F, v)
x = A.solve_right(v)
A2 = Matrix(GF(2), A)
A2K = Matrix(F, A2.right_kernel_matrix())
for lc in product(range(2), repeat=A2.right_nullity()):
try:
t2 = A2K.linear_combination_of_rows(lc)
t = vector([crt([int(a2), 0, 0], [2, 3, 11]) for a2 in t2])
key = x + t
flag = decrypt(key)
print(flag)
except ValueError:
pass
except KeyboardInterrupt:
exit()
Flag
CCTF{This_0n3_Is_State_0f_th3_4rt_and_C0mplex_is_Truly_compl3x!!}
Namura
Challenge
Solved by: Q7
Points: 375
Solution
This looks like a knapsack cryptography problem, which are usually solved by lattice reduction algorithms modelling a Shortest Vector Problem (SVP). We noticed that the title of the challenge "Namura" gave away the paper describing this algorithm, Naskao and Murakami's (Knapsack Public-Key Cryptosystem Using Chinese Remainder Theorem)[https://eprint.iacr.org/2007/107.pdf]. Section 4.2 of the paper describes a lattice that can solve low density subset sum problems, and the public key in this challenge had a very low density:
Since the flag should be all printables, we can reduce the dimension of the pubkey by removing the corresponding number to the MSB of each character in the plaintext.
Then we can just solve this like other knapsack problems by bruteforcing the permutation and using BKZ to find the SVP.
Implementation
import re
import random
import multiprocessing as mp
from functools import partial
def check(sol, A, s):
"""Check whether *sol* is a solution to the subset-sum problem.
"""
return sum(x*a for x, a in zip(sol, A)) == s
def solve(a, s, ID=None):
rand = random.Random(x=ID)
mat = []
for idx,val in enumerate(a):
mat.append([0]*idx + [1] + [0]*(len(a)-idx-1)+[val])
mat.append([0]*len(a)+[-s])
itr = 0
start_time = cputime()
while True:
itr += 1
l = mat[::]
shuffle(l, random=rand.random)
m = matrix(l)
t_BKZ = cputime()
l_sol = m.BKZ(block_size=25)
print(f"{itr} runs. BKZ running time: {cputime(t_BKZ):.3f}s")
for line in l_sol:
if all([x >= 0 for x in line[:-1]]):
print(line)
print(check(line,a,s))
print(f"After {itr} runs. FIND SVP!!! {line}\n"
f"Single core time used: {cputime(start_time):.3f}s")
return True
enc = 154657917005376465967753276253676484467260782425419406781078357515
pubkey = [636730424634282684150787505024636846878192530834301373045417941, 443443736056701854821550045409138156747702906153207509789193893, 4044894679347221866903041471393250783970070284064844489844729640, 2438178506188801348411667154785222321653401060527584288473058029, 1900607069477409243358471897897077706622577630696771143373974126, 4396893130381899655054557551793492148977658211100513328122993482, 2601912276825314189427819328705612999759768062840709690416685851, 849578696430489144601066711846105434868737506048858961510584478, 867634152731852110202428052792503837522496305953184128350918090, 2141949199052254673518707523413310868963934449025085556791898943, 1317724781892829476727276429613649391725697391917627197350586077, 846616203254169113248714620324777288157484807522832537271896727, 1889890413622399357217368964385384275068207071755568870885142697, 4345106754542111105556800435292359436746763182165461814839878219, 1844751943408649439970784234819027788878268101086942786334241578, 4635151867785248653584925319820032342108353583278365090165351369, 1891260029110631153447767958167471428147295737587261835048395769, 3273672699905851794278838098554938393037792687468962414002119644, 4759683391852904086863354069372064775438697384972606618058259428, 2277479715112568474291874878404028785747567257268529120464806983, 712281270914494089486011482407537474741428127403029959878626851, 4663860235979475414650446442104011820603148660069426522253772670, 3570757581386148492619721379754470899316095256123109990599128391, 4609713244848853151872498160877375734335329160891300656414838786, 1431248994688391495017629590719567118297228062918817671705412012, 2225618736576399852718197161416790353023368081178287753385225648, 4782768885432039605448539230699045953181097923357764740448690485, 1025808412433473089433862844337525335386046496037581875356716631, 2850703152833612251035169162871614900872662336925683266673455769, 4686484042664673737330267137247259184248980902553457550045106744, 3316117133062845045327521738264790714934051828005331038083037906, 1411496297445655314847983724570982636448577335114241954690062680, 2542720351620819402979547749565244924618621495731029455602801063, 4197157173419472170084161918188987699514176876278506629655813541, 775178221793495085043576729609381220589053240944436598437451103, 1341597796943613200200560889564801116846969301604051962802959921, 4724275587384586890632093268426638078191399337509178017491641396, 2254966368661541088781913210011063323766242664855534020654216185, 1559111672805843337464695743725374999443380244436636784823457268, 263060461355351726244024949311923372968467484234342136010504498, 4218489168395358789072676527116792449437414059225489587311420630, 2251347608406477583876276692162280889042972229705782250944073182, 1048197300230894759772482326800601949486880189444304544917201349, 4594309375612539584017914006965726879737368434732989117961461158, 1233526648681303204756491942769500757542366936959132748188681389, 3016611933554222534504704995395833948561521013355966057174149640, 685431642960387458833365483769661272653394129002170162343687962, 1252350578439116321952733140441764993245772656606639708501799071, 2004856906093670950398190666612521156885201358615487450361722687, 1725528220657822102510144312466698156124143365979935333948441423, 3301536380780212554033742823735941195638359575128262344444357806, 3361176781081176991336986769591969284375994647164396417238879397, 2555688594908398218735938381172552745926292876995621798813594216, 2149199142659861721027875250011594210747138266017264150889296633, 4654853318545885657451422703700711659405223637471250014707272999, 1783827755250002883819223478577480687561868815037598618999110299, 3876452588731221361888242546888347728419654382142841199604124779, 2283317070521561115970687892255141823986922119608171153201553969, 3015343638915794545630411225203386258523748035633382700837350107, 1308963799032621611684027617168973833892399982687941479751647735, 3363298156592318867171609036073104624481755649616128282937579774, 3543718722328215918394832245155182570535205536855659505934745836, 2955555006922666284454361589146164283232856958998231643765012061, 4193238914021395832431998242809775488323071053203281739810565939, 4863715450542324142694503897491361069694288484386266524822426647, 3583711168144466683911674650704848504341023445180872465082660398, 1433492863048866856968843544774985957106873111077658213115876127, 3622680772935480479302879234497984985614630209532096422962674742, 3887543917518693741822422553185837022122830870466259214366790339, 3010960827639423613523800853443011766752449479334524527050675334, 1675955542074383948970870230135814936799951109866034174734491734, 2568984843336400124353481960719548494069287783874504372170058935, 680042408260630675242336818143271325154353883745350135887078713, 1896768391347692167859873865813768792359296006947445277687988097, 537513148597668578568712785471862479586342936485511258184103046, 4338318157572996055378474172251186724034148657838505626251846209, 4509359887372553408550688030273180923282246069532844476087185588, 1961425576962957081785371096529881351777256192797473186708183898, 4562726127192998241808421239521775685020063730950933119470565151, 3197416476037069116835447572914275965582808251383336065711778098, 4509743379431751154130020063323115916220642219739358425391068150, 1737231313740527925458531852974418083735884963087687882655818328, 4723771434844173636187013002792278070911838005170476297565209636, 4021068815924596682472342770957679146819658388809493963529859273, 4786593367935490268774249574977281762592209022792374805751998882, 1706847947841349067687051586871379604391823960780007506398289654, 2092911436130136930529034363620771320336826052044341129920779847, 2386542753409262049262444109479898339116742017285966198413932291, 2575514997936878781309794857665223684996125674280321049577858392, 2526059212864002845504783002187945419965243527858703947395965701, 2077055376963690862993188737229202782309424513798741527458096967, 1947721666793448806619506886745665574368753315129031773531178573, 2321982120042809240576670901783025887795295409352093643395133004, 4191930348600938505176612143361132888157091847500134549846473180, 1279873852200144323116032749112043797286486924653552312015287694, 3934811009597203954835516432740855968621865146569217009553064951, 804570958275502176779582603101955727481164663345322968855176622, 4755601230261360181533138175300662604366870408130917516343576381, 2016264908613514961521473342929083040444069560476054659007958347, 3857121931198808981033402131835999166260880661479936388701406991, 4787908501772479625441292392638080593307265124479164945134226910, 403228266126326263488043524077179619385866145325037513940941892, 4080757802977772396554968304371742747141072297333640725823656444, 248086288384249359079536769334310714884272887049336400711180125, 1607777042247987295060365154963999272145526955355524894746933487]
solve_n = partial(solve, pubkey, enc)
CPU_CORE_NUM = 8
with mp.Pool(CPU_CORE_NUM) as pool:
reslist = pool.imap_unordered(solve_n, range(CPU_CORE_NUM))
for res in reslist:
if res:
pool.terminate()
break
Output:
After 19 runs. FIND SVP!!! (1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0)
Single core time used: 643.215s
flag = ''
svp = (1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1,
0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0)
for i in range(0, len(svp), 7):
flag += '0' + ''.join(map(str, svp[i:i+7]))
print(b'CCTF{'+long_to_bytes(int(flag, 2))+b'}')
Flag
CCTF{MuR4kam1_nA54K0}