404CTF - Cryptanalyse
Cryptanalyse
Dur à CERNer (Intro)
Le CERN tente une nouvelle manière d’obtenir des collisions de particules en les envoyant une par une. Si cette méthode marchait, cela permettrait de drasiquement réduire le coût des opérations ! Malheureusement, les chances d’obtenir une collision semblent astronomiquement faibles…
Résolution
Le code fourni effectue des vérifications au début: pas les mêmes caractères en input.
La partie intéressante est la suivante:
def accélérateur_de_particules(particule_a : str, particule_b : str) -> bool: sha256 = hashlib.sha256() sha256.update(bytes.fromhex(particule_a)) position_particule_a = sha256.digest()
sha256 = hashlib.sha256() sha256.update(bytes.fromhex(particule_b)) position_particule_b = sha256.digest()
return position_particule_a == position_particule_bIci, on fait le SHA256 des coordonnées des particules, et on cherche à vérifier l’égalité des hashs. Hors, le SHA256 n’a quasiment aucune chance de collision.
La solution doit donc être ailleurs, et il reste pas grand chose. En lisant la documentation de fromhex():
classmethod float.fromhex(s) Méthode de classe pour obtenir le float représenté par une chaîne de caractères hexadécimale s. La chaîne s peut contenir des espaces avant et après le chiffre.
Donc, si on donne une chaîne 4142 et une chaîne 41 42, les chaînes valident la vérification de différence, et sont interprétées de la même façon par fromhex().
Testons:
Position de la première particule (format hexadecimal) :> 4142Position de la deuxième particule (format hexadecimal) :> 41 42Accélérateur de particules en cours...Bien joué ! Voici le résultat de l'analyse des données :Le flag est donc 404CTF{P4rt1cl35_g0_brrrrrrrrr!}
Déjeuner à l’ANSSI (Facile)
Pendant la pause déjeuner, vous vous êtes introduits à l’ANSSI et avez trouvés une machine dont le but est de chiffrer des données privées. Malhereusement pour vous, un filtre empêche les données les plus sensibles d’être leakées. En plus, il faut vous dépêcher avant que les cryptologues reviennent : vous n’avez le temps de faire qu’un seul essai. Saurez vous récupérer le flag ?
Résolution
Donc à première vue, on nous donne:
- n et e, le couple pour une clé publique RSA
- Le cyphertext contenant le flag
Le chiffrement RSA est normal.
Techniquement, on pourrait redonner le cyphertext qui est fourni au démarrage, mais c’est bloqué par le if.
Il faut donc trouver une solution pour contourner ceci.
On trouve que le RSA est un chiffrement homomorphe vis-à-vis de la multiplication, c’est à dire que si E est la méthode de chiffrement, alors E(x)*E(y) = E(x*y) pour être précis, ce serait E(x)*E(y) équivalent à E(x*y) mod n.
Donc en multipliant les cyphertexts, on multiplie aussi les plaintexts.
On peut alors fabriquer c' = c*E(2), et donc c' = E(flag) * E(2) = E(2*flag).
Quand le serveur déchiffre, il obtient 2*flag, et donc la condition if n’est pas validée.
Le seveur a donc répondu avec 2m mod n, et en connaissant n, on peut calculer l’inverse de 2: 2^(-1) mod n, puis m = (2m)* 2^(-1) mod n, ce qui donne le flag.
Voici le code utilisé:
from Crypto.Util.number import long_to_bytes
data = {'n': ..., 'e': ..., 'encrypted_flag': ...}k=2tmp = (data["encrypted_flag"]*pow(k,data["e"],data["n"])) % data["n"]print(tmp)
m_prime = int(input("Chall returns ? "))
k_inv = pow(k, -1, data["n"])
m = (m_prime * k_inv) % data["n"]
print(long_to_bytes(m))Le flag est donc 404CTF{Luncht1m3_4tt4ck_b35t_4tt4ck}
← Back to blog