Skip to content

TJCTF 2024 - rev pseudo-brainrot

Published: at 12:00 AMSuggest Changes

Overview

This challenge consists of extracting the information about the flag which has been embedded into an image.

The majority of the embedding has been done with the help of random numbers. However, a fixed manual seed at the beginning is what allows us to reproduce the random numbers and thus find the flag.

Working of the encoder

The flag is read as a binary and the skibidi.png image is opened.

The flag is first converted to bytes. Each byte is padded appropriately and then saved as a string.

Using a randomly shuffled array inds, each character of the string (ie each individual bit of the flag) is shuffled.


flag = open("flag.txt", "rb").read()

st = ""
for i in bytearray(flag):
    tmp = bin(i)[2:]
    while(len(tmp))<8:
        tmp = "0"+tmp
    st+=tmp
inds = [i for i in range(288)]
randnum = random.randint(1,500)


for i in range(random.randint(0,500), random randint(500,1000)):
    random.seed(i)
    random.shuffle(inds)
    if i==randnum:
        break

new_flag = "".join([st[i] for i in inds])

Next, each bit in the flag is embedded into the image by first choosing a random pixel of the image, then choosing a colour channel (ex: red from rgb) and replacing the LSB of the chosen colour value with the flag bit

colors = list(img.getpixel((row,col)))
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    change = random.randint(0,2)
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    colors[change] = (colors[change]& 0b11111110) | int(new_flag[i])
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    img.putpixel((row,col),tuple(colors))

Note: the code has numerous troll statements.

troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

The purpose of these trolls is simpy to reseed the RNG

Solving

The key idea here is that since the seed for the generator is the same, we get the same output each time

In order to get the flag, we need to get each bit that’s embedded, then unshuffle it, then convert to string

In order to get the bits, we simply rerun the same code but with slight modifications. We remove the reading of flag file and shuffling of bits. In place of accessing random pixels and modifying the LSB of a random colour channel, we simply append the colour channel value’s LSB to an array.

Since we haven’t removed any seed or used random() different number of times than the encoder, we end up choosing the same pixels and colour channels as the encoder.

colors = list(img.getpixel((row,col)))
change = random.randint(0,2)
new_flag.append(colors[change]& 0b00000001)

Once we recieve all the bytes, we use the initial shuffled array inds as it contains where each bit should go.

flag_bytes = [0 for i in range(len(new_flag))]
for i in range(len(new_flag)):
flag_bytes[inds[i]] = new_flag[i]

Once we have the bytes, we simply, convert it back to a string

for i in range(0, len(flag_bytes), 8):
    print(chr(int("".join(map(str, flag_bytes[i:i+8])), 2)), end="")

Flag: tjctf{th@t_m@d3_m3_g0_1n5an3333!!!!}

Here is the entire decoder code

from PIL import Image

import random

random.seed(42)

lmao = random.randint(12345678,123456789)

random.seed(lmao)

img = Image.open("skibidi_encoded.png")

width, height = img.size

troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

inds = [i for i in range(288)]

troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

randnum = random.randint(1,500)

troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

for i in range(random.randint(0,500), random.randint(500,1000)):
    random.seed(i)
    random.shuffle(inds)
    if i==randnum:
        break

troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

troll = [random.randint(random.randint(-lmao,0),random.randint(0,lmao)) for _ in range(random.randint(1,5000))]

troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

pic_inds = []
while len(pic_inds)!=288:
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    temp = random.randint(0,width*height)
    # print(f"temp: {temp}")
    pic_inds.append(temp)

    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
new_flag = []
pixel_accessed_arr = []
for i in range(288):
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))

    cur_ind = pic_inds[i]
    row = cur_ind//height
    col = cur_ind%width
    colors = list(img.getpixel((row,col)))


    change = random.randint(0,2)
    new_flag.append(colors[change]& 0b00000001)

    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    troll = random.randint(random.randint(-lmao,0),random.randint(0,lmao))
    if(i%randnum==0):
        random.seed(random.randint(random.randint(-lmao,0),random.randint(0,lmao)))


flag_bytes = [0 for i in range(len(new_flag))]
for i in range(len(new_flag)):
    flag_bytes[inds[i]] = new_flag[i]
for i in range(0, len(flag_bytes), 8):
    print(chr(int("".join(map(str, flag_bytes[i:i+8])), 2)), end="")

Previous Post
TJCTF 2024 - crypto alkane
Next Post
UIUCTF 2024 - Pwn backup-power