Writeup: FlareOn 2022: 010 - Nur geträumt

Task description

1. TLDR

TLDR graph

2. Dane wejściowe

Plik z zadaniem znajduje się tutaj. Hasło: flare.

Przedmiotem zadania były pliki:

Nur geträumt.img
README.txt

Zweryfikowałem typ pliku Nur geträumt.img:

$ file Nur\ geträumt.img
Nur getra\314\210umt.i: Apple DiskCopy 4.2 image Nur getr\212umt, 1474560 bytes, MFM CAV dshd (1440k), 0x2 format

Plik README.txt zawierał wiadomość:

This challenge is a Macintosh disk image (Disk Copy 4.2 format, for those who need to
know) containing a 68K Macintosh program.  You must determine the passphrase used to
decode the flag contained within the application.  Super ResEdit, an augmented version of
Apple's ResEdit resource editor which adds a disassembler, is also included on the disk
image to help you complete the challenge, though you will likely also need to do some
outside research to guess the passphrase.

This application can be run on any Macintosh emulator (or any real Macintosh from as far
back as a Mac Plus running System 6.0.x up to a G5 running Classic).  The setup of the
emulation environment is part of the challenge, so few spoilers live here, but if you
want to save yourself some headaches, Mini vMac is a pretty good choice that doesn't take
much effort to get up and running compared to some other options.

This application was written on a Power Macintosh 7300 using CodeWarrior Pro 5, ResEdit,
and Resourcerer (my old setup from roughly 1997, still alive!).  It was tested on a great
many machines and emulators, and validated to run well on Mac OS from 6.0.8 through 10.4.

Happy solving!  Be curious!

3. Analiza wstępna

Podjąłem próbę rozpakowania pliku Nur geträumt.img. W tym celu pobrałem narzędzie Convert2Dsk. Convert2Dsk to aplikacja do konwersji obrazów Disk Copy 4.2 na surowe obrazy dysków:

>convert2dsk.exe ".\Nur getraůumt.img"
Converting ".\Nur geträumt.img"... success!

Następnie załadowałem obraz dysku do narzędzia FTK Imager:

ftk-image

Na tym etapie nie znalazłem nic istotnego. Postanowiłem zainstalować i skonfigurować emulator.

4. Instalacja i konfiguracja emulatora

Posiłkując się instrukcją znalezioną na YouTube, przeprowadziłem poniższą konfigurację.

Proces zakończyłem z przygotowanym Mini vMac

desktop

5. Analiza zawartości dysku

Zamontowałem plik Nur geträumt.dsk (oryginalną nazwę pliku i katalogu zmieniłem z powodu problemów z załadowaniem do emulatora).

Widoczne były dwa pliki:

  1. Aplikacja Nur geträumt
  2. Narzędzie Super ResEdit 2.1.3

disk-mounted

Po uruchomieniu programu Nur geträumt wyświetlane było okno z komunikatem zachęcającym do wprowadzenia hasła:

gui-no-password

Po wprowadzeniu przypadkowego hasła prezentowany był losowy ciąg tekstowy:

gui-wrong-password

6. Analiza pliku

Załadowałem plik z programem do narzędzia Super ResEdit 2.1.3:

resedit-elements

Aplikacja miała zdefiniowane 2 alerty:

resedit-alrts

Aplikacja miała zdefiniowany 1 nienazwany blok danych:

resedit-data

Aplikacja miała zdefiniowany 3 etykiety na potrzeby okien dialogowych:

resedit-ditls

Oprócz tego, aplikacja miała zdefiniowany interesujący zasób FLAG:

resedit-password

Definicję zasobu FLAG można było podejrzeć w Super ResEdit 2.1.3:

resedit-crc16

oraz odczytać poszczególne wartości w hex edytorze:

resedit-crc16-hex

Analiza zasobu TMPL pozwoliła ustalić typy danych:

resedit-crc16-types

Z lektury ResEdit Reference For ResEdit 2.1 wiadomo, że PSTR to Pascal string, a HWRD to hex word:

Zatem 0x30 to rozmiar całej struktury (48 bajtów). 0x2D to długość Pascal string (45 bajtów) a dwa ostatnie bajty 27 18 to wartość CRC16:

Oprócz wyżej wymienionych elementów widoczne były m.in. kod aplikacji, formatki oraz duży blok tekstu:

