Na początek jednak garść statystyk.
- Plik został pobrany 236 razy.
- Przesłano 114 flag, w tym 92 były poprawne.
- Odpowiedzi przesłały 23 osoby, w tym 13 z Polski.
- Prawie wszyscy uczestnicy znaleźli 3 lub więcej flag.
Zwycięzcom gratulujemy i mamy nadzieję, że wszyscy się dobrze bawili.
Zadanie polegało na znalezieniu 10 flag w przygotowanym przez nas pliku. Poniżej opisane są sposoby znalezienia wszystkich 10 flag w kolejności od najczęściej znajdowanej do tej najmniej popularnej.
Flaga: ThisWasEasyToFind!
(20 zgłoszeń)
Kilkadziesiąt minut po ogłoszeniu konkursu plik znalazł się już w serwisie VirusTotal. Dwa z testowanych programów błędnie rozpoznało go jako malware. W zakładce „Szczegóły pliku” znalazła się jednak jedna z flag. Hasło to zostało ukryte jako komentarz w metadanych pliku, które wyświetlane są (przynajmniej w systemie Windows XP) po wejściu we „właściwości” pliku tak jak na zdjęciu po lewej. Alternatywnie, jeśli nasz system nie wyświetla tych metadanych, wystarczyło skorzystać z narzędzia strings
z przełącznikiem -e l
oznaczającym wypisanie wszystkich znalezionych w pliku tekstów zapisanych w kodowaniu Unicode 16-bitowym w konwencji Little Endian. Wyjście polecenia zaprezentowano poniżej, flaga znajduje się w 9 linii.
$ strings -e l ./CrackMe.exe
INTERESTING_PCITURE
VS_VERSION_INFO
VarFileInfo
Translation
StringFileInfo
04090025
Comments
flag{ThisWasEasyToFind!}
CompanyName
CERT Polska
FileDescription
CrackMe
FileVersion
InternalName
LegalCopyright
CERT Polska
LegalTrademarks
OriginalFilename
PrivateBuild
ProductName
CrackMe
ProductVersion
SpecialBuild
Flaga: HowToFindStringsInPEYouKnow
(15 zgłoszeń)
Tę flagę można było uzyskać za pomocą narzędzia strings
. Wystarczyło jedynie rozpakować plik EXE. Plik ten był spakowany za pomocą popularnego packera o nazwie UPX, a następnie zmieniono w nim nazwę jednej z sekcji ze standardowej na niestandardową. Powodowało to, że rozpakowanie pliku powodowało wyświetlenie następującego komunikatu:
$ upx -d ../CrackMe.exe
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2013
UPX 3.09 Markus Oberhumer, Laszlo Molnar & John Reiser Feb 18th 2013
File size Ratio Format Name
-------------------- ------ ----------- -----------
upx: ../CrackMe.exe: CantUnpackException: file is modified/hacked/protected; take care!!!
Unpacked 0 files.
Offsety 179-17C zawierały ciąg znaków XXX0
, a w standardowo spakowanym pliku tym ciągiem powinno być nazwa sekcji UPX0
. Zmianę tej nazwy można było wykonać dowolnym edytorem tekstowym. Po zmianie plik rozpakowuje się normalnie, a wykonanie na nim polecenia strings
powoduje znalezienie ciągu znaków ZmxhZ3tIb3dUb0ZpbmRTdHJpbmdzSW5QRVlvdUtub3d9Cg==
, który po zdekodowaniu za pomocą base64 daje nam kolejną flagę.
Flaga: HaveNoFear,ConsoleFlagIsHere!
(13 zgłoszeń)
Znalezienie tej flagi również nie sprawiało większych problemów. Wystarczyło mieć uruchomiony program windowssystem32cmd.exe
i następnie uruchomić nasze CrackMe. W konsoli powinna się wtedy wypisać flaga tak, jak to przedstawiono na zrzucie ekranu poniżej.
Flaga: VeryGoodHardDriveName
(10 zgłoszeń)
Po uruchomieniu pliku CrackMe.exe
drugim oknem dialogowym, które się wyświetlało było okno przedstawione po lewej. Zawierało ono podpowiedź, która wskazywała na malware o nazwie Andromeda. Malware ten implementował technikę sprawdzającą czy jest uruchomiony na maszynie wirtualnej. Jeśli tak było, to wykonywał inny kod niż gdyby był uruchomiony na zwykłej maszynie. Jednak autorzy malware’u również testowali go na maszynie wirtualnej, więc wymyślili sposób, aby go na niej uruchomić. Wystarczyło zmienić nazwę dysku C:
na taką, której CRC32 wynosi 0x20C7DD84
(najbardziej znany przykład to CKF81X
). Wtedy nasze CrackMe wyświetlało, zamiast wcześniejszego okna dialogowego, nowe, już zawierające flagę takie jak poniżej.
Flaga: YouKnowHowToDebugCode!
(9 zgłoszeń)
Aby uzyskać tę flagę, trzeba było zdebugować nasze CrackMe. Można to zrobić za pomocą darmowego narzędzia OllyDbg, albo za pomocą IDA Pro. Kod wywoływał funkcję IsDebuggerPresent
, która sprawdzała czy proces jest debuggowany i jeśli tak było to wyświetlał monit You shall not pass!
. Jednak po jego wyświetleniu wywoływana była funkcja, której wynikiem było wypisanie ciągu znaków za pomocą OutputDebugString
. Ciąg ten był tworzony za pomocą xorowania ciągu znaków changeme
z wcześniej „zaszyfrowanym” tekstem przedstawionym jako ciąg bajtów:
0x39,0x47,0x47,0x46,0xa,0x6,0x44,0x53,0x6a,0x1f,0x30,0x5c,0x6e,0x4e,0x6,0xb,0x44,0x62,0x44,0x13,0x2a,0x4c,0x65,0x4e,0x15,0x3a,0xa,0x5b
Oczywiście trzeba było zmienić ciąg znaków changeme
na właściwe hasło. Można to było wykonać korzystając z faktu, że operacja xor jest operacją odwrotną do samej siebie oraz z faktu, że pierwsze pięć znaków każdej flagi to flag{
, a tylko 5 bajtów z ciągu changeme
było wykorzystywane. Wyliczenia wyglądają następująco:
0x39 xor 0x66 ('f') = 0x5f ('_')
0x47 xor 0x6c ('l') = 0x2b ('+')
0x47 xor 0x61 ('a') = 0x26 ('&')
0x46 xor 0x67 ('g') = 0x21 ('!')
0x0a xor 0x7b ('{') = 0x71 ('q')
Zatem hasłem jest _+&!q
i po rozkodowaniu powyższej tablicy bajtów otrzymujemy zadaną flagę. Można to zrobić albo rozkodowując tablicę za pomocą skryptu, albo po prostu zmieniając w debuggerze ciąg znaków changeme
na _+&!q
.
Flaga: RussianFlagItIs
(8 zgłoszeń)
Tę flagę było stosunkowo łatwo znaleźć, ale osoby, które ją znalazły często źle ją interpretowały. Flaga znajdowała się w nagłówku pierwszego okna dialogowego, które pojawiało się po uruchomieniu CrackMe. Była ona zapisana cyrylicą i trzeba było ją transliterować, zgodnie z zasadami transliteracji, aby otrzymać ciąg znaków ASCII. Kilka osób wysłało flagę w oryginalnej pisowni, cyrylicą, nie czytając dokładnie opisu konkursu, w którym wyraźnie zaznaczyliśmy, że wszystkie flagi składają się z drukowalnych znaków ASCII bez znaków białych. Transliteracji można było dokonać np. za pomocą usługi Google Translate. Jedną z przeszkód mogło też być podobieństwo w cyrylicy znaków ф oraz Ф (odpowiednio małe i duże „f”) lub w ogóle ignorowanie wielkości liter. Jednak sprawiło to problem tylko dwóm uczestnikom.
Flaga: RC4EncryptionIsFun!!!1
(6 zgłoszeń)
Plik CrackMe tworzył plik systemowy decode.py
w katalogu %TEMP%
. Plik ten zawierał następujący kod języka Python:
from Crypto.Cipher import ARC4
from base64 import b64decode
import sys
obj = ARC4.new(sys.argv[1][:5])
text = b64decode('LNLyv86npNDGrMxHrbpzHGoueiX3d3SPOmIZAg==')
text = obj.decrypt(text)
print text
Kod ten dekodował najpierw, za pomocą base64, ciąg znaków z linii 5, a następnie deszyfrował go za pomocą klucza podanego z linii poleceń. Tylko pierwsze 5 znaków klucza było brane pod uwagę. Najprostszym sposobem odszyfrowania tekstu była metoda brute force. Wykonanie jej na 5 drukowalnych znakach ASCII za pomocą bardzo prostego skryptu Pythona przedstawionego poniżej powinno zajmować około 10 godzin, w zależności od użytej maszyny. Zrównoleglając proces poszukiwania, albo wręcz przepisując go np. na język C, proces ten można było skrócić nawet do 2-3 godzin.
from Crypto.Cipher import ARC4
from base64 import b64decode
import sys
import itertools, string
org = b64decode('LNLyv86npNDGrMxHrbpzHGoueiX3d3SPOmIZAg==')
for i in itertools.product(string.printable, repeat=5):
key = ''.join(i)
obj = ARC4.new(key)
text = obj.decrypt(org)
if text.startswith('flag{'):
print key, text
Prawidłowym kluczem, i jedynym wynikiem powyższego skryptu, było Oi01_
.
Flaga: JPEGalsoHasAFlag
(5 zgłoszeń)
Po rozpakowaniu pliku exe za pomocą UPX jednym z zasobów w nim schowanych było archiwum xz
. Zasób ten można wydobyć np. za pomocą darmowego narzędzia ResEdit. Po rozpakowaniu tego archiwum otrzymywaliśmy jeden plik o nazwie picture.png
. Po otwarciu tego pliku prezentowana była flaga, tak jak na obrazku po prawej stronie.
Flaga: PNGdoesNotHaveExif,ButStillIsFun
(4 zgłoszenia)
W wyżej wspomnianym pliku PNG znajdował się również pewien specjalny chunk. Chunk to dodatkowe informacje, które mogą być zawarte w pliku PNG. Niektóre są niezbędne, np. ten zawierający rozmiary obrazu, podczas gdy inne są czysto informacyjne. Jednym z najprostszych sposobów na wyświetlenie tych wartości jest użycie narzędzie strings, tak jak zaprezentowano poniżej.
$ strings -n7 picture.png
tEXtComment
Created with GIMPW
-tEXtFlag4U
flag{PNGdoesNotHaveExif,ButStillIsFun}2+
>}!fYYY
Flaga: DOSisPower
(2 zgłoszenia)
Ostatnia z flag była ukryta jako program systemu DOS. Pliki PE, ze względu na kompatybilność wsteczną, na początku mogą zawierać program, który uruchamia się pod systemem DOS. Zwykle jest to program wyświetlający napis This program cannot be run in DOS mode.
Tym razem jednak ten stub został podmieniony na inny program, którego kod jest zaprezentowany poniżej. Warto przypomnieć, że kod DOS jest 16-bitowy.
00 0e push cs
01 1f pop ds
02 be0000 mov si, 0x0
05 bb2200 mov bx, 0x22
08 b86600 mov ax, 0x66
0b 3200 xor al, [bx+si]
0d 8800 mov [bx+si], al
0f 46 inc si
10 81fe1000 cmp si, 0x10
14 75f5 jnz 0xb
16 ba2200 mov dx, 0x22
19 b409 mov ah, 0x9
1b cd21 int 0x21
1d b8004c mov ax, 0x4c00
20 cd21 int 0x21
Program ten bierze ciąg znaków znajdujący się pod offsetem 0x22
a następnie dekoduje go do flagi. Dekowanie odbywa się za pomocą prostego algorytmu. Pierwszy znak jest xorowany z liczbą 0x66
(offset 0x08, 0x0b) , a każdy następny z poprzednio odszyfrowanym bajtem. W ten sposób otrzymujemy tekst flagi, który ma 16 znaków (offset 0x10). Następnie flaga jest wyświetlana (offsety 0x16, 0x19, 0x1b) i program zwraca kod wyjścia 0 (offsety 0x1d, 0x20).
Aby uzyskać tę flagę wystarczyło uruchomić program pod systemem DOS, np. za pomocą programu DOSBox. Wykonanie zaprezentowano po prawej.
Podsumowanie
Konkurs nie okazał się zbyt trudny (i taką mieliśmy nadzieję). Pierwszy zestaw 10 flag dostaliśmy od osoby z Polski w sobotę, 5 kwietnia o 18:50:09 CEST. Z zagranicy komplet flag otrzymaliśmy o w niedzielę, 6 kwietnia o godzinie 18:48:06 CEST. Zwycięzcom jeszcze raz gratulujemy!