NahamCon 2022, Ostrich

Steganography


diberikan 3 file

ostrich.jpg
result.apng
ostrich.py

ostrich.py
import imageio
from PIL import Image, GifImagePlugin
from Crypto.Util.number import long_to_bytes as l2b, bytes_to_long as b2l
import random
from apng import APNG

filenames = []
flag = "REDACTED" 

orig_filename = "ostrich.jpg"
orig_image = Image.open(orig_filename)
pixels = orig_image.load()
width, height = orig_image.size
images = []

for i in range(len(flag)):
    new_filename = f'./images/ostrich{i}.png'
    new_image = Image.new(orig_image.mode, orig_image.size)
    new_pixels = new_image.load()
    for x in range(width):
        for y in range(height):
            new_pixels[x,y] = orig_image.getpixel((x, y))

    x = random.randrange(0,width)
    y = random.randrange(0,height)
    pixel = list(orig_image.getpixel((x, y)))
    while(pixel[2] == 0):
        x = random.randrange(0,width)
        y = random.randrange(0,height)
        pixel = list(orig_image.getpixel((random.randrange(0,width), random.randrange(0,height))))

    new_val = l2b(pixel[2]*ord(flag[i]))
    pixel[0] = new_val[0]
    if len(new_val) > 1:
        pixel[1] = new_val[1]
    pixel[2] = 0

    new_pixels[x, y] = (pixel[0], pixel[1], pixel[2])
    new_image.save(new_filename)
    filenames.append(new_filename)
    images.append(new_image)

APNG.from_files(filenames, delay=0).save("result.apng")

APNG / Animated-PNG, dalam konteks soal APNG merupakan gabungan dari beberapa gambar dengan beberapa nilai piksel yang berbeda sehingga membentuk gambar beranimasi

Note

gambar asli = ostrich.jpg
gambar baru / gambar gabung = ostrich.jpg dengan mengubah salah satu pixel

Ide Enkoding

aturan pengubahan nilai pixel

pixel_lama = rgb(a,b,c)

    *memilih pixel yang nilai c != 0

new_val = l2b(c*flag[i])
x = new_val[0]
if len(new_val) > 1:
    y = new_val[1]
else:
    y = b
z = 0

pixel_baru = rgb(x,y,z)

maka perlu diekstrak terlebih dahulu file result.apng

from apng import APNG

im = APNG.open("result.apng")
for i, (png, control) in enumerate(im.frames):
    png.save("hasil/ostrich{i}.png".format(i=i))

dengan membandingkan setiap hasil gambar ekstrak dengan gambar asli, dapat diperoleh titik pixel yang berbeda

get_flag.py
from apng import APNG
from PIL import Image

gambar_asli = Image.open('ostrich.jpg')

for k in range(38):
  gambar0 = Image.open('hasil/ostrich'+str(k)+'.png')

  data_asli = gambar_asli.load()
  data_0 = gambar0.load()

  width, height = gambar_asli.size

  for i in range(width):
    for j in range(height):
        if data_0[i,j] != data_asli[i,j]:
          if data_0[i,j][0] / data_asli[i,j][2] > 1:
            fl = data_0[i,j][0] / data_asli[i,j][2]
          else: # kebetulan semua nilai pixel gambar masuk ke else
            p1 = hex(data_0[i,j][1])[2:]
            if len(p1) == 1:
              p1 = '0'+p1
            fl = int(hex(data_0[i,j][0])+p1,16) / data_asli[i,j][2]

  print(chr(int(fl)),end='')