Kolejna misja z serii CTF opublikowana po live stream’ie Hacking Livestream #35.
Treść misji:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
MISSION 016 goo.gl/zqvPQD DIFFICULTY: ████████░░ [8╱10] ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ Operation codename: "Pasokon" During the operational game our spy (codename "Martin") managed to intercept hostile communication. goo.gl/MoYBAx Unfortunately, we have no idea how to decode it. To make matters worse, our most well versed in crypto agent (codename "Scottie") is on a mission right now and cannot help us. Your handler advised to use your skills. The fate of the Chunar rests in your hands! And remember - if something is not clear, you have a license to bruteforce. Good luck! Over and out. -- If you find the answer, put it in the comments under this video! If you write a blogpost / post your solution / code online, please add a link as well! P.S. I'll show/explain the solution in a video in one or two weeks. P.S.2. This mission was brought to you by foxtrot_charlie! |
Czyli po polsku, jakiś gościu przechwycił wrogą komunikację. Nie mają pojęcia jak to zdekodować, a agent Scottie, który jest dobry w te klocki pojechał sobie na wycieczkę.
Los Chunara spoczywa w Twoich rękach!
I gada jeszcze ważne zdanie, tzn. mamy licencję na bruteforce. Czyżby coś podobnego do poprzedniej misji?
Rozwiązanie 1/2
Ściągam plik i zaglądam do środka (TotalCommander – Lister). Wąski przedział użytych znaków (A-Za-z0-9), oraz znak ‘=’ na końcu sugerują format BASE64. Próbuję zatem konwersji.
1 2 3 |
string comm = File.ReadAllText("mission016_comm.txt"); byte[] fb64 = Convert.FromBase64String(comm); File.WriteAllBytes("frombase64.txt", fb64); |
Przeszło bez błędu. Znowu podglądam plik. Nagłówek mówi sam za siebie "RIFFd.6.WAVEfmt"
to jest plik dźwiękowy.
Pierwsze co robię to słucham nagrania. Całkiem przyjemnie się rozpoczyna :). Mogę się mylić, ale nagranie przypomina dźwięk modemu nawiązującego połączenie, a następnie transmisja danych (chyba dawno tego nie słyszałem, bo jednak nie przypomina). Dziwne jest jednak to, że słychać cały czas zapętlone 3 tony, a co kilka sekund słychać krótkie zakłócenia.
Otwieram audacity.

Format pliku to 48000Hz, jedna ścieżka czyli Mono oraz głębia 16 bitowa (short). Nie wiem dlaczego, ale audacity pokazuje 32-bitowy float, a jak później odczytałem nagłówek to wyszło że bitDepth==16
.
Obraz fali dźwiękowej wygląda jak ładna fala sinusoidalna. Amplituda fali na jednakowym poziomie, jednakowa głośność (rysunek 1).
Przechodzimy do podglądu spektrogramu. Widać teraz (rysunek 2) to co słychać w słuchawkach.

Spektrogram wygląda jakby były głównie 3 różne częstotliwości fali, ale są też jakieś szumy. Pomyślałem że w miejscach gdzie spektrogram jest bardziej kolorowy mogą znajdować się jakieś ukryte dane. Jednak w tych miejscach kształt fali także wygląda jak idealna fala sinusoidalna (rysunek 3).binwalk
nic nie wykrył.

Z tego wniosek, że dane muszą siedzieć w częstotliwości. Fala fala sinusoidalna różni się szerokością, co pokazałem na rysunku kwadracikami.
Trochę przypomina to zadanie z misji 009 (blog KrzaQ), gdzie w nagraniu przewijały się tylko dwa tony, które oznaczały poszczególne bity znakow ASCI.
Do odczytania częstotliwości można by użyć odwrotnej transformaty fouriera, ale z tego względu, że wykrywa ona nakładające się różnej długości i częstotliwości fale, musi operować na pewnym zakresie danych. To powoduje pewien stopień rozmycia. Tutaj mamy jednak do czynienia z tą samą amplitudą i fala jest gładka, a jedynie okres się zmienia. Trzeba zatem obliczyć szerokość fali (tzn czas okresu). To nam powinno dać jakieś ciekawsze dane.
Szerokość można wyliczyć wyznaczając punkty, w których wartości amplitudy przechodzą przez 0. W naszym przypadku (co widać na rysunku 4) mamy do czynienia z wartościami dyskretnymi, 48000 punktów na sekundę, ale nie wiemy co dzieje się pomiędzy. To audacity rysuje, pozostałe fragmenty i dlatego widzimy sinusoidę. Nie jestem przekonany czy bazując tylko na punktach dokładność będzie wystarczająca.

Trochę się tym pobawiłem, między innymi konwertowałem wyniki na znaki ASCII i podglądałem w notatniku. Rezultaty widać na rysunku 5. Nie miałem czasu tego dnia implementować generowania bitmapy.

