IRON CTF 2024 Writeup(Crypto/Random Pixels)

Q : My Image accidently fell into a pixel mixer can you help me recover it?

A zip file is given, containing a python program (enc.py) to encode the image and the image (encrypted.png).
So, we can decode the images.

enc.py

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")

Looking at enc.py, it seems that seed (timestamp) is required for decoding, so use exiftool to obtain it.

encrypted.png

$ exiftool encrypted.png
ExifTool Version Number         : 12.76
File Name                       : encrypted.png
Directory                       : .
File Size                       : 22 kB
File Modification Date/Time     : 2024:10:07 09:58:36+09:00
File Access Date/Time           : 2024:10:07 09:59:07+09:00
File Inode Change Date/Time     : 2024:10:07 09:58:36+09: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

decrypted.py

import random, numpy
from PIL import Image
from datetime import datetime

def derandomize(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)

    original = numpy.empty_like(img)
    for i, y in enumerate(new_y):
        for j, x in enumerate(new_x):
            original[y][x] = img[i][j]
    return original

if __name__ == "__main__":
    date_str = '2024-10-03T06:02:40+0900'
    dt = datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S%z')
    seed = int(dt.timestamp())
    with Image.open("encrypted.png") as f:
        img = numpy.array(f)
        original_img = derandomize(img, seed)
        image = Image.fromarray(original_img)
        image.save("decrypted.png")
        print("Image successfully decrypted and saved as decrypted.png")

decrypted.png

$ zbarimg decrypted.png
QR-Code:ironCTF{p53ud0_r4nd0m_f0r_4_r3450n}
scanned 1 barcode symbols from 1 images in 0.01 seconds

FLAG:ironCTF{p53ud0_r4nd0m_f0r_4_r3450n}