2 min read

[CTF] WU - One Ring 💍

CTF InterCampus Ynov 2024

Difficulty Level : Insane

Challenge Category : Crypto

Description :

In the heart of Middle-earth, the legendary One Ring has resurfaced, but its true power remains hidden behind layers of dark enchantment. The mysterious image ring.bmp holds the secrets of the Ring's essence, obscured by ancient magic that only the bravest and most skilled can unravel. Sauron's influence has twisted the image, concealing the Ring's true nature and the path to its ultimate power.

Challenge Description

In this challenge, you are given a single image file, ring.bmp, and a cryptic hint:

"Well done, Arnold! Now all that's left is to catch the beast!"

The goal is to reverse the Arnold transformation applied to the image and retrieve the original content.


Solution Approach

The Arnold Transform is a mathematical and quantum-inspired transformation that scrambles an image's pixels based on a specific mapping formula. The challenge involves reversing this transformation to retrieve the original image.


Arnold Transform (Scrambling)

The scrambling process applies the Arnold Transform over a number of iterations (rounds) with two parameters (a and b). The formula for pixel mapping is as follows:

  • New X-coordinates: (a * b * x + x + a * y) % size
  • New Y-coordinates: (b * x + y) % size

Handling Unknown Parameters (a, b, rounds)

The parameters (a, b, rounds) are not provided, brute-forcing is necessary. A script can iterate through potential values of a, b, and rounds to reconstruct the original image.

Reversing the Arnold Transform (Solving)

To retrieve the original image, the inverse Arnold Transform must be applied. The formula for the inverse mapping is:

  • New X-coordinates: (x - a * y) % size
  • New Y-coordinates: (-b * x + a * b * y + y) % size

Here is the Python script to reverse the transform:

import numpy as np  
from PIL import Image  
import sys  
  
class Arnold:  
   def __init__(self, a: int, b: int, rounds: int):  
       self.__a = a  
       self.__b = b  
       self.__rounds = rounds  
  
   def inverseMapping(self, s: np.shape):  
       x, y = np.meshgrid(range(s[0]), range(s[0]), indexing="ij")  
       xmap = (x - self.__a * y) % s[0]  
       ymap = (-self.__b * x + self.__a * self.__b * y + y) % s[0]  
       return xmap, ymap  
  
   def applyInverseTransformTo(self, image: np.ndarray):  
       xm, ym = self.inverseMapping(image.shape)  
       img = image  
       for r in range(self.__rounds):  
           img = img[xm, ym]  
       return img  
  
def apply_inverse_transform(image_path, a, b, rounds, output_path):  
   image = np.array(Image.open(image_path).convert("L"))  
   arnold = Arnold(a, b, rounds)  
   inverse_transformed = arnold.applyInverseTransformTo(image)  
   Image.fromarray(inverse_transformed).convert("L").save(output_path, format="TIFF")  
  
if __name__ == "__main__":  
   if len(sys.argv) != 6:  
       print("Usage: python apply_inverse_transform.py [image_path] [a] [b] [rounds] [output_path]")  
       sys.exit(1)  
  
   image_path = sys.argv[1]  
   a = int(sys.argv[2])  
   b = int(sys.argv[3])  
   rounds = int(sys.argv[4])  
   output_path = sys.argv[5]  
  
   apply_inverse_transform(image_path, a, b, rounds, output_path)

To solve a scrambled image:

python3 apply_inverse_transform.py scrambled_image.bmp 150 150 42 solved_image.bmp