Challenge: Prelim
Description: The challenge involves a Python script (source.py
) that scrambles a message and encrypts a flag. Your task is to write a script (decoder.py
) to reverse these operations and retrieve the original flag.
Brief Explanation of source.py
:
The source.py
script performs the following actions:
- Initializes
n
ande
. - Defines functions to
scramble
a list based on a permutation andsuper_scramble
a permutation by applying it multiple times. - Creates a shuffled list of numbers from 0 to
n-1
. - Applies the
super_scramble
function to this shuffled list using the exponente
. - Reads the flag from
flag.txt
, pads it, and encrypts it using AES in ECB mode with a key derived from the initial shuffled list. - Writes the scrambled list and the encrypted flag (in hexadecimal format) to
tales.txt
.
decoder.py
:
from hashlib import sha256
from Crypto.Cipher import AES
import ast
def main():
# Define RSA-like parameters
n = 0x1337 # 4919
e = 0x10001 # 65537
# Read scrambled_message and enc_flag from tales.txt
with open('tales.txt', 'r') as f:
lines = f.readlines()
scrambled_line = lines[0].strip()
enc_flag_line = lines[1].strip()
# Parse scrambled_message
scrambled_str = scrambled_line.split('=', 1)[1].strip()
scrambled_message = ast.literal_eval(scrambled_str)
# Parse enc_flag
enc_flag = enc_flag_line.split('=', 1)[1].strip().strip("'")
# Initialize the original message list
message = [0] * n
visited = [False] * n
# Process each element to find cycles
for i in range(n):
if not visited[i]:
cycle = []
j = i
while not visited[j]:
visited[j] = True
cycle.append(j)
j = scrambled_message[j] # Follow the permutation
L = len(cycle)
if L == 0:
continue
# Compute inverse of e modulo L
d = pow(e, -1, L)
# Reorder the cycle
reordered_cycle = [cycle[(k * d) % L] for k in range(L)]
# Assign the values to message
for k in range(L):
current = reordered_cycle[k]
next_val = reordered_cycle[(k + 1) % L]
message[current] = next_val
# Generate the key from the original message
key = sha256(str(message).encode()).digest()
# Decrypt the flag
cipher = AES.new(key, AES.MODE_ECB)
encrypted_flag_bytes = bytes.fromhex(enc_flag)
flag = cipher.decrypt(encrypted_flag_bytes)
# The flag might have padding, which we can strip if necessary
print(flag.decode('utf-8').strip())
if __name__ == "__main__":
main()
Solution:
Flag: HTB{t4l3s_fr0m___RS4_1n_symm3tr1c_gr0ups!}