Un point c'est tout (Cryptanalyse) - 404CTF 2022

Un point c'est tout (Cryptanalyse) - 404CTF 2022

Fichiers du challenge Principe:
Exploiter un point fixe non-trivial du RSA (un message qui, chiffré, est égale à lui-même) pour factoriser N = P*Q et retrouver d, qui permet de déchiffrer le flag

Le challenge

Le challenge demande de déchiffrer un RSA à partir d'infos annexes

Le challenge a été refait pendant le CTF car la factorisation de N avait leaké sur internet. Ce point sera important dans la résolution!

J'avais oublié de screener l'énoncé, alors je l'ai screené une fois le flag entré

Mise de côté

En voyant les données du challenge, je pensais qu'il s'agirait d'une timing attack: on a des données d'entrée, on a la valeur chiffrée et on a la durée de chiffrement et de déchiffrement. Je me disais donc qu'à partir de ça, j'aurai été capable de déterminer, bit à bit, la valeur de d sur la base de ces durée. Dans le concept, cela aurait été "si la durée de chiffrement de 00..010..0 est plus longue que celle de 00..001, alors il devrait y avoir un 1 en x-eme place de d

Mais dans l'un des autres challenges, appelé "Puisse Kocher être avec vous", la mention du nom de "Kocher" (lié aux side-channel attacks) m'a aussi murmuré à l'oreille que ce challenge ne serait peut-être pas une timing attack (sinon, les deux challenges seraient trop similaires).

Ne sachant par où partir, j'ai mis le challenge de côté. Jusqu'à ce que, sur Discord, les organisateurs annoncent que les données du challenge (et le flag) ont été renouvelés, car la factorisation de N avait fuitée sur FactorDB.

Fuite

Ayant gardé les données du challenge initial, j'ai retrouvé la valeur de d à partir des données de factordb puis j'ai déchiffré l'ancien flag:
404CTF{f1x3d_P01n75_4Re_v3ry_C00l}

Mon idée était de déchiffrer le flag précédent (qui me donnerait un indice), d'appliquer la méthode vers laquelle le flag me pointera aux anciennes données (dont je connais la solution du coup), puis de faire de même sur le nouveau challenge (pour flagger vraiment)

Points fixes

On cherche alors ce que sont les "points fixes" de RSA sur le net: il s'agit des messages m pour lesquels C = m ** e mod N = m
On retrouve en effet un "point fixe" dans les nouvelles données (l'input et l'encrypted sont identiques)
Mais on en a aussi dans les anciennes données: ce n'est sûrement pas un hasard

Si vous vous souvenez de Un simple oracle 1/2 (Cryptanalyse) , on savait déjà que 0 et 1 sont des points fixes pour toute clef RSA, appelés "points fixes triviaux".

Notez qu'on trouve aussi l'appelation "unconcealed messages": il faudra donc orienter les recherches sur ces deux dénominations
Or, dans un papier du net sur RSA, on peut lire qu'il existe plusieurs "unconcealed messages", mais pas une "infinité"

Cela nous renforce encore dans l'idée que ce point fixe est la solution, et que le challenge n'a donc rien à voir avec une timing attack

On trouve alors la mention de plusieurs points fixes "connus" dans RSA
On peut donc les tester sur les anciennes données pour lesquelles P et Q sont connus (via factordb)

C'est là aussi une excellente piste, car cela expliquerait comment le challenge a été construit: à partir de P et Q, connus par le créateur du challenge, choisir les bonnes input pour obtenir un seul point fixe non trivial est simple

On cherche alors, avec u notre point fixe des anciennes données, à retrouver P ou Q: ici, u=k*Q (ou u=k'*P + 1)
En creusant encore, on trouve même l'équation directe à résoudre: gcd([u;u+1;u-1],N) = [1,P,Q] (dans le désordre).
En menant ce calcul sur les anciennes données, on retrouve P, Q, 1!

Cela fonctionne car u est un point fixe si et seulement si u = {0,-1,1} mod P et u = {0,-1,1} mod Q.
Pour le point non trivial u = U2 = k*P = 0 mod P alors u = {-1,1} mod Q car si on avait u = 0 mod Q alors u = k*P = k'*Q = N = 0 mod N (P et Q premiers) donc u serait un point fixe trivial.
D'où GCD(u=k*P,N=P*Q) = P (vu que k < Q), GCD(u+/-1,N) = Q car u+/-1 = {-1+1;1-1} mod Q = 0 mod Q, multiple de Q et GCD(u-/+1,N) = 1 car u-/+1 = {-2,2} mod Q et u-/+1 = {0-1;0+1} mod P = {-1;1} mod P n'est alors multiple ni de P ni de Q
La même approche s'applique aux autres points non-triviaux (les autres combinaisons de {0;-1;1} mod {P;Q})

Le +/-1 précédent est choisi comme l'opposé de u mod Q: si u mod Q = -1 alors on prend +1 sinon on prend -1;

On mène donc ce calcul (avec les nouvelles données) et on trouve trois nombres, dont un 1. Les deux autres sont, d'après les informations précédentes, P et Q
A partir de P et Q, on en tire d, la clef de déchiffrement

Sachant que N = P * Q, le calcul de phi(N) revient à calculer phi(P) * phi(Q), ce qui est nettement plus rapide et réalisable.

On obtient alors le nouveau flag, et on peut valider le challenge:
404CTF{L35_p01n75_f1x35_C'357_7r35_b13n}

Fichiers du challenge

↩ Retour à la liste des challenges

⇇ Retour à l'accueil