2
$\begingroup$

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:

  1. Get the OTP by using choice 1
  2. 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() ``` 
$\endgroup$
4
  • 1
    $\begingroup$ The hint could be related to weak keys in DES. Or not. $\endgroup$ Commented Aug 6, 2023 at 6:33
  • $\begingroup$ I thought about that as well, I have read some articles about them and as I understood with 4 specific keys I could obtain the same ciphertext as the plaintext. I have tried passing one of the keys suggested as weak to the program and proceed to obtain the encrypted flag. I obtained some bytes, but I do not think they are equal to the flag, they seem to be just random bytes.. $\endgroup$ Commented Aug 6, 2023 at 9:13
  • $\begingroup$ I edited the question and added my current approach which makes use of the weak keys to obtain the plaintext by the ciphertext, but the problem is that when I xor it with the otp I get in phase 1 I get random bytes, and I was expecting to get the flag, is there any error in the idea or is the problem in the implementation itself according to you? $\endgroup$ Commented Aug 6, 2023 at 10:07
  • $\begingroup$ You repeatedly assert(foo). Please don't do that. Better to simply assert foo. Then a maintenance engineer won't be tricked into "refactoring" as assert(foo, "diagnostic msg"), which means something very very different from assert foo, "diagnostic msg". $\endgroup$ Commented Aug 6, 2023 at 16:11

1 Answer 1

2
$\begingroup$

You seem to have gotten pretty far. Here are my musings.

spoiler: some keys can be weak

$ nc desoracle.challs.cyberchallenge.it 9035 1. Encrypt text 2. Encrypt flag 0. Exit > 2 What key do you want to use (in hex)? FEFEFEFEFEFEFEFE 4bbe3dbd2af198110b1dba3b8be427a53119b02e2c9872687846c3058a225f77 1. Encrypt text 2. Encrypt flag 0. Exit > 1 What do you want to encrypt (in hex)? 4bbe3dbd2af198110b1dba3b8be427a53119b02e2c9872687846c3058a225f77 With what key (in hex)? FEFEFEFEFEFEFEFE 434349547b35306d335f6b3379355f63346e5f62335f7733346b7df1bd443636b5c08a964c2193be 1. Encrypt text 2. Encrypt flag 0. Exit > 0 
>>> enc = '434349547b35306d335f6b3379355f63346e5f62335f7733346b7d447622cbd9c695f42387476e51' >>> >>> vals = [int(enc[i:i+2], 16) for i in range(0, len(enc), 2)] >>> >>> ''.join(map(chr, vals)) 

'CCIT{50m3_k3y5_c4n_b3_w34k}Dv"ËÙÆ\x95ô#\x87GnQ'

Repeating it with another weak key, 0101010101010101, leads to this:

>>> enc = '434349547b35306d335f6b3379355f63346e5f62335f7733346b7d447622cbd9c695f42387476e51' >>> enc = '434349547b35306d335f6b3379355f63346e5f62335f7733346b7d3877318cc695d6d51f0502ef03' >>> vals = [int(enc[i:i+2], 16) for i in range(0, len(enc), 2)] >>> ''.join(map(chr, vals)) 

'CCIT{50m3_k3y5_c4n_b3_w34k}8w1\x8cÆ\x95ÖÕ\x1f\x05\x02ï\x03'

Looks like a 27-byte Flag, as confirmed by the asserts.

EDIT

Whoops, no need for the list comprehension, as this suffices:

import codecs print(codecs.decode(enc, 'hex')) 
$\endgroup$
2
  • 1
    $\begingroup$ Ok so basically your approach is a bit different. You first get the encrypted flag, and then try to encrypt the encrypted flag (which is still the same since we are using a weak key). It works because the xor done in the first phase is re-made in the second phase re-transforming the text to the original flag. Is this correct? In any case chapeau and thank you :) $\endgroup$ Commented Aug 6, 2023 at 18:29
  • $\begingroup$ Yes, that's right. We exploit that the 2nd encrypt acts as decrypt for a weak key. Suppose the use of weak keys is prohibited. I wonder if this approach could be extended to use a related pair of semi-weak keys. If so, feel free to post an Answer. $\endgroup$ Commented Aug 6, 2023 at 19:14

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.