Write up for UTCTF 2024 - Crypto/Cryptordle
Challenge
Just guess the word in 6 tries. What do you mean it’s hard?
#!/usr/bin/env python3
import random
wordlist = open('/src/wordlist.txt', 'r').read().split('\n')
for word in wordlist:
assert len(word) == 5
for letter in word:
assert letter in 'abcdefghijklmnopqrstuvwxyz'
for attempt in range(3):
answer = random.choice(wordlist)
num_guesses = 0
while True:
num_guesses += 1
print("What's your guess?")
guess = input().lower()
assert len(guess) == 5
for letter in guess:
assert letter in 'abcdefghijklmnopqrstuvwxyz'
if guess == answer:
break
response = 1
for x in range(5):
a = ord(guess[x]) - ord('a')
b = ord(answer[x]) - ord('a')
response = (response * (a-b)) % 31
print(response)
if num_guesses > 6:
print("Sorry, you took more than 6 tries. No flag for you :(")
exit()
else:
print("Good job! Onward...")
if num_guesses <= 6:
print('Nice! You got it :) Have a flag:')
flag = open('/src/flag.txt', 'r').read()
print(flag)
else:
print("Sorry, you took more than 6 tries. No flag for you :(")
Expalin
This is a similar problem to the “Wordle” game. I adopted a method of reducing candidates based on a word list. However, this does not guarantee complete success.
Solve
import random
from pwn import *
r = remote("betta.utctf.live", 7496)
with open("wordlist.txt", 'r') as f:
wordlist = f.read().split()
def calc_response(word1, word2):
response = 1
for x in range(5):
a = ord(word1[x]) - ord('a')
b = ord(word2[x]) - ord('a')
response = (response * (a-b)) % 31
return response
for i in range(3):
candidates = wordlist
while True:
word = random.choice(candidates)
r.recvuntil(b"What's your guess?\n")
r.sendline(bytes(word, "utf-8"))
response = r.recvline()[:-1]
if str(response, "utf-8").find("Good job! Onward...") != -1:
break
elif str(response, "utf-8").find("Sorry, you took more than 6 tries. No flag for you :(") != -1:
exit()
response = int(response)
temp_candidates = []
for w in candidates:
if calc_response(word, w) == response:
temp_candidates.append(w)
candidates = temp_candidates
r.recvuntil(b"Nice! You got it :) Have a flag:\n")
print(str(r.recvline(), "utf-8")[:-1])
❯ python3 utctf_Cryptordle.py
[+] Opening connection to betta.utctf.live on port 7496: Done
utflag{sometimes_pure_guessing_is_the_strat}
[*] Closed connection to betta.utctf.live port 7496