I have used an RSA key to encrypt the flag. Can you find a way to reconstruct the private key using the public key?
Given files
We are given the following files:
Main python file super_secure_rsa.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#!/usr/bin/env python3
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from base64 import b64encode, b64decode
from flag import FLAG
# public key file name
PUB_FILE = 'pub.pem'
FLAG_FILE = 'flag.enc'
# convert key to pem format
def get_pem(key:rsa.RSAPrivateKey|rsa.RSAPublicKey):
# check the type of key, and create pem is respective format
if isinstance(key, rsa.RSAPublicKey):
pem = key.public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo)
else:
pem = key.private_bytes(encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption())
# return the key in pem format
return pem
# loads in a public key that is saved in PEM format
def load_public_key():
with open(PUB_FILE, 'rb') as pubf:
pubkey = serialization.load_pem_public_key(pubf.read(), backend=default_backend())
return pubkey
# encrypts a plaintext with the provided public key and returns the ciphertext encoded in base 64
def encrypt(pubkey:rsa.RSAPublicKey, ptxt:str) -> str:
# encrypt the flag using the public key
ctxt = pubkey.encrypt(ptxt.encode(), padding.PKCS1v15())
# return the encrypted flag in base 64
return b64encode(ctxt).decode()
# decrypts a ciphertext (encoded to base 64) with the provided private key and returns the decrypted string
def decrypt(privkey:rsa.RSAPrivateKey, ctxt:bytes) -> str:
# decode the ciphertext from base 64 and encrypt
ptxt = privkey.decrypt(b64decode(ctxt), padding.PKCS1v15())
# return the decrypted string
return ptxt.decode()
if __name__ == '__main__':
# Load in the key from PEM file
pub_key = load_public_key()
# save public key in PEM format to be printed out
pub_key_pem = get_pem(pub_key).decode()
# encrypt the flag using the public key
enc_flag = encrypt(pub_key, FLAG)
# write encrypted flag to file
with open('flag.enc', 'w') as f:
f.write(enc_flag)
Encrypted flag flag.enc
1
M1Qgcu5TJPojVpLreDXxEPctgYG7ZSXso0bIcPWeHsorU7Z5MDViiLPMTfCkdB0UtbdZeWNNzJ5EEtqk+nZjxQ==
Public key pub.pem
1
2
3
4
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAN8YoDOh4Na+z440/O5EZvcrDncG0R7R
bvb3vTn8l13js3CEfAMddkTpTs5xH6Iwi9XFyQnojLI/fS1Pw0CQMn8CAwEAAQ==
-----END PUBLIC KEY-----
Exploitation
The main objective is to recover the private key by extracting values from public key. Here are the steps I followed in order to read the flag:
Extract modulus
n
and exponente
from public keyFactorize
n
in order to get 2 primes numbersp
andq
(n = p*q
) - factor-dbCalculate
phi
withp
andq
(phi = (p-1)*(q-1)
)Build
d
, private exponantGet the private key
There is many ways to solve this challenge. Either exporting the private key and then using the
decrypt()
function from main file, or by decrypting ourselv the flag, or using openssl.. and probably more. Personally, I used the second one.
Flag
Here is my final script exploit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from Crypto.Util.number import inverse
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
from base64 import b64decode
public_key = RSA.importKey(open('pub.pem', 'r').read())
enc_flag = 'M1Qgcu5TJPojVpLreDXxEPctgYG7ZSXso0bIcPWeHsorU7Z5MDViiLPMTfCkdB0UtbdZeWNNzJ5EEtqk+nZjxQ=='
p = 106824314365456746562761668584927045312727977773444260463553547734415788806571
q = 109380489566403719014973591337211389488057388775161611283670009403393352513149
n = public_key.n
e = public_key.e
phi = (p-1)*(q-1)
d = inverse(e, phi)
key = RSA.construct((n, e, d))
# remove padding
cipher = PKCS1_v1_5.new(key)
sentinel = None
enc_flag = b64decode(enc_flag)
flag = cipher.decrypt(enc_flag, sentinel=sentinel)
print(flag)
#dam{4lw4y5_u53_l4r63_r54_k3y5}
🚩
dam{4lw4y5_u53_l4r63_r54_k3y5}
Thank’s for reading !