El siguiente contenido esta protegido por contraseña Javascript needs to be enabled to decrypt content Archivos proporcionados flag.txt.aes: fichero cifrado con AES. key: fichero con la clave de AES cifrado con RSA pubkey.pem: clave pública con la que se cifró el fichero key. Obtención de la clave privada En casos normales en los la clave para RSA está bien creada, no debería de ser posible la obtención de la clave privada a partir de la pública. Sin embargo, ya que este reto es planteado para ser resuelto, lo más lógico es pensar que de los tres ficheros proporcionados habrá que comenzar por pubkey.pem. Siguiendo la suposición previa, en primer lugar sacamos de la clave pública los números e y n. e = 65537 n = 1128137999850045612492145429133282716267233566834715456536184965477269592934207986950131365518741418540788596074115883774105736493742449131477464976858161587355643311888741515506653603321337485523828144179637379528510277430032789458804637543905426347328041281785616616421292879871785633181756858096548411753919440011378411476275900648915887370219369154688926914542233244450724820670256654513052812215949495598592852131398736567134556141744727764716053145639513031 Tras saber estos dos números, probaremos a factorizar n. En condiciones normales la factorización de un número tan grande sería algo inviable computacionalmente hablando, pero si este reto tiene solución, es una opción que es lógica considerar. Para la factorización de este número pueden utilizarse diversos métodos, pero en este caso utilizamos una herramienta online llamada FactorDb. Tras factorizarlo obtenemos que n en realidad no es el producto de dos primos p y q sino que es el cubo de un primo. $$n = p^3$$ Por lo tanto ya podemos calcular la phi de Euler. $$\varphi(n) = p^2 * (p-1)$$ Con esto podemos calcular la clave privada con la que descifrar el archivo key. Para obtener la d tenemos que calcular la inversa multiplicativa modular de e y de $\varphi(n)$. Para ello podemos utilizar la función inverse de Crypto.Util.number. from Crypto.Util.number import inverse inverse(e, phi) Resolución Una vez obtenida la d ya podemos descifrar el archivo key ( $M = C^d\bmod n$ ). Y tras descifrar el archivo key, tenemos la clave para descifrar el archivo flag.txt.aes. Script A continuación se muestra un pequeño script en python para la resolución del problema. from Crypto.Util.number import bytes_to_long, long_to_bytes, inverse from Crypto.PublicKey import RSA from Crypto.Cipher import AES from gmpy2 import iroot def get_private(pub): n = pub.n e = pub.e # n = p**3 p = int(iroot(n,3)[0]) phi = (p**2) * (p - 1) return inverse(e, phi) def decrypt_rsa(c, d, n): result = 1 while d 0: if (d & 1) 0: result = (result*c) % n d = 1 c = c**2 % n return result def decrypt_aes(k, c): aes = AES.new(k, AES.MODE_ECB) return aes.decrypt(c) if __name__ == '__main__': # Open challenge files with open('pubkey.pem') as f: pub = RSA.import_key(f.read()) with open('key') as f: k = bytes.fromhex(f.read()) with open('flag.txt.aes', 'rb') as f: c = f.read() c = c[:-1] # Solve challenge d = get_private(pub) k = bytes_to_long(k) k = long_to_bytes(decrypt_rsa(k, d, pub.n)) flag = decrypt_aes(k,c).decode() # Print results print(f'RSA Private Key: {d}\n') print(f'Unciphered "key" file: {k}\n') print(f'Unciphered "flag.txt.aes" file: {flag}') Flag HTB{pl4y1ng_w1th_pr1m3s_1s_fun!} div#hugo-encrypt-sha1sum {display: none;} const storageKey = location.pathname + "password"; const userStorage = localStorage ; function str2buf(str) { return new TextEncoder("utf-8").encode(str); } function buf2str(buffer) { return new TextDecoder("utf-8").decode(buffer); } function hex2buf(hexStr) { return new Uint8Array(hexStr.match(/.{2}/g).map(h = parseInt(h, 16))); } function deriveKey(passphrase, salt) { salt = salt || crypto.getRandomValues(new Uint8Array(8)); return crypto.subtle .importKey("raw", str2buf(passphrase), "PBKDF2", false, ["deriveKey"]) .then(key = crypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: 1000, hash: "SHA-256" }, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"], ), ) .then(key = [key, salt]); } function decrypt(passphrase, saltIvCipherHex) { const [salt, iv, data] = saltIvCipherHex.split("-").map(hex2buf); return deriveKey(passphrase, salt) .then(([key]) = crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, data)) .then(v = buf2str(new Uint8Array(v))); } async function digestMessage(message) { const msgUint8 = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest('SHA-1', msgUint8); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray.map(b = b.toString(16).padStart(2, '0')).join(''); return hashHex; } const hugoDecrypt = function(password, type) { for (const cipher of ciphers) { decrypt(password, cipher.innerText).then(function(decrypted_text) { digestMessage(decrypted_text.replace(/\r?\n?[^\r\n]*$/, "")).then(function(sha1_sum) { if ( decrypted_text.includes(sha1_sum) ) { document.getElementById("hugo-encrypt-encryption-notice").remove(); cipher.outerHTML = decrypted_text; userStorage.setItem(storageKey, password); document.getElementById("hugo-encrypt-sha1sum").innerHTML = "Success: " + sha1_sum; console.log("Decryption successful. Storing password in Storage."); MathJax.Hub.Typeset(); code_copy_bttn(); } }); }).catch(function(error) { if (type === "input") { document.getElementById("hugo-encrypt-input-response").innerHTML = "La contraseña es incorrecta"; console.log('La contraseña es incorrecta', error); } else if (type === "storage") { userStorage.removeItem(location.pathname + "password"); console.log("Password changed. Clearing userStorage.", error); } }); } }; window.onload = () = { ciphers = Array.from(document.querySelectorAll("cipher-text")); if (userStorage.getItem(storageKey)) { console.log("Found storageKey in userStorage. Attemtping decryption"); hugoDecrypt(userStorage.getItem(storageKey), "storage"); } };