CScamp 2012 Quals – Crypt 300

CScamp CTF 2012 - Crypt 300 - task description

Bei dieser Challenge (Crypt 300) sollen wir den originalen Schlüssel zu einem Schlüsseltext bestimmen. Wir erhalten dazu das Verschlüsselungsprogramm, ein Linux 64bit Binary, die Information, dass der Schlüssel alphanumerisch sowie 11 Zeichen lang ist, den Schlüsseltext “7f e7 ff ce 0 98 15 dd 88 fb 6e” und die CRC-XMODEM Prüfsumme 0x8124 des Originalschlüssels.

Zunächst einmal sehen wir uns die Binary genauer an um die Aufgabe etwas besser fassen und das Ziel näher bestimmen zu können:

rup0rt@linux64:~$ ./crypt 111
your encrypted key is : ff ff ff 0 0 0 0 0 0 0 0 
rup0rt@linux64:~$ ./crypt 123456
your encrypted key is : ff 86 89 d3 89 27 0 0 0 0 0 
rup0rt@linux64:~$ ./crypt A A A 
your encrypted key is : 8f 0 0 0 0 0 0 0 0 0 0

Auf den ersten Blick sieht es so aus, dass das crypt-Tool einen Parameter übernimmt, diesen zeichenweise auswertet, dabei das entsprechende Zeichen verschlüsselt und den verschlüsselten Key ausgibt. Wir müssen es demnach schaffen, den originalen Schlüssel (Übergabeparameter) zu finden bzw. so zu wählen, dass der von der Aufgabe geforderte Cipher “7f e7 ff ce 0 98 15 dd 88 fb 6e” entsteht.

Um dies zu erreichen Schreiben wir ein (hier zugegeben sehr unsauberes) Python-Skript, dass den Schlüssel per Brute Force bestimmt:

#!/usr/bin/python

import commands
import re

chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

for c1 in chars:
 if re.match(".* : 7f.*", commands.getoutput("./crypt " + c1)):
  for c2 in chars:
   if re.match(".* : 7f e7.*", commands.getoutput("./crypt " + c1 + c2)):
    for c3 in chars:
     if re.match(".* : 7f e7 ff.*", commands.getoutput("./crypt " + c1 + c2 + c3)):
      for c4 in chars:
       if re.match(".* : 7f e7 ff ce.*", commands.getoutput("./crypt " +c1+c2+c3+c4)):
        for c5 in chars:
         if re.match(".* : 7f e7 ff ce 0.*", commands.getoutput("./crypt " +c1+c2+c3+c4+c5)):
          for c6 in chars:
           if re.match(".* : 7f e7 ff ce 0 98.*", commands.getoutput("./crypt " +c1+c2+c3+c4+c5+c6)):
            for c7 in chars:
             if re.match(".* : 7f e7 ff ce 0 98 15.*", commands.getoutput("./crypt " +c1+c2+c3+c4+c5+c6+c7)):
              for c8 in chars:
               if re.match(".* : 7f e7 ff ce 0 98 15 dd.*", commands.getoutput("./crypt " +c1+c2+c3+c4+c5+c6+c7+c8)):
                for c9 in chars:
                 if re.match(".* : 7f e7 ff ce 0 98 15 dd 88.*", commands.getoutput("./crypt " +c1+c2+c3+c4+c5+c6+c7+c8+c9)):
                  for c10 in chars:
                   if re.match(".* : 7f e7 ff ce 0 98 15 dd 88 fb.*", commands.getoutput("./crypt " +c1+c2+c3+c4+c5+c6+c7+c8+c9+c10)):
                    for c11 in chars:
                     if re.match(".* : 7f e7 ff ce 0 98 15 dd 88 fb 6e.*", commands.getoutput("./crypt " +c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+c11)):
                      print c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+c11


Das Skript brute-forced Zeichen für Zeichen – davon ausgehend, dass bereits gefundene korrekte Zeichen durch das Anfügen weiterer Zeichen nicht mehr verändert werden. Wenn wir dieses Skript nun ausführen, stellen wir jedoch folgendes fest:

rup0rt@linux64:~$ ./crypt300.py 
Sh1IsSh3KeQ
Sh1IsSh3Key
Sh1IsTh3KeQ
[...]

rup0rt@linux64:~$ ./crypt300.py | wc -l
36

Anstatt einem einzigen Schlüssel erhalten wir 36 Lösungen, die den gesuchen Ciphertext ergeben. Da die Schlüssel auch relativ sinnvoll aussehen, sind wir wohl dennoch auf dem richtigen Weg. Man könnte nun versuchen aus den 36 möglichen Schlüsseln, den von der Challenge erwarteten zu erraten…

… oder man nimmt den letzten vom Aufgabensteller gegebenen Hinweis zur Hand, dass die CRC-XMODEM Prüfsumme des Schlüssels 0x8124 betragen soll. Mit diesem Hinweis und Unterstützung der PYCRC Bibliothek können wir unser Python-Skript um den folgenden Quellcode ergänzen:

xmodem = commands.getoutput("./pycrc-0.7.11/pycrc.py --model=xmodem --check-string=" +c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+c11)
print c1+c2+c3+c4+c5+c6+c7+c8+c9+c10+c11 + " (" + xmodem + ")"
if xmodem == "0x8124":
 print "GOT IT!"
 sys.exit(0)

Die Ausführung führt zu diesem Ergebnis:

creeq@f00l:~$ ./crypt300.py 
Sh1IsSh3KeQ (0xc5b2)
Sh1IsSh3Key (0x60d8)
Sh1IsTh3KeQ (0xdf3)
Sh1IsTh3Key (0xa899)
Sh1Ismh3KeQ (0x6a9d)
Sh1Ismh3Key (0xcff7)
Sh1qsSh3KeQ (0x9db4)
Sh1qsSh3Key (0x38de)
Sh1qsTh3KeQ (0x55f5)
Sh1qsTh3Key (0xf09f)
Sh1qsmh3KeQ (0x329b)
Sh1qsmh3Key (0x97f1)
Th1IsSh3KeQ (0xec0f)
Th1IsSh3Key (0x4965)
Th1IsTh3KeQ (0x244e)
Th1IsTh3Key (0x8124)
GOT IT!

Die Lösung lautet somit “Th1IsTh3Key“.

Leave a Reply

Your email address will not be published.