dCTF - Just Take Your Time
Over the weekend I participated in dCTF by DragonSec SI along with some friends. There were some really interesting and unique challenges in this CTF.
May 17, 2021
• 2 min read
Over the weekend I participated in dCTF by DragonSec SI along with some friends. There were some really interesting and unique challenges in this CTF.
Summary This was a time-restricted python crypto challenge served over a socket. The first part was to solve a simple maths equation within two seconds. The second part was cracking a triple DES cipher that was initialized using time as the key, also within a two-second time limit.
Challenge Source #!/usr/bin python3
from flag import flag
from Crypto.Cipher import DES3
from time import time
from random import randint
from secrets import token_hex
from pytimedinput import timedInput
guess = 3
TIMEOUT = 2
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 = 2, 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)
The challenge source code Solution The following solution uses pwntools to handle the connection to the server. The crux of the solution comes down to getting the same value for int(time())
as the server. Initially, I thought this could be problematic; however, I found it was correct when running the solution on the first attempt.
from pwn import *
from Crypto.Cipher import DES3
from time import time
def solve_maths(equ):
a,b = equ.split('=')[0].replace(' ','').split('*')
return int(a)*int(b)
def decrypt(t1, ct):
key = str(t1).zfill(16).encode("utf-8")
cipher = DES3.new(key, DES3.MODE_CFB, b"00000000")
return cipher.decrypt(bytes.fromhex(ct))
c = remote('dctf-chall-just-take-your-time.westeurope.azurecontainer.io', 9999)
c.recvline()
equ = c.recvline()
print('Equ: {}'.format(equ))
solution = solve_maths(equ.decode("utf-8"))
print('Sol: {}'.format(solution))
t1 = int(time())
print('Time: {}'.format(t1))
c.sendline(str(solution))
if 'capable' not in c.recvline().decode("utf-8"):
print('Failed...')
exit()
ct = c.recvline().strip().decode("utf-8")
print('CT: {}'.format(ct))
for t in range(t1, t1+3):
secret = decrypt(t, ct).decode("utf-8")
print('Attempt: {} - {} - {}'.format(t, ct, secret))
c.sendline(secret)
if 'wrong' in c.recvline().decode("utf-8"):
print('Wrong...')
else:
break
c.interactive()
The source code of one possible solution Running this gives the following:
The solution in action So now we have the flag, woo!
dctf{1t_0n1y_t0Ok_2_d4y5...}