Zadanie

Na 49 streamie nie pojawił się co prawda utęskniony raytracing “bardzo rozproszony”, ale próba kryptoanalizy szyfrogramu na żywo również okazała się tematem wartym uwagi. Jak zwykle, pod koniec streamu czekała na agenta (lub nas) misja. Jej treść brzmi następująco:

MISJA 011            goo.gl/keE94T                  DIFFICULTY: █████░░░░░ [5/10]
┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅

Jednemu z naszych agentów polowych poszczęściło się - zakradł się do biura
podejrzanego i zrobił zdjęcie bardzo ważnego dokumentu. Zdjęcie udało się wywołać
i otrzymaliśmy dzisiaj archiwum z jego skanem.

Ponieważ jestem obecnie bardzo zajęty i mam bardzo ważne spotkanie, poniżej jest
link do pliku - zajmij się tym.

  goo.gl/A6sMwA

Powodzenia!

--

Odzyskaną wiadomość umieść w komentarzu pod tym video :)
Linki do kodu/wpisów na blogu/etc z opisem rozwiązania są również mile widziane!

P.S. Rozwiązanie zadania przedstawię na jednym z vlogów w okolicy dwóch tygodni.

Zaczynamy!

Pod linkiem znajdującym się w misji, umieszczony został plik o rozszerzeniu bin. Polecenie file albo szybkie spojrzenie w hexedytor rozjaśnia sytuację - to archiwum 7z (jeśli Czytelnik spodziewał się radare2 w tym wątku - tak ono również rozumie tego magica ;] ).

λ file 43842e832bfe28328309053ce1b1a49afc1047e5.bin 43842e832bfe28328309053ce1b1a49afc1047e5.bin: 7-zip archive data, version 0.4

Wypakowanie zawartości zajmuje chwilę. Wewnątrz mamy 76 801 plików. Hm, no ciekawie. Okazuje się, że te pliki to PCX skompresowane RLE (hm, my się chyba znamy z innej misji). Żeby tego było mało wszystkie są jednakowej wielkości.

λ file ffff609e5415
ffff609e5415: PCX ver. 3.0 image data bounding box [0, 0] - [319, 239], 3 planes each of 8-bit colour, RLE compressed

Przeczesałem główne archiwum jak i kilka pojedynczych randomowo wybranych plików. Niestety exiftools nie potrafiły znaleźć ukrytej treści. Czyli chyba trzeba rozwiązać to “the hard way” łącząc te obrazki. W związku z tym, że każdy był rozmiaru 320x240 i nieparzystej liczby to odrzuciłem od razu możliwość rozbicia dużego obrazu na pojedyncze i mniejsze. Zacząłem więc nakładać na siebie obrazki.

Pierwszy fail

Piniższy kod prezentuje moją próbę połączenia PCXów w jeden obrazek. Oczywiście strukturę pliku musiałem potem odtworzyć.

import os

prefix = "./wyj/"
def main():
	fs = []
	for file in os.listdir(prefix):
		with open(prefix + file, 'rb') as f:
			fs.append(list(f.read()))

	print("xoring now")
	bstr = fs[0]
	for f in fs[1:]:
		for i in range(0, k):
			bstr[i] += f[i]

	with open("dump.bmp", 'wb') as f:
		f.write(bytes(bstr))

if __name__ == '__main__':
	main()

Niestety nie wiedziałem, że plik PCX nie obsługuje kanału ALFA czyli przeźroczytości. Dlatego po otrzymaniu wynikowego obrazka zobaczyłem wielki, ciekawy… czarny ekran. Tak wyglądało to w hexedytorze:

hexeditor

A tak po wczytaniu pliku raw (.data) przez GIMPa.

gimp

Rozwiązanie

Postanowiłem zmienić podejście i skonwertować PCX na BMP a następnie powtórzyć operację. Konwersji dokonałem za pomocą polecenia:

mogrify -path "path/here" -format bmp *

Mogrify uporał się z całą gromadką plików w niewiele ponad 5 minut. Zmodyfikowałem trochę skrypt. Stworzyłem obraz 400x400 (nie sprawdzałem pojedynczo plików, to był taki failsafe na wypadek wyjścia poza te 320x240) i zacząłem nakładać pixele. Kod wygląda tak:

from PIL import Image
import os
import numpy as np
import time
import progressbar
import operator

prefix = "./tmp/"
def main():
	fs = []
	out = Image.new("RGB",(400, 400))
	pxs = out.load()
	out.save("output.bmp")
	bar = progressbar.ProgressBar()
	for file in bar(os.listdir(prefix)):
		im = Image.open(prefix + file )
		row, col = im.size
		f = Image.open('output.bmp')
		pxs = f.load()
		for r in range(row):
			for c in range(col):
				pxs[r,c] = tuple(map(operator.add, pxs[r,c], im.getpixel((r,c))))				
		f.save("output.bmp")

	print('END')

if __name__ == '__main__':
	main()

Z każdym kolejnym krokiem obrazek wyglądał coraz lepiej:

pr1

pr2

Tutaj pasek postępu i “ETA”:

pr3

pr4

prbr

Rozwiązanie coraz bliżej:

pr5

pr5

No i obrazek w całości:

solution

Śliczny widok ;) a dzisiejszą flagą jest:

Pocztówka z wakacji

Kudos dla KrzaQ, który wyprzedził mnie w swoim rozwiązaniu. Jego post znajdziecie tutaj

Dzięki za misję Gyn!