Category: Crypto Points: 150 Description:
Find the flag file
This write-up is made by Steven of the HacknamStyle CTF team.
The challenge contains this image:
…and a Python script:
#!/usr/bin/env python
import Image
import random
def get_color(x, y, r):
n = (pow(x, 3) + pow(y, 3)) ^ r
return (n ^ ((n >> 8) << 8 ))
flag_img = Image.open("flag.png")
im = flag_img.load()
r = random.randint(1, pow(2, 256))
print flag_img.size
enc_img = Image.new(flag_img.mode, flag_img.size)
enpix = enc_img.load()
for x in range(flag_img.size[0]):
for y in range(flag_img.size[1]):
t = random.randint(1, pow(2, 256)) % 250
enpix[x,y] = t
for x in range(flag_img.size[0]):
for y in range(flag_img.size[1]):
if im[x,y] < 250 :
s = get_color(x, y, r)
enpix[x,y] = s
enc_img.save('enc' + '.png')
The script is used to encode an image with the flag, and turns it into the given image.
Pixels with value lower than 250 are overwritten by the value generated by get_color(x, y, r)
.
This function generates a value based on the pixel location (x,y)
and 256-bit random value r
.
In get_color
we can see that the value is calculated by XORing the sum of the cubes of x
and y
with r
, and then keeping the least significant 8 bits.
We don't have the random key r
, but we can bruteforce it because only the least significant 8 bits are used.
For the correct version of r
, get_color(x,y,r)
will generate a value that is identical to the one in enc.png
.
Unfortunately, some pixels will contain random information instead (those which have values 250 and higher in the original flag image).
We give each of these 2 cases a different color. Pixels matching their get_pixel
value will be colored black, the rest is colored white. For each of the 256 possible values of r
, we generate a ‘decoded’ image. By going through the image, we find that decoded_38.png
(for r = 38
) contains the flag:
color_decrypto.py
contains the code for the solution.