Google CTF 2021 Beginners Quest
#7 - Buenos Aires Conference
For this challenge we are given a file.
Running the file command we can see the file is a Zip archive.
The archive contains chall.py
and __pycache__
.
Inspecting the chall.py
script we can see that some string “flag
” has been converted into bytes and then passed through a pow() function as a form of encryption. In comments at the end of the script are two long numbers, presumably c
and n
, generated from the original flag.
from Crypto.Util.number import *
flag = b"REDACTED"
p = getPrime(1024)
q = getPrime(1024)
n = p*q
m = bytes_to_long(flag)
c = pow(m,3,n)
print(c)
print("\n")
print(n)
#15478048932253023588842854432571029804744949209594765981036255304813254166907810390192307350179797882093083784426352342087386691689161026226569013804504365566204100805862352164561719654280948792015789195399733700259059935680481573899984998394415788262265875692091207614378805150701529546742392550951341185298005693491963903543935069284550225309898331197615201102487312122192298599020216776805409980803971858120342903012970709061841713605643921523217733499022158425449427449899738610289476607420350484142468536513735888550288469210058284022654492024363192602734200593501660208945967931790414578623472262181672206606709
#21034814455172467787319632067588541051616978031477984909593707891829600195022041640200088624987623056713604514239406145871910044808006741636513624835862657042742260288941962019533183418661144639940608960169440421588092324928046033370735375447302576018460809597788053566456538713152022888984084306297869362373871810139948930387868426850576062496427583397660227337178607544043400076287217521751017970956067448273578322298078706011759257235310210160153287198740097954054080553667336498134630979908988858940173520975701311654172499116958019179004876438417238730801165613806576140914402525031242813240005791376093215124477
We dont know the original prime numbers used to encrypt the message as the getPrime(1024)
function generates a random prime number. However, we do know their product (n
) and their remainder from the pow() function (c
).
c = pow(m,3,n)
is essentially the same as c = m^3 % n
The modulo function (%
) gives the remainder of a division so in this case “c
” is the remainder. We can use this knowledge to make brute forcing the flag much much faster.
Brute forcing
“m
” is a long int created from the bytes that make up the flag.
As the flag is turned into an int, it must be a whole number. With this in mind we can write a reverse function to the pow()
function which goes a little like this: m^3 = k * n + c
where k
is a constant coefficient of n
.
As we know, the cube root of m^3
should be a whole number so all we need to do to brute force the flag is itterate through different values of k until we get m
to be a whole number. We can use the gmpy2
library to find the cube root of long ints and it will also conviniently return a bool depending on whether it is an int or not. Writing the script to bruteforce the flag in python looks like this:
from Crypto.Util.number import *
import gmpy2
c = 15478048932253023588842854432571029804744949209594765981036255304813254166907810390192307350179797882093083784426352342087386691689161026226569013804504365566204100805862352164561719654280948792015789195399733700259059935680481573899984998394415788262265875692091207614378805150701529546742392550951341185298005693491963903543935069284550225309898331197615201102487312122192298599020216776805409980803971858120342903012970709061841713605643921523217733499022158425449427449899738610289476607420350484142468536513735888550288469210058284022654492024363192602734200593501660208945967931790414578623472262181672206606709
n = 21034814455172467787319632067588541051616978031477984909593707891829600195022041640200088624987623056713604514239406145871910044808006741636513624835862657042742260288941962019533183418661144639940608960169440421588092324928046033370735375447302576018460809597788053566456538713152022888984084306297869362373871810139948930387868426850576062496427583397660227337178607544043400076287217521751017970956067448273578322298078706011759257235310210160153287198740097954054080553667336498134630979908988858940173520975701311654172499116958019179004876438417238730801165613806576140914402525031242813240005791376093215124477
k = 0
while not gmpy2.iroot(k*n +c, 3)[1]:
k+=1;
print(long_to_bytes(gmpy2.iroot(k*n +c, 3)[0]))
Running the script we get the flag to be: CTF{34sy_RS4_1s_e4sy_us3}
Next quest: Google2021Beginners-08