Śmieszne, ten ostatni rysunek przypomina mi ustawianie głowicy w commodore 64.
Następnego dnia był kolejny livestream na polskim kanale Gynvaela. Nie oglądałem całego, przeklikałem tylko mając nadzieję że później zobaczę. Traf chciał, że kliknąłem akurat, gdy Gynvael pokazywał jak w GIMP’ie można podglądać dane z pliku w postaci obrazu. Można określić jaki format, od którego byte’a i jaki rozmiar obrazka ma być pokazany. Zmniejszając powoli szerokość można próbować znaleźć poprawny obraz.
SUPER! 😀 Tego mi było trzeba. Nie umiem się przekonać do GIMP’a, ale ta funkcjonalność mnie zaskoczyła.
Spróbowałem podglądnąć pliki, które zostały mi po wczorajszych zabawach (rysunek 6), ale to nie miało sensu.

Dosyć zabawy! Trzeba porządnie obliczyć długość fali, czyli wyznaczyć punkty przecięcia z osią. Oczywiście nie będę tutaj szukał przybliżenia fali sinusoidalnej. Takie rzeczy to na studiach się robiło 😉
Obliczę punkt przecięcia się z osią wyznaczając prostą przecinającą dwa sąsiednie punkty, pomiędzy którymi następuje przecięcie.

OK. Teraz adrenalinka podrosła. Otwieram GIMP’a.
JEST! Widać jakiś tekst.

Robię jeszcze kilka modyfikacji, aby obraz był czytelniejszy i ostatecznie mamy:

Kod, który pozwoli uzyskać taki obraz jest następujący:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// L[] - WAVE data normalized - dane odczytane z pliku znormalizowane do zakresu (-1;1) List<double> int0 = new List<double>(); List<double> freq = new List<double>(); for (int t = 1; t < L.Length; t++) { if (((L[t - 1] <= 0) && (L[t] > 0)) || ((L[t - 1] >= 0) && (L[t] < 0))) { // Calculation of linear function parameters double t1 = t - 1; //double t2 = t; double y1 = L[t - 1]; double y2 = L[t]; //double a = (y2 - y1) / t2 - t1; => t2 - t1 == 1 double a = (y2 - y1); double b = y1 - a * t1; // Intersection with OX axis double t0 = -b / a; int0.Add(t0); } if ((int0.Count >= 2) && (t % 4 == 0)) { double f = int0[int0.Count - 1] - int0[int0.Count - 2]; freq.Add(f); } } byte[] freqb = new byte[freq.Count]; for (int i = 0; i < freq.Count; i++) freqb[i] = (byte)((freq[i] - 10) * 20); File.WriteAllBytes("freqd.data", freqb); |
Rozwiązanie 2/2
Mamy taki tekst:
1 2 3 4 5 6 7 8 9 10 11 |
REPORT ONE: # # R O N D I Y M A U Z # # # B C K P # # # V W X Y DHXDMW BQLF KDYNV Over and out. |
Tablica 5×5 i jakieś zaszyfrowane zdanie. Nie spotkałem się jeszcze z czymś takim, ale podejrzewam, że ta tablica jest kluczem do rozszyfrowania hasła. Niestety kilka znaków zostało ewidentnie zamazanych. Przypomina mi to testy na IQ. Pamiętam, że często w takich tablicach był jakiś wzór, np. suma wszystkich liczb w każdej kolumnie i w każdym wierszu musiała być taka sama. Pytanie tylko jak to później zmapować. Czy tę tablicę mapuje się na litery alfabetu wpisane kolejno rzędami? Tylko co w takim wypadku zrobić z jedną literą, bo tablica ma 25 pól, a alfabet angielski licy 26 liter.
Przez kilka kolejnych dni próbowałem jakiś prostych szyfrów podstawieniowych, ale nic nie wychodziło. Nie interesowałem się do tej pory takimi rzeczami, więc nić innego do głowy mi nie przychodziło.
Mission Failed?
Zagadałem więc do autora, czyli do foxtrot_charlie i mówię, że chyba nie dam rady, nic już więcej nie wymyślę. A on mi na to:
“nie poddawaj się jeszcze, to jest prosty szyfr”
Prosty szyfr, hmmmm… klik, klik, google “prosty szyfr”. Na jednej z pierwszych pozycji wyskoczyła strona www.crypto-it.net. Przeglądam dział Proste szyfry.
BINGO!
Implementuję. Znaków, których może brakować w tablicy jest 9:
1 2 |
ABCDEFGHIJKLMNOPQRSTUVWXYZ EFGH J L Q ST |
Robimy permutację, wstawiamy w brakujące miejsca i do pliku.
Finish!

Link do githuba, ale kod jeszcze nie posprzątany.
2 thoughts on “Gynvael’s Mission 016”
SSTV w 16 misji Gynvaela – MalLog
(8 października 2017 - 18:25)[…] go do przesyłanego obrazu. Mowa tutaj o rozwiązaniu podesłanym przez Adriana Laskowskiego i marbela. Wielki szacunek dla […]
Misje fajne, ale czasu brak – JaProgramista
(16 października 2017 - 00:42)[…] naprawdę miał być podsumowaniem do misji 016, bo rozwiązanie jakie zaprezentował Gynvael trochę mnie zaskoczyło. Analizując sygnał […]