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.
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
-
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 to0
. - 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:
- If a character is a space (
-
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).
-
encrypt
Function- The
encrypt
function takes a message (msg
) and a list of shift values (key
). It applies thejulius_encrypt
function for each shift value inkey
. - Essentially, it's applying multiple Caesar cipher shifts sequentially over the same message, making it a form of multi-step Caesar cipher encryption.
- The
-
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
.
- Reads a message from a file called
Decryption Plan
To decrypt the message, we need to reverse the shift operations in the Caesar cipher:
- The decryption of a Caesar cipher involves shifting the letter backward by the same shift value that was applied during encryption.
- 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.