Challenge Overview

Challenge Name Category Difficulty Link
Sekur Julius Crypto Very Easy Link to Challenge

Description

Hidden deep in the forest was an ancient scroll, rumored to grant immense power to anyone who could read its shifting symbols. On Halloween, a curious traveler found the scroll, its letters strangely out of order. As they deciphered the message, the words slowly rearranged themselves, revealing a dark spell. But with the final shift, the traveler felt a cold presence behind them, whispering, "You were never meant to understand." The forest grew silent, but the spell was already cast.

An image to describe post

Process

Upon downloading the assistive ZIP file, I found two files: output.txt and source.py.

Contents of output.txt

LTARDBT0ID0WPRZIWTQDD0ILDIWDJHPCSILTCINUDJG!

0IWXH0XH0P0EGDDU0DU0RDCRTEI0ID0EGDKT0NDJ0IWPI0IWT0RPTHPG0RXEWTG0XH0XCHTRJGT0CD0BPIITG0WDL0BPCN0IXBTH0NDJ0PEEAN0XI.
0IWT0HTRJGXIN0DU0P0IWDJHPCS0SXHIXCRI0HWXUIH0XH0TKTCIJPAAN0IWT0HPBT0PH0IWPI0DU0P0HXCVAT0HWXUI.
0TCDJVW0BJBQAXCV,0IPZT0NDJG0UAPV0PCS0TCYDN0IWT0GTHI0DU0IWT0RDCITHI.
0BPZT0HJGT0NDJ0LGPE0IWT0UDAADLXCV0ITMI0LXIW0IWT0WIQ0UAPV0UDGBPI0HTRJGXINDUPIWDJHPCSDGHTRJGXINDUPHXCVAT.

Contents of source.py

from random import choices 

def julius_encrypt(msg, shift): 
	ct = ''
	for p in msg:
		if p == ' ':
			ct += '0'
		elif not ord('A') <= ord(p) <= ord('Z'): 
			ct += p 
		else:
			o = ord(p) - 65
				ct += chr(65 + (o + shift) % 26) return ct 
				
def encrypt(msg, key): 
	for shift in key: 
		msg = julius_encrypt(msg, shift) 
	return msg 
	
msg = open('secret.txt').read().upper() secure_key = os.urandom(1337) 

with open('output.txt', 'w') as f: f.write(encrypt(msg, secure_key))

Encryption Code Breakdown

  1. julius_encrypt Function (Caesar Cipher)

    • The julius_encrypt function is a variant of the Caesar cipher. It takes a string (msg) and a shift value (shift), then shifts each letter of the message by the specified amount in the alphabet.

    • How it works:

      • If a character is a space (' '), it is converted to 0.
      • If the character is not an uppercase letter (A-Z), it is left unchanged.
      • For uppercase letters (A-Z), the function shifts the letter by a specified value (the shift) using this formula:
new_letter = chr(65 + (ord(letter) - 65 + shift) % 26)

This formula ensures the letter shifts within the A-Z range and wraps around if necessary (because of the modulus 26).

  1. encrypt Function

    • The encrypt function takes a message (msg) and a list of shift values (key). It applies the julius_encrypt function for each shift value in key.
    • Essentially, it's applying multiple Caesar cipher shifts sequentially over the same message, making it a form of multi-step Caesar cipher encryption.
  2. Main Code

    • Reads a message from a file called secret.txt.
    • Converts the message to uppercase.
    • Generates a random key of 1337 bytes using os.urandom(1337). This key is likely converted into a list of shifts, but it's unclear how (since it's not used as is).
    • Writes the encrypted message to output.txt.

Decryption Plan

To decrypt the message, we need to reverse the shift operations in the Caesar cipher:

  1. The decryption of a Caesar cipher involves shifting the letter backward by the same shift value that was applied during encryption.
  2. Since the encryption applied multiple shifts sequentially (from the key), we need to reverse these shifts in the reverse order.

To easily find the correct shift by iterating over the possible values I used the following code. The code increments the Caesar cipher shift by +1 each time user press Enter and shows the next 5 possible decrypted results.

decrypt.py

def julius_decrypt(ct, shift):
    pt = ''
    for c in ct:
        if c == '0':  # Handling spaces
            pt += ' '
        elif not ord('A') <= ord(c) <= ord('Z'):  # Non-alphabet characters remain unchanged
            pt += c
        else:
            o = ord(c) - 65
            pt += chr(65 + (o - shift) % 26)  # Reversing the Caesar cipher shift
    return pt

# Encrypted message
encrypted_message = "LTARDBT0ID0WPRZIWTQDD0ILDIWDJHPCSILTCINUDJG!0IWXH0XH0P0EGDDU0DU0RDCRTEI0ID0EGDKT0NDJ0IWPI0IWT0RPTHPG0RXEWTG0XH0XCHTRJGT0CD0BPIITG0WDL0BPCN0IXBTH0NDJ0PEEAN0XI.0IWT0HTRJGXIN0DU0P0IWDJHPCS0SXHIXCRI0HWXUIH0XH0TKTCIJPAAN0IWT0HPBT0PH0IWPI0DU0P0HXCVAT0HWXUI.0TCDJVW0BJBQAXCV,0IPZT0NDJG0UAPV0PCS0TCYDN0IWT0GTHI0DU0IWT0RDCITHI.0BPZT0HJGT0NDJ0LGPE0IWT0UDAADLXCV0ITMI0LXIW0IWT0WIQ0UAPV0UDGBPI0HTRJGXINDUPIWDJHPCSDGHTRJGXINDUPHXCVAT."

# Function to display the next 5 decrypted values with incremental shifts
def display_decryptions(ct, start_shift):
    for shift in range(start_shift, start_shift + 5):
        print(f"\nShift: {shift}")
        decrypted_message = julius_decrypt(ct, shift)
        print(decrypted_message)

# Main loop to handle user input and shift increments
current_shift = 0
while True:
    input("Press Enter to show next 5 shift values...")
    display_decryptions(encrypted_message, current_shift)
    current_shift += 5  # Increment by 5 for the next set of shifts

After 15 shifts, I found a text that makes sense.

Shift: 15 

WELCOME TO HACKTHEBOO TWOTHOUSANDTWENTYFOUR! THIS IS A PROOF OF CONCEPT TO PROVE YOU THAT THE CAESAR CIPHER IS INSECURE NO MATTER HOW MANY TIMES YOU APPLY IT. THE SECURITY OF A THOUSAND DISTINCT SHIFTS IS EVENTUALLY THE SAME AS THAT OF A SINGLE SHIFT. ENOUGH MUMBLING, TAKE YOUR FLAG AND ENJOY THE REST OF THE CONTEST. MAKE SURE YOU WRAP THE FOLLOWING TEXT WITH THE HTB FLAG FORMAT SECURITYOFATHOUSANDORSECURITYOFASINGLE.

I successfully submitted the flag with HTB{} format.