CSAW CTF Qualifiers 2012 –
Reversing 300

Auch bei dieser Challenge (Reversing 300) bekommen wir zunächst nur ein .EXE-Binary, das wir der näheren Begutachtung unterziehen müssen. Diese Aufgabe ist der Challenge Reversing 200 sehr ähnlich, so dass wir relativ analog vorgehen und mit einer Untersuchung des Dateityps beginnen können.

rup0rt@lambda:~/CSAW2012$ file CSAWQualification.exe 
CSAWQualification.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

Es handelt sich wiederum um eine Datei, die mit dem Microsoft .NET-Framework erstellt wurde, weshalb wir, genau wie in der vorherigen Challenge auch, zur Bearbeitung eine Virtuelle Maschine (wieder ein Windows XP SP3) verwenden werden. Aus Neugier erfolgt als Erstes auch ein Ausführen der Datei mit dem diesem Ergebnis: ;-).

CSAW CTF 2012 - Reversing 300 - normal execution

Der Ersteller der Challenge fragt uns hier, ob wir wirklich einfach immer die Binarys aus CTFs ausführen (ohne nachzudenken) und es bleibt nur eine Antwort: JA, Natürlich!! Wir sind neugierig und wollen unbedingt wissen, was passiert!! 😛

Unsere Erwartung, dass der Schlüssel zur Challenge einfach direkt ausgegeben wird und wir uns die 300 Punkte sichern können, wird jedoch enttäuscht und wir müssen tatsächlich noch mehr tun, um die Aufgabe zu lösen :-).

Da es sich erneut um ein .NET-Framework-Binary handelt, verwenden wir analog zur Challenge Reversing 200 erst einmal wieder den open-source Decompiler ILSpy, um damit den Quellcode, aus dem die Datei erstellt wurde, zu erhalten. Das Werkzeug liefert uns folgende Ausgabe:

using [...]
namespace CSAWQualification {
  internal class Program {
    private static byte[] data = new byte[] { [...] };
    private static byte[] marker = new byte[] { [...] };
    private static string target = "C:\\Program Files\\";

    private static void Main(string[] args) {
      Console.WriteLine("Do you really just run random binaries given to you in challenges?");
      Console.ReadLine();
      Environment.Exit(0);

      MD5CryptoServiceProvider mD5CryptoServiceProvider = new MD5CryptoServiceProvider();
      AesCryptoServiceProvider aesCryptoServiceProvider = new AesCryptoServiceProvider();

      foreach (string current in Directory.EnumerateDirectories(Program.target)) {
        byte[] first = mD5CryptoServiceProvider.ComputeHash(Encoding.UTF8.GetBytes(current.Replace(Program.target, "")));

        if (first.SequenceEqual(Program.marker)) {
          byte[] rgbKey = mD5CryptoServiceProvider.ComputeHash(Encoding.UTF8.GetBytes("sneakyprefix" + current.Replace(Program.target, "")));
          ICryptoTransform cryptoTransform = aesCryptoServiceProvider.CreateDecryptor(rgbKey, new byte[] { [...] });
          byte[] bytes = cryptoTransform.TransformFinalBlock(Program.data, 0, Program.data.Length);
          Console.Write(Encoding.UTF7.GetString(bytes));
        }
      }
      Console.ReadLine();
    }
  }
}

Das Programm initialisiert zunächst drei Variablen (Zeilen 4-6), wobei “data” das entscheidende Array ist, das unser Ziel, den (noch verschlüsselten) String zur Lösung der Challenge, enthält.

Zu Beginn der “Main”-Funktion (Zeilen 9-11) wir die Ausgabe erzeugt, die wir bereits bei der Ausführung gelesen haben, auf eine Tasteneingabe gewartet und anschließend das Programm beendet.

Anschließend werden alle Unterverzeichnisse des Verzeichnisses “Program Files” erfasst (Zeile 16), deren Namen per MD5 gehash (Zeile 17) und dann mit dem vorher definierten Array “marker” verglichen (Zeile 19). Sollte dies erfolgreich verlaufen, wird der Verzeichnisname als Schlüssel verwendet, um das Array “data” zu entschlüsseln (Zeile 22).

Der essentielle Schritt, zum Lösen dieser Challenge, besteht also darin, das gesuchte Unterverzeichnis von “Program Files” zu bestimmen, dessen Hash im Array “marker” abgelegt ist und verwendet wird, um die Entschlüsselung des Ergebnistextes vorzunehmen.

Das Array “marker” können wir direkt aus dem Quelltext entnehmen und erhalten in hexadezimer Schreibweise:

ff97a9fdede09eaf6e1c8ec9f6a61dd5

Diesen Hash können wir nun an einen Hash-Cracker, hier John the Ripper übergeben, um das Unterzeichnis, das vom Programm gesucht und zur Entschlüsselung verwendet wird, zu erhalten.

rup0rt@lambda:~/CSAW2012$ john -format=raw-md5 rev300.hash
Loaded 1 password hash (Raw MD5 [128/128 SSE2 intrinsics 12x])

Noch während der Cracker arbeitet, können wir uns auf den nächsten Schritt vorbereiten. Da das Programm sich nämlich selbst beendet (Zeile 11), bevor überhaupt die Entschlüsselung starten kann, muss Quelltext verändert werden. In der vorherigen Challenge haben wir aus Faulheit vermieden, das Microsoft Visual Studio Express für C# zu installieren. Dies werden wir nun doch nachholen müssen.

Wir laden also Visual Studio herunter und installieren es auf der Virtuellen Machine…

Anschließend kopieren wir den Quellcode in ein neues Projekt, entfernen die Zeilen 9-11, damit sich das Programm nicht mehr vorab selbst beendet und kompilieren den Code. Zwischenzeitlich hat auch der Hash-Cracker ein Ergebnis geliefert:

rup0rt@lambda:~/CSAW2012$ john -format=raw-md5 rev300.hash
Loaded 1 password hash (Raw MD5 [128/128 SSE2 intrinsics 12x])
Intel            (marker)
guesses: 1  time: 0:00:10:03 DONE (Thu Oct  4 18:54:56 2012)  c/s: 12273K  trying: Inter - Intex

Dem Hash aus dem Array “marker” konnte die Zeichenfolge “Intel” zugeordnet werden! Das bedeutet, wenn ein Unterverzeichnis “Intel” in “Program Files” existiert, wird die Hash-Überprüfung mit dem Array “marker” erfolgreich verlaufen und die Entschlüsselung des Textes im Array “data” durchgeführt.

Wir legen also das Verzeichnis “Program Files\Intel” an und starten das neu kompilierte Programm. Als Ergebnis erhalten wir:

CSAW CTF 2012 - Reversing 300 - solution

Die Lösung lautet somit “6a6c4d43668404041e67f0a6dc0fe243“.

Leave a Reply

Your email address will not be published. Required fields are marked *