# 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}`