CSCG CTF - APDU Decode und Crack

Bevor wir uns den harten Nüssen Captcha 3 und 4 widmen, gibts eine Aufgabe an der ich gefühlte Ewigkeiten saß. Es geht um das Decoden eines APDU Protokolls. Dabei handelt es sich um eine serielle Übertragung zwischen einem PC und einer sog. Smartcard. Man bekam man einen Mitschnitt der übertragenen Daten vor die Füße geworfen und musste nun eine Challenge-Response Verifikation knacken. “Smartcard, APDU, Challange-Response”? Alles Begriffe, die man zwar schonmal gehört hat, aber nicht richtig zuordnen kann.

Die Analyse der Sniff-Datei begann und die Stunden zogen sich hin. Ich gebe zu, dieser Ansatz war nicht gerade kreativ. Ich versuchte Muster in dem Protokoll zu erkennen und diese auf Aktionen zurückzuführen. Das mag in der Protokollanalyse des Gamehackings funktionieren, da man dort Aktionen selbst hervorrufen kann. Aber in diesem Fall war es verschwendete Zeit. Bis schließlich (mehr aus Frust als aus Intelligenz) ein paar der Bytes als Hex-Encodierte ASCII Strings betrachtet wurden. Und siehe da, MSCM erschien. Nach ein wenig Suchen des Begriffs “MSCM” in Verbindung mit APDU, war klar dass die .NET Library von gemalto verwendet wurde. Ab hier war das Spiel mehr oder weniger einfach: Auf der Website fand sich eine detailierte Beschreibung des APDU Protkolls in Verwendung mit Smartcards. Besonders interessant war dabei natürlich der Teil der Dokumentation, welcher von der Challenge-Response handelt:

ChallengeResponse

Quelle: APDU Doku Seite 123

Der sog. “Hivecode” für die GetChallenge-Methode ist FA3B. Und siehe da:

transmitted:
80 C2 00 00 12 D8 00 05 6F 00 C0 4B 4E 7F BD FA 3B 00 04 4D 53 43 4D
received:
  61 12
transmitted:
  00 C0 00 00 12
received:
  00 D2 5D 1C 45 A3 00 00 00 08 CF CB C8 42 8E 8A C3 61 90 00
transmitted:
  80 C2 00 00 1E D8 00 05 6F 00 C0 4B 4E 7F BD 24 FE 00 04 4D 53 43 4D 00 00 00
  08 2B 22 D6 F1 DA 2D D4 A2
received:
  90 00

FA 3B in der obersten Zeile fordert eine Challenge der Smartcard an. Diese Antwortet mit “Alles klar, ich übertrage Dir 0×12 Byte”. Der Computer antwortet wieder mit “Gib mir die nächsten 0×12 Byte” und die Smartcard haut die Challenge raus. Dabei ist “45 A3″ der Typen-Bezeichner für System.Byte[] und “00 00 00 08″ die Länge des folgenden Bytes. Somit ist unsere Challenge: CF CB C8 42 8E 8A C3 61. Wo eine Challenge, da ist auch die Response nicht weit. In der nächsten Antwort findet sich wieder ein Byte-Array mit Länge 8, dahinter folgt die Response: 2B 22 D6 F1 DA 2D D4 A2. Die Smartcard antwortet mit “ALLES KLAR” (90 00) und man ist eingeloggt.

In der Aufgabenstellung war eine weitere Information gegeben: Der Key, welcher zum einloggen verwendet wird, ist 4 Ziffern lang. Problematisch ist nur, dass wir es hier mit einer TripleDES Verschlüsselung im CBC Mode zutun haben. Der gesuchte Key ist also 24 Byte lang! Schnell war das gemalto SDK installiert und ein neues C#-Projekt erstellt. Mit diesem konnte man sich zu einem passenden Key und einer passenden Challenge eine Response ausrechnen lassen. Wir müssen also Brute-Forcen!

Die Challange hätte hier innerhalb von 10 Minuten vorbei sein können, hätte sich nicht ein Fehler im Programmcode eingeschlichen. Ich konnte Brute-Forcen und rumpadden wie ich wollte, es kam nie die gesuchte Response raus. Das Problem versteckte sich in der Library selbst: Der übergebene Key, in Form eines Byte-Arrays, wird in .NET “By Ref” übergeben. In Klartext übersetzt bedeutet dies, dass Byte-Arrays als Referenzen (und somit als Zeiger) an die Funktion übergeben werden. Wenn die Funktion den Eingabeparameter verändert, ändert sich auch das Byte-Array außerhalb der Funktion. Dies war der Fall mit dem Challenge-Byte-Array. Nach jedem versuchten Key hat sich die Challenge verändert. So war es unmöglich die passende Response zur Challenge zu finden.

Lange Rede kurzer Sinn, hier der Codeausschnitt zum Berechnen des Keys:

BruteForceAlgorithm.BruteForceTest testCallback = delegate(ref char[] test, int testIndex, int testMax)
{
    byte[] array = new byte[8];
    for (int i = 0; i < 4; i++)
        currentTestArray[i] = (byte) (test[i]);
 
 
    Program.des.Process3Des(currentTestArray, tempChallange, array);
    tempChallange = new byte[] {0xcf, 0xcb, 0xc8, 0x42, 0x8e, 0x8a, 0xc3, 0x61};
 
    var retVal = (array[0] == 0x2B && array[1] == 0x22 && array[2] == 0xD6 && array[3] == 0xF1);
    if (retVal == true)
    {
        // Debugger Break
        String s = "br";
    }
    return (array[0] == 0x2B && array[1] == 0x22 && array[2] == 0xD6);
};
 
if (BruteForceAlgorithm.BruteForce("0123456789", 4, testCallback))
{
    Console.WriteLine("Success! Combination found!");
}

Der damit errechnete Key war: 0868. Ob dies richtig ist, zeigt uns das im SDK enthaltene Tool zum berechnen einer Response bei gegebener Challange und Key:

5 people like this post.
  1. Noch keine Kommentare vorhanden.

  1. Noch keine TrackBacks.