Description
Can you abuse the oracle? An attacker was able to intercept communications between a bank and a fintech company. They managed to get the message (ciphertext) and the password that was used to encrypt the message. After some intensive reconassainance they found out that the bank has an oracle that was used to encrypt the password and can be found here nc titan.picoctf.net 62026. Decrypt the password and use it to decrypt the message. The oracle can decrypt anything except the password.
Setup
Download secret.enc (the message) and password.enc (the RSA ciphertext).
Interact with the oracle at titan.picoctf.net 62026 to encrypt a chosen value and decrypt manipulated ciphertexts.
wget https://artifacts.picoctf.net/c_titan/148/secret.enc && \
wget https://artifacts.picoctf.net/c_titan/148/password.enc && \
nc titan.picoctf.net 62026Solution
- Step 1Encrypt a small multiplierAsk the oracle to encrypt the value 2. The result (c_a) will later be multiplied with the captured password ciphertext (c).
E → 0x02Learn more
This challenge exploits the multiplicative homomorphism of textbook RSA. In RSA, encryption is defined as
c = m^e mod n. A critical mathematical property follows: if you encrypt two messages separately and multiply their ciphertexts together, the result equals the encryption of the product of the plaintexts -Enc(a) * Enc(b) = Enc(a * b) mod n.An RSA oracle is a service that will encrypt or decrypt values on your behalf. This one refuses to decrypt the specific ciphertext
c(the captured password), but it will decrypt any other value. By asking it to encrypt the small constant2, you obtainc_a = 2^e mod n, which you can then multiply withcto create a new ciphertext that the oracle will willingly decrypt.This class of attack is called a chosen-ciphertext attack (CCA). Real RSA implementations use OAEP padding (PKCS#1 v2.1) specifically to prevent it - padding randomizes the message so the homomorphic property no longer holds in a useful way.
- Step 2Multiply and decryptSubmit c * c_a to the decrypt endpoint. The oracle refuses to decrypt the original password, but this scaled ciphertext is acceptable. Convert the hex response to an integer and divide by 2 to recover the password.
p.sendline(str(c_a * c).encode())Learn more
When you submit
c_a * c mod nto the oracle, it decrypts it to get2 * password mod n(by the homomorphic property). Dividing that result by 2 yields the original plaintext password. This is a textbook RSA blinding attack- you "blind" the forbidden ciphertext by multiplying it with a known factor, get the oracle to do the decryption, then "unblind" by dividing.The oracle's blacklist only checks for the exact ciphertext value
c. By multiplying byc_a, you produce a numerically different ciphertext that passes the blocklist check but still encodes information about the original message.- The response comes back as a hex integer - convert with
int(response, 16). - Integer division by 2 works because the blinding factor was exactly 2 and all arithmetic is over integers, not a field.
- In a proper RSA-OAEP implementation this trick does not work because padding bytes make the resulting plaintext garbage.
- The response comes back as a hex integer - convert with
- Step 3Use the recovered passwordFeed the plaintext password to OpenSSL to decrypt secret.enc and reveal the flag.
openssl enc -aes-256-cbc -d -in secret.encExample automation script: from pwn import * context.log_level = 'critical' p = remote("titan.picoctf.net", 62026) with open("password.enc") as f: c = int(f.read()) p.sendline(b"E") p.sendline(b"\x02") c_a = int(p.recvline()) p.sendline(b"D") p.sendline(str(c_a * c).encode()) password = int(p.recvline(), 16) // 2 print(password.to_bytes((password.bit_length()+7)//8, 'big').decode())Learn more
openssl encis the symmetric encryption/decryption command. The flags used here specify AES-256 in CBC mode (-aes-256-cbc), decryption mode (-d), and the input file (-in secret.enc). OpenSSL will prompt for the password, which you recovered in the previous step.AES-256-CBC is a well-regarded symmetric cipher. Unlike RSA, it is not vulnerable to mathematical attacks - its security relies entirely on the secrecy of the key (here, derived from the password). This two-layer approach - RSA to protect the symmetric key, symmetric encryption for the bulk data - is called hybrid encryption and is the foundation of TLS, PGP, and most real-world secure communication protocols.
The pwntools Python library used in the automation script is the standard CTF toolkit for interacting with remote services.
remote(host, port)opens a TCP connection, andsendline/recvlinehandle communication. It vastly simplifies writing exploit scripts compared to raw socket code.
Alternate Solution
After recovering the plaintext password via the blinding attack, use the RSA Calculator on this site to perform manual RSA decryption and verify intermediate values - enter n, e, and the manipulated ciphertext to confirm the homomorphic computation before submitting.
Flag
picoCTF{su((3ss_(r@ck1ng_r3@_24bc...}
Decrypting secret.enc with the recovered password yields the flag above.