Scrambled: RSA
Problem
Hmmm I wonder if you have learned your lesson... Let's see if you understand RSA and how the encryption works. Connect with
nc mercury.picoctf.net 4572
.
Solution
Connecting to the service outputs some ciphertext, the public modulus, and the exponent:
The service will also encrypt any input we give it and show the corresponding ciphertext.
In textbook RSA, a
1
should encrypt to1
. But, when we try encrypting a1
we get13589787814203979735997344432080802832776008984701751529073256623683835560426019268055662727723878817162581242623884397426411415725347741008962849580645219519573984615300484601979495080932024787662131004577978449903745252490885056468740446181188019506761784393355054186218263954234491000582090477859332982836
.Encrypting some input (
aaa
) multiple times produces different outputs, which means the algorithm is not deterministic. Strangely, encryptinga
multiple times produces the same output. Essentially, the number of possible encrypted outputs is equal to the length of the input text. For example, there is only one character in1
so there is only one ciphertext while there are three characters inaaa
and thus three valid ciphertexts exist.Encrypting
aa
produces1358978781420397973599734443208080283277600898470175152907325662368383556042601926805566272772387881716258124262388439742641141572534774100896284958064521951957398461530048460197949508093202478766213100457797844990374525249088505646874044618118801950676178439335505418621826395423449100058209047785933298283673561024996000428515785201807310147438746525988645885310370799314417341170352572980373936820027773998706009446119059121725998847299152732140652261734547503673358211949690790453350635511909487532110430283112659904909965978120113482426195268318329751292020654211499572883335268473019408057847129211754745164317
, which is 616 characters long. Let's useE
to denote the encryption function andE1(m)
to denote the first ciphertext of messagem
. TheE1('a')
from before is 308 characters long. This is exactly double which indicates that the encryption algorithm uses some kind of concatenation. Reconnecting and sendinga
andaa
again does not produce ciphertexts where the length is exactly double, but the length ofE1('aa')
is always close to double that ofE1('a')
.After looking at
E1('a')
andE1('aa')
, I realized thatE1('aa')
includesE1('a')
. Encryptingabc
also includesE1('a')
. In other words,a
's ciphertext is inabc
's ciphertext. However,b
's ciphertext is not inabc
's ciphertext. Despite this,E1('ab')
is inE1('abc')
. The encryption algorithm appears to randomize the order of the encrypted letters. InE1('abc')
,E1('a')
is sometimes first, sometimes second, and sometimes last.Taking all of this information into account,
E1('a')
and some value that representsE1('b')
are always inE1('abc')
. This also applies to the flag ciphertext. Since the flag format begins withpicoCTF{
,E1('p')
is inE1(flag)
and a representation ofE1('i')
is also in the flag. We can encryptp
and then encryptpi
. We can then removeE1('p')
fromE1('pi')
to obtain the representation ofE1('i')
that is in the encrypted flag. We repeat this process until the{
character when we don't know the next character. At this point we can loop through every printable ascii character,c
, and encrypt'picoCTF{'+c
.So, in summary, our exploit script does the following:
Create a string,
decoded_flag
, to hold the flag's characters as the loop runs.While
decoded_flag[-1]
is not}
then for each printable ascii character,c
:Encrypt
decoded_flag+c
and store tocurrent_encrypt_test
.Remove the previous encrypted input (
previous_encrypt_test
) fromcurrent_encrypt_test
to obtain the representation ofE(c)
and save tocurrent_char_rep
.If
current_char_rep
is inE1(flag)
then appendc
todecoded_flag
and break to the next iteration.Set
previous_encrypt_test
tocurrent_encrypt_test
.
Running the script will print the flag character by character.
Flag
picoCTF{bad_1d3a5_3525501}
Last updated