Skip to content

Instantly share code, notes, and snippets.

@ky28059
Created April 21, 2024 19:33
Show Gist options
  • Select an option

  • Save ky28059/e1d26ae6652bc6f4c25535555034ca4b to your computer and use it in GitHub Desktop.

Select an option

Save ky28059/e1d26ae6652bc6f4c25535555034ca4b to your computer and use it in GitHub Desktop.

UMass CTF 2024 — Stop the voices

Patrick’s been trying to remember the flag, but his vision seems a little blurry and the voices just don't stop...

We're given 400 samples and a generator script that looks like this:

from PIL import Image
import numpy as np

img = Image.open('FLAG.png').convert('L')
arr = np.asanyarray(img)


def normalize(mat):
    return (mat - mat.min()) / (mat.max() - mat.min()) * 255


for i in range(400):
    noise = np.random.normal(arr, 200)
    noise = normalize(noise)
    noise = noise.astype(np.uint8)
    im = Image.fromarray(noise)
    im.save(f"./samples/{i}.png")

The script generates 400 files of random noise based on the original flag image, storing them in the samples directory like so:

We can write a script to combine all the samples into a single grayscale image using OpenCV.

import cv2

cv2.namedWindow('reconstruction', cv2.WINDOW_NORMAL)
reconstructed = None

for i in range(400):
    img = cv2.imread(f'./samples/{i}.png', cv2.IMREAD_GRAYSCALE)
    if reconstructed is None:
        reconstructed = img / (400 * 255)
    else:
        reconstructed += img / (400 * 255)

cv2.imshow('reconstruction', reconstructed)
cv2.waitKey()

out = cv2.equalizeHist((reconstructed * 255).astype('uint8'))
cv2.imshow('reconstruction', out)
cv2.waitKey()

Then, equalizing the histogram using OpenCV, we get the flag.

UMASS{#id31n9_L1k3_@_c#Am3_le0n}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment