/usd-hackertage-2018-challenge

Mini-Writeup zur Challenge für die usd Hackertage 2018

usd Hackertage 2018 - Challenge

In der diesjährigen (2018) Challenge galt es, Tokens in dem Format usd{[a-z0-9]{32}} in einem Unity Game zu finden. Mindestens eines musste gefunden werden, um sich für eine Anmeldung an den Hackertagen 2018 qualifizieren zu können - maximal 6 gab es zu holen.

Dies war meine erste Teilnahme an einer Challenge von usd. Der folgende Aufschrieb dient hauptsächlich der persönlichen Archivierung.

Zum nachträglichen Nachvollziehen der Lösung kann hier die Challenge heruntergeladen werden: Awareness.zip

Token #1 - app.info

Das erste Token "versteckt" sich in der app.info Datei:

Token 1 in der app.info Datei

Dasselbe Token ließe sich alternativ auch unter C:\Users\User\AppData\LocalLow finden:

Token 1 im AppData Verzeichnis

Token #2 - Asset

Stupides Suchen nach Strings mit einem Text- bzw. Hex-Editor in den Ressourcen-Dateien des Spiels brachte (natürlich) keine weiteren Erkenntnisse.

Offensichtliche Ressourcen-Dateien

Auf der Suche nach Software, die in der Lage ist Unity-Assets zu betrachten, bin ich auf DevXUnity-Unpacker Magic Tools gestoßen. Gibt eine kostenlose Demoversion - top. Fix runtergeladen und den Ordner Awareness_Data damit geöffnet.

Unter Shared-Assets findet sich nun ein Bild mit dem Namen token:

Token 2 - Bild in Shared-Assets

Zwischenschritt

Der Unity-Unpacker kann zwar auch den Quellcode des Spiels dekompilieren, aber nicht editieren oder gar debuggen. Nach kurzer Recherche habe ich dann das Tool dnSpy entdeckt. Kann dekompilieren, kann Code in .NET Assemblies editieren, kann .NET Binaries debuggen... Oh und es gibt sogar eine Anleitung wie man Unity Games debuggen kann!

In meinem Fall musste ich tatsächlich der Turning a release build into a debug build-Anleitung folgen, bis ich mich erfolgreich an einen laufenden Awareness.exe-Prozess anhängen konnte.

Besonders interessant für uns sind die Assemblies Awareness_Data/Managed/Api.dll und Awareness_Data/Managed/Assembly-CSharp.dll - scheinbar ist letztere das Kompilat der Unity C#-Skripte des Entwicklers.

Token #3 - License Key

Beim Starten des Spiels ist der Menüpunkt "New Game" ausgegraut, wir können lediglich "Enter License" oder "Exit" wählen.

Spielmenü beim ersten Start

Wir durchstöbern den Quellcode und stoßen in Assembly-CSharp.dll auf die Klasse RestrictedButton. Dort wird in der Methode Check() festgelegt, ob der Button "aktiv" bzw. "interactable" ist. Wir setzen einen Breakpoint an genau dieser Stelle, wählen "Enter License" im Menü und geben eine beliebige Zeichenkette ein. Der Breakpoint wird getriggert und wir sehen den Wert, mit dem unsere Eingabe verglichen wird:

Token 3 - Lizenzschlüssel

Gibt man das Token dann als Lizenz ein, wird der Menüpunkt "New Game" freigeschaltet.

Token #4 - Highscore

In der Klasse HttpApi setzen wir einen Breakpoint in der Start() Methode und wählen im Menü "New Game". Der Breakpoint wird getriggert und wir können die Klassenfelder endpoint und key auslesen.

HTTP API Endpoint und Key

Wir entnehmen den restlichen Methoden der Klasse, dass es die API Endpoints /players und /highscore zu geben scheint. Ein Aufruf von /players gibt einen einfachen Integer zurück - angeblich die Anzahl der Spieler.

Wesentlich interessanter sind da die Methoden PostHighScore und SecureMessage:

Methoden der HttpApi Klasse

Kurz: Um einen Highscore einstellen zu können, müssen wir den entsprechenden Score zusammen mit einem HMAC bestehend aus dem Score als Nachricht und dem zuvor identifizierten API key als Secret and den /highscore Endpoint posten. Wie deutlich im Code zu sehen muss SHA256 zum hashen verwendet werden.

Token 5 - Response auf das Posten eines Highscores

Für die schnelle Erzeugung des HMAC habe ich diese Seite verwendet.

Token #5 - HTTP API Secret

Wir schauen uns die Klasse ApiSecret aus dem Api.dll Assembly an.

ApiSecret Code

Ok - GetString sieht schonmal gruselig aus. Aber wir sehen, dass scheinbar je nachdem von welcher Methode aus GetSecret aufgerufen wird, wir ein anderes Secret bekommen.

Seltsamerweise wird GetSecret aber nie getriggert, kein Breakpoint greift. Wir behelfen uns, indem wir die Methode manuell von einer Stelle aus aufrufen, von der wir wissen, dass sie garantiert beim Starten des Spiels aufgerufen wird: HttpApi.Start():

Die Modifizierte Methode

Nun setzen wir einen Breakpoint in ApiSecret, Zeile 29. Wir wählen wieder "New Game" und unser Breakpoint wird getriggert. Wir überspringen diese Zeile und editieren dann die Variable flag, sodass diese nun false statt true beinhaltet. Jetzt steppen wir im Debugger bis zum Ende der Methode und erhalten unser Token.

Token 5 - Das alternative API secret

Token #6 - Screenshot

Beim Betrachten der Klasse ScreenshotUtil fällt uns auf, dass Irgendwas komisches mit dem Bild gemacht wird, bevor es gespeichert wird:

Code der ScreenshotUtil Klasse

Ein Overlay wird über das Bild gelegt - bei den betroffenen Pixeln wird der Red-Channel um 0.01 inkrementiert - für das bloße Auge eine nicht zu erkennende Änderung.

Ich habe viel zu viel Zeit damit verbracht, irgendwie nachzuvollziehen, was genau da passiert und wie wohl das Resultat aussehen könnte, bis ic darauf kam, das Inkrement einfach auf eine höhere Zahl zu erhöhen, z.B. 1.0.

Das war dann auch schon die Lösung. Code editiert, kompiliert, Assembly gespeichert, Spiel gestartet, mit F12 einen Screenshot erstellt, die neue Datei capture.png im Hauptverzeichnis des Spiels geöffnet...

Am linken unteren Bildschirmrand war ein vertikal gespiegeltes Token. Also Bild um 180° gedreht und horizontal gespiegelt:

Token 6 - Der Screenshot