Flash CTF – Key For Me

Overview

This challenge has us generating a key to activate our access to the flag. We have a single python function that validates the input key, so that’s the one we need to bypass.

The function in question

def check_key(key):

    if len(key) != 8 or ord(key[0]) % 5 != 3 or ord(key[1]) % 4 != 2 or not key[2].isdigit() or not key[3].islower() or not ord(key[4]) <= ord(key[3]) + 5 or not key[5].isdigit() or int(key[5]) <= int(key[2]) + 2 or not key[6].islower() or ord(key[6]) >= ord(key[3]) - 3 or not key[7].isupper() or ord(key[7]) >= ord(key[4]) - 4:
        return False
    return True

Put simply, this function is just checking various positions of the key to see if they match certain requirements. We can write it down better as follows:

def check_key(key):
    # Check if the key length is exactly 8 characters
    if len(key) != 8:
        return False
    
    # Check if the ASCII value of the first character modulo 5 equals 3
    if ord(key[0]) % 5 != 3:
        return False
    
    # Check if the ASCII value of the second character modulo 4 equals 2
    if ord(key[1]) % 4 != 2:
        return False
    
    # Check if the third character is a digit
    if not key[2].isdigit():
        return False
    
    # Check if the fourth character is a lowercase letter
    if not key[3].islower():
        return False
    
    # Check if the ASCII value of the fifth character is less than or equal to the ASCII value of the fourth character plus 5
    if not ord(key[4]) <= ord(key[3]) + 5:
        return False
    
    # Check if the sixth character is a digit
    if not key[5].isdigit():
        return False
    
    # Check if the integer value of the sixth character is greater than the integer value of the third character plus 2
    if int(key[5]) <= int(key[2]) + 2:
        return False
    
    # Check if the seventh character is a lowercase letter
    if not key[6].islower():
        return False
    
    # Check if the ASCII value of the seventh character is less than the ASCII value of the fourth character minus 3
    if ord(key[6]) >= ord(key[3]) - 3:
        return False
    
    # Check if the eighth character is an uppercase letter
    if not key[7].isupper():
        return False
    
    # Check if the ASCII value of the eighth character is less than the ASCII value of the fifth character minus 4
    if ord(key[7]) >= ord(key[4]) - 4:
        return False
    
    return True

Solve

We could manually go and meet all of these requirements, but instead let’s save ourself the effort and write a quick python script that generates as many keys as we could ever want:

import random
import string

def check_key(key):

    if len(key) != 8 or ord(key[0]) % 5 != 3 or ord(key[1]) % 4 != 2 or not key[2].isdigit() or not key[3].islower() or not ord(key[4]) <= ord(key[3]) + 5 or not key[5].isdigit() or int(key[5]) <= int(key[2]) + 2 or not key[6].islower() or ord(key[6]) >= ord(key[3]) - 3 or not key[7].isupper() or ord(key[7]) >= ord(key[4]) - 4:
        return False
    return True

def crack_key():
    while True:
        key = [None] * 8

        # Generate key[0] such that ord(key[0]) % 5 == 3
        key[0] = chr(random.choice([i for i in range(256) if i % 5 == 3]))

        # Generate key[1] such that ord(key[1]) % 4 == 2
        key[1] = chr(random.choice([i for i in range(256) if i % 4 == 2]))

        # Generate key[2] as a digit and ensure valid key[5]
        while True:
            key[2] = random.choice(string.digits)
            if any(i > int(key[2]) + 2 for i in range(10)):
                break

        # Generate key[3] as a lowercase letter and ensure valid key[6]
        while True:
            key[3] = random.choice(string.ascii_lowercase)
            if any(ord(c) < ord(key[3]) - 3 for c in string.ascii_lowercase):
                break

        # Generate key[4] such that ord(key[4]) <= ord(key[3]) + 5 and allows valid key[7]
        while True:
            key[4] = chr(random.choice([i for i in range(256) if i <= ord(key[3]) + 5]))
            if any(ord(c) < ord(key[4]) - 4 for c in string.ascii_uppercase):
                break

        # Generate key[5] as a digit and int(key[5]) > int(key[2]) + 2
        key[5] = random.choice([str(i) for i in range(10) if i > int(key[2]) + 2])

        # Generate key[6] as a lowercase letter and ord(key[6]) < ord(key[3]) - 3
        key[6] = random.choice([c for c in string.ascii_lowercase if ord(c) < ord(key[3]) - 3])

        # Generate key[7] as an uppercase letter and ord(key[7]) < ord(key[4]) - 4
        key[7] = random.choice([c for c in string.ascii_uppercase if ord(c) < ord(key[4]) - 4])

        key = ''.join(key)

        if check_key(key):
            return key

while True:
    key = crack_key()
    valid = check_key(key)
    print(f"{key} - {valid}")

Running our keygen will give us thousands of keys!

ó¦3vQ9iE - True
b&2uV6cF - True
æ1jK7fD - True
?Æ2wK9oC - True
²Z2gf8cZ - True
º5oH8eC - True
Ë2xe5rU - True
+Ò0fG3bB - True
ø2rJ5fA - True
Dn6sc9lN - True
Nö5wU8rG - True
!B5wQ8oD - True
:2nY9hM - True
5v4qo8hK - True
â1oi6bI - True
£â5zV8hD - True
&64ub9fE - True

Using any one of them solves the challenge and gets us the flag!

nc kubenode.mctf.io 30008

 MetaCTF Key Validation System
      _____
     /   _ \__.--._._--.-_
    |   |_| ______________\
     \_____/

Enter your activation key: Nö5wU8rG
Congratulations! You unlocked the door, here's your prize: MetaCTF{wh0_n33ds_l0ckp1ck5_wh3n_y0u_own_th3_k3y_f4ct0y}

Flag

MetaCTF{wh0_n33ds_l0ckp1ck5_wh3n_y0u_own_th3_k3y_f4ct0y}