import gmpy from Crypto.Util.number import * from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5
flag = open('flag', 'r').read() * 30
defext_rsa_encrypt(p, q, e, msg): m = bytes_to_long(msg) whileTrue: n = p * q try: phi = (p - 1)*(q - 1) d = gmpy.invert(e, phi) pubkey = RSA.construct((long(n), long(e))) key = PKCS1_v1_5.new(pubkey) enc = key.encrypt(msg).encode('base64') return enc except: p = gmpy.next_prime(p**2 + q**2) q = gmpy.next_prime(2*p*q) e = gmpy.next_prime(e**2)
p = getPrime(128) q = getPrime(128) n = p*q e = getPrime(64) pubkey = RSA.construct((long(n), long(e))) f = open('pubkey.pem', 'w') f.write(pubkey.exportKey()) g = open('flag.enc', 'w') g.write(ext_rsa_encrypt(p, q, e, flag))
Looks like a simple RSA encryption there are some strange things hapening here like the While True look with a try catch and “open(‘flag’, ‘r’).read() * 30”, we will see why this happens later right now we need to get our modulus N and e from the pubkey.pem file:
fac: factoring 98099407767975360290660227117126057014537157468191654426411230468489043009977 fac: using pretesting plan: normal fac: no tune info: using qs/gnfs crossover of 95 digits
starting SIQS on c77: 98099407767975360290660227117126057014537157468191654426411230468489043009977
==== sieving in progress (10 threads): 36224 relations needed ==== ==== Press ctrl-c to abort and save state ====
SIQS elapsed time = 1.9290 seconds. Total factoring time = 2.0017 seconds
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5, PKCS1_OAEP from base64 import b64decode from Crypto.Hash import SHA from Crypto import Random import subprocess import sys
(.env)kinyabitch@Debian ~/h/c/a/c/r/RSA> python rsa2.py $(cat flag.enc | tr -d '\n') Traceback (most recent call last): File "rsa2.py", line 20, in <module>; print decrypt_RSA('priv.key', sys.argv[1]) File "rsa2.py", line 16, in decrypt_RSA decrypted = rsakey.decrypt(b64decode(message), None) File "/home/kinyabitch/ctf/asis-2016/ppc/SecuPrim/.env/local/lib/python2.7/site-packages/Crypto/Cipher/PKCS1_v1_5.py", line 204, in decrypt raise ValueError("Ciphertext with incorrect length.") ValueError: Ciphertext with incorrect length.
But we failed, incorrect length? remember this part of the code from server.py ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
flag = open('flag', 'r').read() * 30 whileTrue: n = p * q try: phi = (p - 1)*(q - 1) d = gmpy.invert(e, phi) pubkey = RSA.construct((long(n), long(e))) key = PKCS1_v1_5.new(pubkey) enc = key.encrypt(msg).encode('base64') return enc except: p = gmpy.next_prime(p**2 + q**2) q = gmpy.next_prime(2*p*q) e = gmpy.next_prime(e**2)
Yes the flag is being multiplied by 30 times so is going to be very big, and if you notice the try catch is used , so when an error occurs (length error) it updates our p,q and e getting the next primes!, so we had the wrong pubkey which only works for small cipher texts what we need to do here is to modify this encrypt script so we can get the next p,q,e with a very big string to make sure we can decrypt the original cipher text by simply modify our decrypt file
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5, PKCS1_OAEP from base64 import b64decode from Crypto.Hash import SHA from Crypto import Random import subprocess import sys