# Solution for dCTF 2021 Challenge "Just Take Your Time" (Crypto)## Challenge Description
Let's go. In and out. 2 second adventure.```nc dctf-chall-just-take-your-time.westeurope.azurecontainer.io 9999```While this may not be pwn, its tools may still be quite handy.
### Provided Python Code```#!/usr/bin python3
from flag import flagfrom Crypto.Cipher import DES3from time import timefrom random import randintfrom secrets import token_hexfrom pytimedinput import timedInput
guess = 3TIMEOUT = 1
a = randint(1000000000000000, 9999999999999999)b = randint(1000000000000000, 9999999999999999)
print("Show me you are worthy and solve for x! You have one second.")print("{} * {} = ".format(a, b))
answ, _ = timedInput("> ", timeOut = 1, forcedTimeout = True)
try:    assert(a*b == int(answ))except:    print("You are not worthy!")    exit(1)
key = str(int(time())).zfill(16).encode("utf-8")secret = token_hex(16)cipher = DES3.new(key, DES3.MODE_CFB, b"00000000")encrypted = cipher.encrypt(secret.encode("utf-8"))print("You have proven yourself to be capable of taking on the final task. Decrypt this and the flag shall be yours!")print(encrypted.hex())
start_time = time()while(time() - start_time < TIMEOUT and guess > 0):    delta = time() - start_time    answ, _ = timedInput("> ", timeOut = TIMEOUT + 1 - delta, forcedTimeout = True)
    try:        assert(secret == answ)        break    except:        if answ != "":            guess -= 1            if (guess != 1):                print("You are wrong. {} guesses remain.".format(guess))            else:                print("You are wrong. {} guess remains.".format(guess))
