ATAST CTF Quals 2012 –
Chall2_200pts (crack1)

Wie so oft werden wir auch bei dieser Challenge (crack1) einfach nur mit den Worten

“get the password”

begrüßt. Dieses Passwort sollen wir aus einer Binärdatei extrahieren.

Sehen wir uns also als Erstes den Typ des Binarys an:

rup0rt@lambda:~$ file crack1
crack1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x4579db2a2ebe3b4e83948f7a650dc3fced1d812d, not stripped

Es handelt sich um ein einfaches Linux-32bit-Programm.

Wir führen das Programm zunächst einmal aus um uns einen Überblick über dessen Funktionsweise zu verschaffen:

creeq@linux:~/ATAST2012$ ./crack1 
Password Required : 12345 
Wrong !!!! better luck next time :D

Es wird eine Passwortabfrage durchgeführt, die uns anschließend, bei Eingabe von “12345”, mit “falsch” beantwortet wird. Unser Ziel ist es daher, den Programmcode zu untersuchen um festzustellen, wie genau das Passwort überprüft wird und so an die korrekte Lösung zu gelangen.

Dafür nutzen wir “objdump” um an den Assembler-Code des Binarys zu gelangen. Dabei fallen folgende Inhalte in der <main>-Funktion auf:

804865f:     mov    eax,DWORD PTR [esp+0x2c]
8048663:     mov    edx,DWORD PTR [esp+0x2c]
8048667:     movzx  edx,BYTE PTR [esp+edx*1+0x32]
804866c:     xor    edx,0x21

804866f:     mov    BYTE PTR [esp+eax*1+0x68],dl
8048673:     mov    eax,DWORD PTR [esp+0x2c]
8048677:     mov    DWORD PTR [esp+0x8],eax
804867b:     lea    eax,[esp+0x68]
804867f:     mov    DWORD PTR [esp+0x4],eax
8048683:     lea    eax,[esp+0x54]
8048687:     mov    DWORD PTR [esp],eax
804868a:     call   80484d0 <strncmp@plt>

804868f:     test   eax,eax
8048691:     jne    804869a <main+0x106>
8048693:     add    DWORD PTR [esp+0x2c],0x1
8048698:     jmp    80486ad <main+0x119>

In Zeile 4 wird eine XOR-Operation auf einen statischen Byte-Wert angewendet. Dies ist für gewöhnlich nur dann der Fall, wenn Daten im Programm versteckt wurden. Anschließend (Zeile 13) wird die “strcmp”-Funktion ausgeführt um den mit XOR erhaltenen Wert, mit den von uns eingegebenen Passwort-Buchstaben zu vergleichen. Zuletzt (Zeile 15) wird geprüft, ob die Zeichen überein stimmen und bei Erfolg der Buchstaben-Zähler (Zeile 17) erhöht.

Zusammengefasst wird also das von uns eingegebene Passwort mit einer im Programm per XOR verstecken Zeichenkette verglichen. An diesen String müssen wir gelangen! Dem Assembler-Code zur Folge befindet sich die gesuchte Zeichenkette an Position “esp+edx*1+0x32” (Zeile 3). Da “edx” der Schleifenzähler ist (und bei Null beginnt) suchen wir nur die Position “esp+0x32“. Die entsprechende Zuordnung finden wir hier ebenfalls im Assembler-Code:

80485b4:     mov DWORD PTR [esp+0x32],0x48534e59
80485bc:     mov DWORD PTR [esp+0x36],0x52404452
80485c4:     mov DWORD PTR [esp+0x3a],0xbdbfef58
80485cc:     mov DWORD PTR [esp+0x3e],0xefbdbfef
80485d4:     mov DWORD PTR [esp+0x42],0xbfefbdbf
80485dc:     mov DWORD PTR [esp+0x46],0xbfc256bd
80485e4:     mov DWORD PTR [esp+0x4a],0xbdbfef39
80485ec:     mov DWORD PTR [esp+0x4e],0xbdbfef24
80485f4:     mov WORD PTR [esp+0x52],0x78

Die Ersteller der Challenge haben hier Daten statisch in das Binary codiert, was zu Beginn der Betrachtung schon auffällig war. Dem Anschein nach befinden sich hier jedoch mehr Daten als nur das Passwort. Daher sollte vorher geprüft werden, wie lang das Passwort ist, das heißt, wann die XOR-Schleife also regulär verlassen wird. Diese Information finden wir, wenn wir dem Sprung von Speicheradresse 8048698 (Zeile 18) folgen.

80486ad:     mov ebx,DWORD PTR [esp+0x2c]
80486b1:     lea eax,[esp+0x54]
80486b5:     mov DWORD PTR [esp],eax
80486b8:     call 8048490 <strlen@plt>
80486bd:     cmp ebx,eax
80486bf:     jb 804865f <main+0xcb>

80486c1:     cmp DWORD PTR [esp+0x2c],0xa
80486c6:     jne 80486d4 <main+0x140>

Zunächst wird in Zeile 4, erneut mittels “strlen” geprüft, ob die Länge unserer Zeichenkette mit der Anzahl per XOR durchlaufener Zeichen überein stimmt. Wenn weitere Zeichen per XOR zu bearbeiten sind, dann wird an den Beginn der XOR-Schleife zurück gesprungen (Zeile 6). Das Interessante ist hier jedoch Zeile 8, in der die Zählvariable (esp+0x2c) mit 0xa (10) verglichen wird. Bei Misserfolg wird das Programm beendet! Das bedeutet, dass das gesuchte Passwort 10 Zeichen (inklusive Zeilenumbruch bzw. bereits inkrementierter Zählvariable) lang sein muss.

Wir entnehmen also 9 Zeichen in Network-Byte-Order aus dem Assembler-Code und erstellen ein kleines C-Programm, dass die XOR-Operationen darauf vornimmt:

#include <stdio.h>
#include <string.h>

char crypt[9] = "\x59\x4e\x53\x48\x52\x44\x40\x52\x58";
int i;

int main() {

  for (i=0;i<strlen(crypt);i++) {
    printf("%c", crypt[i] ^ 0x21);
  }

  printf("\n");
}

Nach Kompilierung und Ausführung erhalten wir folgendes Ergebnis:

rup0rt@lambda:~/ATAST2012$ gcc chall2.c -o chall2

rup0rt@lambda:~/ATAST2012$ ./chall2
xoriseasy

Die Lösung der Challenge lautet somit “xoriseasy“.

Leave a Reply

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