# IRON CTF 2024 - Random Pixels **Title:** Random Pixels **Description:** My Image accidently fell into a pixel mixer can you help me recover it? **Files:** - `enc.py`: ```python import random, time, numpy from PIL import Image from secret import FLAG def randomize(img, seed): random.seed(seed) new_y = list(range(img.shape[0])) new_x = list(range(img.shape[1])) random.shuffle(new_y) random.shuffle(new_x) new = numpy.empty_like(img) for i, y in enumerate(new_y): for j, x in enumerate(new_x): new[i][j] = img[y][x] return numpy.array(new) if __name__ == "__main__": with Image.open(FLAG) as f: img = numpy.array(f) out = randomize(img, int(time.time())) image = Image.fromarray(out) image.save("encrypted.png") ``` - `encrypted.png`: ![encrypted](https://hackmd.io/_uploads/rklo7Vekkg.png) ## Solution: The challenge begins with an encrypted PNG image. Suspecting that the image was randomized based on pixel positions, we analyzed the encryption process. I inspected the encryption script(`enc.py`) and found this: ```python def randomize(img, seed): random.seed(seed) new_y = list(range(img.shape[0])) new_x = list(range(img.shape[1])) random.shuffle(new_y) random.shuffle(new_x) new = numpy.empty_like(img) for i, y in enumerate(new_y): for j, x in enumerate(new_x): new[i][j] = img[y][x] return numpy.array(new) ``` The encryption process involves using a random number generator to shuffle the `x` and `y` coordinates of the image. I discovered that the Unix timestamp at the time of encryption was the key factor in shuffling. Luckily, I was able to find out the file's modification date through the image's metadata: ```bash $ exiftool encrypted.png ExifTool Version Number : 12.40 File Name : encrypted.png Directory : . File Size : 22 KiB File Modification Date/Time : 2024:10:03 00:02:40+03:00 File Access Date/Time : 2024:10:06 18:25:20+03:00 File Inode Change Date/Time : 2024:10:05 21:40:40+03:00 File Permissions : -rwxrwxrwx File Type : PNG File Type Extension : png MIME Type : image/png Image Width : 300 Image Height : 300 Bit Depth : 8 Color Type : RGB with Alpha Compression : Deflate/Inflate Filter : Adaptive Interlace : Noninterlaced Image Size : 300x300 Megapixels : 0.090 ``` ```bash File Modification Date/Time : 2024:10:03 00:02:40+03:00 ``` I used this timestamp as the seed to reverse the shuffle. By using the seed, I can reverse the shuffling process and reconstruct the image by: - Generating the same shuffled indices for `x` and `y` axes. - Creating inverse mappings of these indices. - Rearranging the pixels back to their original positions using the inverse mappings. Here's the script I used for this: ```python import random import numpy as np from PIL import Image import os def get_seed_from_mtime(file_path): mtime = os.path.getmtime(file_path) unix_timestamp = int(mtime) return unix_timestamp def reverse_randomize(encrypted_img, seed): random.seed(seed) height, width = encrypted_img.shape[:2] new_y = list(range(height)) new_x = list(range(width)) random.shuffle(new_y) random.shuffle(new_x) inverse_y = [0] * height inverse_x = [0] * width for i, y in enumerate(new_y): inverse_y[y] = i for j, x in enumerate(new_x): inverse_x[x] = j decrypted_img = np.empty_like(encrypted_img) for i in range(height): for j in range(width): decrypted_img[i][j] = encrypted_img[inverse_y[i]][inverse_x[j]] return decrypted_img encrypted_image_path = 'encrypted.png' decrypted_image_path = 'decrypted.png' seed = get_seed_from_mtime(encrypted_image_path) with Image.open(encrypted_image_path) as img: img = img.convert('RGB') encrypted_array = np.array(img) decrypted_array = reverse_randomize(encrypted_array, seed) decrypted_image = Image.fromarray(decrypted_array) decrypted_image.save(decrypted_image_path) print(f"Decrypted image saved as {decrypted_image_path}") ``` ```bash $ python3 decrypt.py Decrypted image saved as decrypted.png ``` ![decrypted](https://hackmd.io/_uploads/rJNh7Vg11g.png) Once the image was decrypted, we noticed that it contained a QR code, likely hiding the flag. To extract the flag from the QR code, I used a tool called `zbarimg` which is used for scanning barcodes and QR codes from images. ```bash $ zbarimg decrypted.png QR-Code:ironCTF{p53ud0_r4nd0m_f0r_4_r3450n} scanned 1 barcode symbols from 1 images in 0.15 seconds ``` And there's our flag: `ironCTF{p53ud0_r4nd0m_f0r_4_r3450n}`