if (secret != answ):    print("You have been unsuccessful in your quest for the flag.")else:    print("Congratulations! Here is your flag.")    print(flag)```## Solution OverviewTo solve this challenge, we need 3 steps:
1. Write code for network service interaction: read from remote, and send data as a response.2. Add code to calculate multiplication result from the intercepted numbers (solve task 1)3. Add code to decrypt the ciphertext with 3DES (CFB mode, IV=b"00000000") and a timestamp-based key (solve task 2)
Due to a time-out condition, we need to automate the response by writing a script. Before starting to code the script, lets look at the tasks separately to fully understand each.
Language choice: Python3
This way we can re-use code fragments provided with the challenge.
### 1. Network Service Interaction - Connect to remote service and parse output
The manual network connection test:
```fm@NUC7:~$ nc dctf-chall-just-take-your-time.westeurope.azurecontainer.io 9999Show me you are worthy and solve for x! You have one second.3431802513119313 * 8053949562118619 => You are not worthy!```Now we do the same under Python:
```fm@NUC7:~$ python3Python 3.8.5 (default, Jan 27 2021, 15:41:15)>>> import socket>>> remotehost = "dctf-chall-just-take-your-time.westeurope.azurecontainer.io">>> remoteport = 9999>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)>>> connect = s.connect((remotehost, remoteport))>>> remoteout = str(s.recv(1024).decode("utf-8"))>>> remotelines = remoteout.splitlines();>>> print(remotelines[1])7030601571755451 * 1909787585147146 =```
### 2. Solve the first service challenge - Multiply two random 16-digit numbers
```fm@NUC7:~$ python3Python 3.8.5 (default, Jan 27 2021, 15:41:15)[GCC 9.3.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> from random import randint>>> a = randint(1000000000000000, 9999999999999999)>>> b = randint(1000000000000000, 9999999999999999)>>> print("{} * {} = ".format(a, b))3748747587965172 * 1830956562823976 =```To resolve, we simply multiply and return it:
```>>> a*b6863793998555381943399854563872```
### 3. Decrypt the service ciphertext
Per challenge code, a 16-char key string is generated, containing the current timestamp prefixed with zeros.
```fm@NUC7:~$ python3Python 3.8.5 (default, Jan 27 2021, 15:41:15)>>> from time import time>>> key = str(int(time())).zfill(16).encode("utf-8")>>> print(key)b'0000001621051737'```A random 16-char text string is generated, displayed in hexadecimal.
```fm@NUC7:~$ python3Python 3.8.5 (default, Jan 27 2021, 15:41:15)>>> from secrets import token_hex>>> secret = token_hex(16)>>> print(secret)bb775e5e11abc3ea28967061fc1957f1```The random secret string gets Triple-DES encrypted in CFB mode, using the timestamp key. CFB mode turns the block cipher into a stream cipher. Each byte of plaintext is XOR-ed with a byte taken from a keystream: the result is the ciphertext. IV is set to b"00000000".
```fm@NUC7:~$ python3Python 3.8.5 (default, Jan 27 2021, 15:41:15)>>> from Crypto.Cipher import DES3>>> cipher = DES3.new(key, DES3.MODE_CFB, b"00000000")>>> encrypted = cipher.encrypt(secret.encode("utf-8"))>>> print(encrypted)b'b\xf1\x7f\x1d|%\xe3\xf4\x0f\xb0\xdaS\xed\x0fM\x17\x99;\x86\x8e\x04Ds\xb1`\xfbF\x12\xd6\xe6\xa8\xcb'>>> print(encrypted.hex())62f17f1d7c25e3f40fb0da53ed0f4d17993b868e044473b160fb4612d6e6a8cb```So, to solve it we need to decrypt the provided ciphertext and return the original 'secret' string, using a timestamp as the key. This will be the decryption part:
```fm@NUC7:~$ python3Python 3.8.5 (default, Jan 27 2021, 15:41:15)>>> from binascii import unhexlify>>> from Crypto.Cipher import DES3>>> ciphertext = "62f17f1d7c25e3f40fb0da53ed0f4d17993b868e044473b160fb4612d6e6a8cb">>> key = b'0000001621051737'>>> cipher = DES3.new(key, DES3.MODE_CFB, b"00000000")>>> cleartext = cipher.decrypt(unhexlify(ciphertext))>>> print(cleartext.decode("utf-8"))bb775e5e11abc3ea28967061fc1957f1```
### Final Solve
```fm@NUC7:~$ ./jtyt-solve.pydebug remote output:Show me you are worthy and solve for x! You have one second.2904958076352217 * 4432329690179776 =>
debug number extract: 1=2904958076352217 2=4432329690179776debug multiplication: 12875731930543460049557026163392debug remote output:You have proven yourself to be capable of taking on the final task. Decrypt this and the flag shall be yours!f0199fa6054cd2a677967b4fb135a60cd832d370c830d7376613fc254eaf5ac2>
debug cipher extract: enc=f0199fa6054cd2a677967b4fb135a60cd832d370c830d7376613fc254eaf5ac2debug decryption key: key=0000001621068036debug show cleartext: clr=c5a84a46f94e7065ac8fdd0410747466debug remote output:Congratulations! Here is your flag.dctf{1t********************}```
### Code Listing```fm@NUC7:~$ cat jtyt-solve.py#!/usr/bin/python3import socketfrom time import timefrom Crypto.Cipher import DES3from binascii import unhexlify
remotehost = "dctf-chall-just-take-your-time.westeurope.azurecontainer.io"remoteport = 9999
# Connect to the remote side and capture the outputs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)connect = s.connect((remotehost, remoteport))output1 = str(s.recv(1024).decode("utf-8"))print("debug remote output:\n" + output1 + "\n")
# Parse and process the output to calculate result 1remotelines = output1.splitlines();num1 = remotelines[1].split()[0];num2 = remotelines[1].split()[2];print("debug number extract: 1=" + num1 + " 2=" + num2)result1 = str(int(num1) * int(num2))print("debug multiplication: " + result1)
# Send result to remote side, and check responses.send(bytearray(result1 + "\n", 'utf-8'))output2 = str(s.recv(1024).decode("utf-8"))print("debug remote output:\n" + output2 + "\n")
# Parse and process the output to calculate result 2remotelines = output2.splitlines();enc = remotelines[1];print("debug cipher extract: enc=" + enc)
# Generate the decryption key based on the timestampkey = str(int(time())).zfill(16).encode("utf-8")print("debug decryption key: key=" + str(key.decode("utf-8")))
# Decrypt the ciphertextcipher = DES3.new(key, DES3.MODE_CFB, b"00000000")cleartext = str(cipher.decrypt(unhexlify(enc)).decode("utf-8"))print("debug show cleartext: clr=" + cleartext)
# Sent decryption result to remote, and check for flags.send(bytearray(cleartext + "\n", 'utf-8'))output3 = str(s.recv(1024).decode("utf-8"))print("debug remote output:\n" + output3 + "\n")```