Contexte
Nous avons un flag qui a été chiffré avec le chiffrement RSA.
Nous avons deux fichiers :
- rien-a-signaler.py : le fichier qui chiffre le flag.
- output.txt : le fichier stock les paramètres pour le chiffrement du flag.
Solution
Analyse
Analysons le fichier : rien-a-signaler.py.
import json
from Crypto.Util.number import getPrime, bytes_to_long
def keygen(n = 1024):
p = getPrime(n)
q = getPrime(n)
n = p * q
e = 2 ** 16 + 1
d = pow(e, -1, (p - 1) * (q - 1))
sk = (d, n)
pk = (e, n)
return pk, sk
# Read the flag as an integer
m = bytes_to_long(open("flag.txt", "rb").read())
# Generate RSA keys
sk, pk = keygen()
# Encrypt the flag
c = pow(m, pk[0], pk[1])
# Output public key and ciphertext
d = {
"e": pk[0],
"n": pk[1],
"c": c,
}
print(json.dumps(d, indent = 4))
import json
from Crypto.Util.number import getPrime, bytes_to_long
Nous avons plusieurs importations une pour le json, donc le résultat output.txt sera en json et Crypto.Util.number pour la gestion des nombres et génération des nombres premiers pour le chiffrement RSA.
def keygen(n = 1024):
p = getPrime(n)
q = getPrime(n)
n = p * q
e = 2 ** 16 + 1
d = pow(e, -1, (p - 1) * (q - 1))
sk = (d, n)
pk = (e, n)
return pk, sk
Ici nous avons une fonction qui permet de générer les différentes clefs publique et privée RSA avec le module n.
Nous avons une fonction qui prend en paramètre n qui sera la longueur des nombres premiers générés.
On génère deux nombres premiers de 1024 bits et on les stocke dans p et q.
On calcule le module n en multipliant p par q.
On calcule l’exposant e qui est de 2 ** 16 + 1 = 65537.
On calcule l’exposant privé d.
On calcule la clef secrète sk qui possède le couple l’exposant privé d et le module n.
On calcule la clef publique pk qui possède le couple l’exposant e et le module n.
On retourne la clef publique et la clef secrète.
# Read the flag as an integer
m = bytes_to_long(open("flag.txt", "rb").read())
# Generate RSA keys
sk, pk = keygen()
# Encrypt the flag
c = pow(m, pk[0], pk[1])
# Output public key and ciphertext
d = {
"e": pk[0],
"n": pk[1],
"c": c,
}
print(json.dumps(d, indent = 4))
On lit le fichier le flag.txt et on le convertie les données lues en entier. On génère les clef RSA mais ici il y a une grosse erreur et on inverse la clef privée et la clef publique, regardons ce qui est retourné et ce qui est généré :
return pk, sk
sk, pk = keygen()
On voit bien que l’on inverse les deux clef publique et privée.
On chiffre le flag avec la clef publique.
On affiche la clef privée.
{
"e": 14939086586092777407540803168471412724086958884607893995687327163153290580760558837291728666456222816453459253012875608081140912518401828609726644228963594136502689596910372270878975142615041204855876795840250744447608791110019817832312337476046798491861483950133453478764973611286365531244274907864964200118887980416350639882907479248120503190137345205402154450552803826178574159801186219948543406588724442253188994068292704744044422267282898105644719291000793491804938648328829611223993162601906075018324472156338267348355427156047595434154590931416765750047893661286247274247632521858558403416012123883148428323057,
"n": 15796942747309728499758004731551695370913663306666035509299434642801916886496898004446545897149657535285268305926374338100837909963511256277964036962044387829939281166102731090331978991280163210213940391251452338553405036351243486418991475381065523778778374159216111211039724992140348798301914302441933569705494577465736752087544176074475722982600742085989140379907623574747713824460161103249270448563714176784913386788071348191510218812659925461534747629228752452045853041012162619056264262054391967199115369336548943331022933845667724296738334370747384492830658154258526863726939357154899976616849634493499797766299,
"c": 8974868290281688737233990325600894780715849339628541493919631966007477856153771121147897587192029426714635875587384109624607194486211852465796766441066196469272988076202321557112300294463883797708163984188107199926745938577562219282934551167072277621808474131345695591468145868455419473050498493285402336637848596791275101533878984692539165395918338275186762268105380646876795842765910627488934075701761752437069042340873474933889573307306539126206460702731582652544213958040586038088129224761895431978602343177304095553828090049657631935349611981192723124744317395844933142968117051307548448128268941861109853064071
}
Dans le fichier output.txt nous avons notre clef privée.
Nous avons e qui est d l’exposant privé.
Nous avons n qui est le module.
Nous avons le flag qui est chiffré qui est c.
Il nous manque e pour pouvoir déchiffrer le message, mais on le connaît, on l’avait calculer en analysant le code source, il vaut 65537.
Maintenant on peut déchiffrer le message avec la clef privée par la formule suivant : $m = c^e \bmod n$
Voici le code python qui permet de retrouver le code en claire :
from Crypto.Util.number import long_to_bytes
e = 65537
c = 8974868290281688737233990325600894780715849339628541493919631966007477856153771121147897587192029426714635875587384109624607194486211852465796766441066196469272988076202321557112300294463883797708163984188107199926745938577562219282934551167072277621808474131345695591468145868455419473050498493285402336637848596791275101533878984692539165395918338275186762268105380646876795842765910627488934075701761752437069042340873474933889573307306539126206460702731582652544213958040586038088129224761895431978602343177304095553828090049657631935349611981192723124744317395844933142968117051307548448128268941861109853064071
n = 15796942747309728499758004731551695370913663306666035509299434642801916886496898004446545897149657535285268305926374338100837909963511256277964036962044387829939281166102731090331978991280163210213940391251452338553405036351243486418991475381065523778778374159216111211039724992140348798301914302441933569705494577465736752087544176074475722982600742085989140379907623574747713824460161103249270448563714176784913386788071348191510218812659925461534747629228752452045853041012162619056264262054391967199115369336548943331022933845667724296738334370747384492830658154258526863726939357154899976616849634493499797766299
d = 14939086586092777407540803168471412724086958884607893995687327163153290580760558837291728666456222816453459253012875608081140912518401828609726644228963594136502689596910372270878975142615041204855876795840250744447608791110019817832312337476046798491861483950133453478764973611286365531244274907864964200118887980416350639882907479248120503190137345205402154450552803826178574159801186219948543406588724442253188994068292704744044422267282898105644719291000793491804938648328829611223993162601906075018324472156338267348355427156047595434154590931416765750047893661286247274247632521858558403416012123883148428323057
# Déchiffrement
m = pow(c, e, n)
original_bytes = long_to_bytes(m)
flag = original_bytes.decode()
print(flag)
python3 test.py
FCSC{XXX}