resedit-text

o zawartości:

Hello there.

I'm from the DISTANT FUTURE, where normal computers run at 2-4 GHz and 16 GB is
considered a "medium" amount of RAM.  That's right; we have more RAM than you 
have hard drive space.

The good news:

- Unicode really seems to have worked, for the most part. We even have characters
for clown faces and smiling piles of poo.
- The Mac is still a pretty big deal, and can still read this program (but hasn't
been able to run it for a while).
- Nearly all computers in the world are connected together through a network 
called the Internet.  Depending on when you read this, you may have heard of it.
Don't get rid of MacTCP just yet.

The bad news:

- Nearly all computers in the world are connected together through a network 
called the Internet. This has made a lot of people very angry and been widely
regarded as a bad move.
- Despite having 16 GB of RAM, Microsoft Word still takes up roughly half of it.
- We're still using Microsoft Word.

Anyway, because in the future we're stuck at home due to a worldwide pandemic
(no, not the Internet, there is ANOTHER one), we had a competition for finding
fun things in computer programs. I've hidden a flag in this program, but it's
not going to be all that easy to find just with ResEdit.

You'll probably need to interact with the program a bit.  It will let you know
when you've found the right flag.  I've done you the favor of including Super
ResEdit here, which has a disassembler, and I'm even nice enough to give you
the debug version of the program with all the symbol names, to give you a head
start (because I'm not wicked enough to make you step through it with MacsBug,
but you could if you wanted).

Here's your first hint: 1983 was a pretty good year in music.

Have fun, and enjoy the challenge!

- Dave Riley, July 2022

7. Analiza kodu wykonywalnego

Analizując kod w programie Super ResEdit zauważyłem funkcję decodeFlag:

resedit-decodeflag-01 resedit-decodeflag-02

Zauważyłem pod offsetem ++048 rozkaz EOR.W odpowiadający za operację XOR (Exclusive OR).

8. Odczytanie flagi

W celu odczytania flagi przyjąłem założenia:

  1. Flaga została zaszyfrowana algorytmem OTP
  2. Tekst jawny zawiera postfix @flare-on.com

Znając fragment tekstu jawnego podjąłem próbę odzyskania części klucza:

import malduck

known_plaintext = "@flare-on.com"
msg_length = 0x2D
plaintext = (msg_length-len(known_plaintext))*'a'+known_plaintext
plaintext_bytes = plaintext.encode('latin1')
ciphertext_bytes = b'\x0C\x00\x1D\x1A\x7F\x17\x1C\x4E\x02\x11\x28\x08\x10\x48\x05\x00\x00\x1A\x7F\x2A\xF6\x17\x44\x32\x0F\xFC\x1A\x60\x2C\x08\x10\x1C\x60\x02\x19\x41\x17\x11\x5A\x0E\x1D\x0E\x39\x0A\x04'
key = malduck.xor(plaintext_bytes, ciphertext_bytes)
print(key)

Na standardowym wyjściu odczytałem tekst:

b'ma|{\x1ev}/cpIiq)daa{\x1eK\x97v%Sn\x9d{\x01Miq} du etwas Zei'

Widoczny fragment tekstu du etwas Zei był fragmentem piosenki Neny z albumu 99 Luftballons, co korespondowało z artefaktami znalezionymi w aplikacji.

Pierwszy wers słów tej piosenki to:

Hast du etwas Zeit für mich?

Użyłem tego zdania jako klucza:

ciphertext_bytes = b'\x0C\x00\x1D\x1A\x7F\x17\x1C\x4E\x02\x11\x28\x08\x10\x48\x05\x00\x00\x1A\x7F\x2A\xF6\x17\x44\x32\x0F\xFC\x1A\x60\x2C\x08\x10\x1C\x60\x02\x19\x41\x17\x11\x5A\x0E\x1D\x0E\x39\x0A\x04'
key = 'Hast du etwas Zeit fur mich?'
key_bytes = key.encode('latin1')
plaintext_bytes = malduck.xor(key_bytes, ciphertext_bytes)
plaintext= plaintext_bytes.decode('latin1')
print(plaintext)

Na standardowym wyjściu odczytałem tekst:

Dann_singe_ich_ein_Led_fr_dich@flare-on.com

Wpisanie klucza do programu skutkowało odczytaniem flagi:

resedit-flag