I am trying to solve a CTF challenge based on DES. I attached the code of the challenge to the question. So far I have noticed that the otp used for the encryption is the same for the entire session, and my idea would be the following:
- Get the OTP by using choice 1
- Use the obtained OTP to decrypt the ciphertext given by choice 2 (since I pass the key)
I tried to implement this process and haven't managed to get the flag. Given that the hint of the challenge is the following:
Not all keys are strong alike.
Do you think that I am on the right track or do you have any proposal on how I could approach the problem? Thank you in advice.
Code of the challenge:
#!/usr/bin/env python3 import signal from Crypto.Cipher import DES from Crypto.Util.Padding import pad from Crypto.Util.number import bytes_to_long import os TIMEOUT = 300 assert("FLAG" in os.environ) flag = os.environ["FLAG"] assert(flag.startswith("CCIT{")) assert(flag.endswith("}")) otp = os.urandom(8) def xor(a, b): return bytes([a[i % len(a)] ^ b[i % len(b)] for i in range(max(len(a), len(b)))]) def encrypt_des(text, key): try: key = bytes.fromhex(key) text = xor(bytes.fromhex(text), otp) cipher = DES.new(key, DES.MODE_ECB) ct = xor(cipher.encrypt(pad(text, 8)), otp) return ct.hex() except Exception as e: return f"Something went wrong: {e}" def handle(): while True: print("1. Encrypt text") print("2. Encrypt flag") print("0. Exit") choice = int(input("> ")) if choice == 1: text = input("What do you want to encrypt (in hex)? ").strip() key = input("With what key (in hex)? ").strip() print(encrypt_des(text, key)) elif choice == 2: key = input("What key do you want to use (in hex)? ").strip() print(encrypt_des(flag.encode().hex(), key)) else: break if __name__ == "__main__": signal.alarm(TIMEOUT) handle() My current approach:
from pwn import * from Crypto.Cipher import DES from Crypto.Util.Padding import pad, unpad import warnings warnings.filterwarnings("ignore") r = remote('desoracle.challs.cyberchallenge.it', 9035) r.recvuntil('>') # First we want to get the OTP r.sendline('1') myText = b'This is my cool text'.hex() r.recvuntil('(in hex)?') r.sendline(myText) myKey = "FEFEFEFEFEFEFEFE" #this is one of the four weak keys print(myKey) r.recvuntil('(in hex)?') r.sendline(myKey) output = r.recvline().strip().decode() outputInBytes = bytes.fromhex(output) otp = xor(bytes.fromhex(myText), outputInBytes) print(otp) r.recvuntil('>') r.sendline('2') myKey = "FEFEFEFEFEFEFEFE" #this is one of the four weak keys r.recvuntil('(in hex)?') r.sendline(myKey) output = r.recvline().strip().decode() paddedFlagAfterXor = bytes.fromhex(output) flag = xor(paddedFlagAfterXor, otp) print(flag.decode()) r.interactive() ```
assert(foo). Please don't do that. Better to simplyassert foo. Then a maintenance engineer won't be tricked into "refactoring" asassert(foo, "diagnostic msg"), which means something very very different fromassert foo, "diagnostic msg". $\endgroup$