[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
