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.
Ściągnięty plik 43842e832bfe28328309053ce1b1a49afc1047e5.bin wykrywany jest jako archiwum 7z przez narzędzie file:
> file 43842e832bfe28328309053ce1b1a49afc1047e5.bin 43842e832bfe28328309053ce1b1a49afc1047e5.bin: 7-zip archive data, version 0.4 |
Po sprawdzeniu okazało się, że w archiwum znajduje się ponad 75 000 plików o właściwie identycznych rozmairach. Będąc przekonanym, że podobnie do Misji 008, wypakowywanie ich jest bezcelowe, zacząłem szukać sugestii w ich metadanych. Lista wyglądała następująco:
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21 p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,8 CPUs Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz (306C3),ASM,AES-NI) Scanning the drive for archives: 1 file, 2260394 bytes (2208 KiB) Listing archive: 43842e832bfe28328309053ce1b1a49afc1047e5.bin.7z -- Path = 43842e832bfe28328309053ce1b1a49afc1047e5.bin.7z Type = 7z Physical Size = 2260394 Headers Size = 990068 Method = LZMA:27 Solid = + Blocks = 1 Date Time Attr Size Compressed Name ------------------- ----- ------------ ------------ ------------------------ 2017-09-28 19:28:39 D.... 0 0 zdjecie_dokumentu 2017-09-28 19:15:54 ....A 8771 1270326 zdjecie_dokumentu/1000099b5802 2017-09-28 19:15:54 ....A 8771 zdjecie_dokumentu/10001494c006 2017-09-28 19:15:54 ....A 8774 zdjecie_dokumentu/1000ee4ba590 2017-09-28 19:15:54 ....A 8776 zdjecie_dokumentu/1000f352b441 2017-09-28 19:15:54 ....A 8771 zdjecie_dokumentu/10023645483f 2017-09-28 19:15:54 ....A 8771 zdjecie_dokumentu/10040f06c95d [...] 2017-09-28 19:25:20 ....A 8772 zdjecie_dokumentu/fff6940e20c0 2017-09-28 19:25:20 ....A 8771 zdjecie_dokumentu/fff86fecc806 2017-09-28 19:25:20 ....A 8771 zdjecie_dokumentu/fffa379476c6 2017-09-28 19:25:20 ....A 8774 zdjecie_dokumentu/fffbb82314bb 2017-09-28 19:25:20 ....A 8771 zdjecie_dokumentu/fffda28a026f 2017-09-28 19:25:20 ....A 8771 zdjecie_dokumentu/fffdc98e6122 2017-09-28 19:25:20 ....A 8771 zdjecie_dokumentu/fffe366b11ec 2017-09-28 19:25:20 ....A 8771 zdjecie_dokumentu/ffff609e5415 2017-09-28 19:25:20 ....A 8772 zdjecie_dokumentu/ffffdca9b891 ------------------- ----- ------------ ------------ ------------------------ 2017-09-28 19:28:39 673653115 1270326 76800 files, 1 folders |
Jak widać, wielkości plików są prawie identyczne – ale jednak identyczne nie są. Wobec tego należy sprawdzić, jaki mają rozrzut:
arr = File.read('list.txt') .scan(/ (87[678]\d)/) .map(&:first) .map(&:to_i) p [arr.min, arr.max] [8768, 8780] |
Interesujące. Może są to piksele obrazka o poszczególnej jasności?
arr = File.read('list.txt') .scan(/ (87[678]\d)/) .map(&:first) .map(&:to_i) .map{ |n| n - 8768 } .map{ |n| [(n*15).chr]*3 } .flatten .join File.write('img.raw', arr) |
Po otworzeniu w programie GIMP okazało się jednak, że to ślepa uliczka.
Wobec tego rozpakowałem archiwum i sprawdziłem jakiego typu są zawarte w nim pliki. file raportował dla każego z nich, że jest to PCX ver. 3.0 image data bounding box [0, 0] – [319, 239], 3 planes each of 8-bit colour, RLE compressed.
Po przejrzeniu kilku z tych plików okazało się, że każdy z nich miał dokładnie jeden ustawiony piksel na czarnym tle. Oczywistym stało się przypuszczenie, że 76 800 plików-obrazków to tak naprawdę 76 800 pikseli obrazka z flagą. Zdecydowałem, że je wszystkie złożę. Aby tego dokonać, musiałem pierw przekonwertować wszystkie do formatu png, ponieważ pcx nie wspiera kanału alfa.
FILES = Dir['zdjecie_dokumentu/*'] .map{ |s| s.sub(/zdjecie_dokumentu\/(.+)/, '\1') } CMD_CONVERT = 'convert zdjecie_dokumentu/%s -transparent black out/%s.png' CMD_COMPOSE = 'convert tmp.png out/%s.png -gravity center -composite tmp.png' system('rm tmp.png') system('cp base.png tmp.png') done = 0 FILES.each do |f| system(CMD_CONVERT % [f, f]) system(CMD_COMPOSE % f) done += 1 puts 'Done: % 5d/%d' % [done, FILES.size] if done % 100 == 0 then cmd = 'cp tmp.png partials/%05d.png' % done system cmd end end |
Nie było to rozwiązanie najszybsze (przerabiało ok 15 pikseli na sekundę), ale mimo wszystko było zadowalające. Już po przerobieniu połowy pikseli widać było część hasła, chociaż wtedy wydawało mi się, że jego treść to “Pocztówka z Sarkcz“:
Wystarczyło jednak chwilkę jeszcze poczekać, aby odczytać faktyczne hasło – “Pocztówka z wakacji“. Osobiście preferuję jednak wersję z Sarkcz.
A tak wygląda wizualizacja uzupełniania obrazka:
Bardzo ciekawa misja, oby takich więcej!