## REE / Prof. Smits / WS 22-23 / Hochschule Mannheim ### Team 12 <br> Names: Mike, Gabriel, Kyrill <br>MatNr.: 1921224, 1925874, 1926420 # Assignment_13 - Schreiben Sie auf, wie Sie vorgegangen sind, und zwar so, dass ein fachkundiger Dritter Ihre Schritte nachvollziehen kann. - Gab es Probleme? - Welche Information konnten Sie extrahieren? - Falls es ein Flag gab, wie lautete das Flag? ## Reconnaissance Folgende Datei wurde zu verfügung gestellt und sollte Untersucht werden: [password_check_4](https://gitty.informatik.hs-mannheim.de/ree-lecture/assignments/src/branch/master/Assignment_13/password_check_4) ### $ file Die Datei wurde zuerst mit dem Programm file untersucht. Es handelt sich um ein 64-bit Programm, welches dynamisch gelinkt ist und nciht gestrippt wurde. ``` $file password_check_4 password_check_4: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4f2b3472be169d1c2bd8475cdd0a07d9a67ebae3, not stripped ``` Da weder das Program Strings noch der Hex-Editor uns das richtige Passwort oder die Flagge einzeigt, verwenden wir im folgenden den Debugger gdb. ### $ gdb Im folgenden untersuchen wir das Programm mit gdb: ``` $ gdb -q password_check_4 $ set disassembly-flavor intel $ disassemble main ``` Die Ausgabe, sieht wie folgt aus: Adresse | Offset | Befehl | Argumente | Kommentare -- | -- | -- | -- | -- 0x00000000000009da | <+0>: | push | rbp | 0x00000000000009db | <+1>: | mov | rbp,rsp | 0x00000000000009de | <+4>: | sub | rsp,0x130 | 0x00000000000009e5 | <+11>: | mov | DWORD PTR [rbp-0x124],edi | 0x00000000000009eb | <+17>: | mov | QWORD PTR [rbp-0x130],rsi | 0x00000000000009f2 | <+24>: | mov | rax,QWORD PTR fs:0x28 | 0x00000000000009fb | <+33>: | mov | QWORD PTR [rbp-0x8],rax | 0x00000000000009ff | <+37>: | xor | eax,eax | 0x0000000000000a01 | <+39>: | lea | rax,[rbp-0x110] | 0x0000000000000a08 | <+46>: | lea | rdx,[rip+0x1c55]| # 0x2664 0x0000000000000a0f | <+53>: | mov | esi,0xff | 0x0000000000000a14 | <+58>: | mov | rdi,rax | 0x0000000000000a17 | <+61>: | call | 0xc9e <read_password> | 0x0000000000000a1c | <+66>: | mov | edi,0x9 | 0x0000000000000a21 | <+71>: | call | 0x8b0 <malloc@plt> | 0x0000000000000a26 | <+76>: | mov | QWORD PTR [rbp-0x120],rax | 0x0000000000000a2d | <+83>: | mov | rax,QWORD PTR [rbp-0x120] | 0x0000000000000a34 | <+90>: | mov | r8d,0x10 | 0x0000000000000a3a | <+96>: | lea | rcx,[rip+0x1c23] | # 0x2664 0x0000000000000a41 | <+103>: | mov | edx,0x8 | 0x0000000000000a46 | <+108>: | lea | rsi,[rip+0x2025db] | # 0x203028 <PASSWORD> 0x0000000000000a4d | <+115>: | mov | rdi,rax | 0x0000000000000a50 | <+118>: | call | 0xb0f <xor_crypt> | 0x0000000000000a55 | <+123>: | mov | rax,QWORD PTR [rbp-0x120] | 0x0000000000000a5c | <+130>: | add | rax,0x8 | 0x0000000000000a60 | <+134>: | mov | BYTE PTR [rax],0x0 | 0x0000000000000a63 | <+137>: | mov | rdx,QWORD PTR [rbp-0x120] | 0x0000000000000a6a | <+144>: | lea | rax,[rbp-0x110] | 0x0000000000000a71 | <+151>: | mov | rsi,rdx | 0x0000000000000a74 | <+154>: | mov | rdi,rax | 0x0000000000000a77 | <+157>: | call | 0x890 <strcmp@plt> | 0x0000000000000a7c | <+162>: | test | eax,eax | 0x0000000000000a7e | <+164>: | jne | 0xae5 <main+267> | 0x0000000000000a80 | <+166>: | mov | edi,0x15 | 0x0000000000000a85 | <+171>: | call | 0x8b0 <malloc@plt> | 0x0000000000000a8a | <+176>: | mov | QWORD PTR [rbp-0x118],rax | 0x0000000000000a91 | <+183>: | mov | rax,QWORD PTR [rbp-0x118] | 0x0000000000000a98 | <+190>: | mov | r8d,0x10 | 0x0000000000000a9e | <+196>: | lea | rcx,[rip+0x1bbf] | # 0x2664 0x0000000000000aa5 | <+203>: | mov | edx,0x14 | 0x0000000000000aaa | <+208>: | lea | rsi,[rip+0x20255f] | # 0x203010 <FLAG> 0x0000000000000ab1 | <+215>: | mov | rdi,rax | 0x0000000000000ab4 | <+218>: | call | 0xb0f <xor_crypt> | 0x0000000000000ab9 | <+223>: | mov | rax,QWORD PTR [rbp-0x118] | 0x0000000000000ac0 | <+230>: | add | rax,0x14 | 0x0000000000000ac4 | <+234>: | mov | BYTE PTR [rax],0x0 | 0x0000000000000ac7 | <+237>: | mov | rax,QWORD PTR [rbp-0x118] | 0x0000000000000ace | <+244>: | mov | rdi,rax | 0x0000000000000ad1 | <+247>: | call | 0x810 <puts@plt> | 0x0000000000000ad6 | <+252>: | mov | rax,QWORD PTR [rbp-0x118] | 0x0000000000000add | <+259>: | mov | rdi,rax | 0x0000000000000ae0 | <+262>: | call | 0x800 <free@plt> | 0x0000000000000ae5 | <+267>: | mov | rax,QWORD PTR [rbp-0x120] | 0x0000000000000aec | <+274>: | mov | rdi,rax | 0x0000000000000aef | <+277>: | call | 0x800 <free@plt> | 0x0000000000000af4 | <+282>: | mov | eax,0x0 | 0x0000000000000af9 | <+287>: | mov | rcx,QWORD PTR [rbp-0x8] | 0x0000000000000afd | <+291>: | xor | rcx,QWORD PTR fs:0x28 | 0x0000000000000b06 | <+300>: | je | 0xb0d <main+307> | 0x0000000000000b08 | <+302>: | call | 0x830 <__stack_chk_fail@plt> | 0x0000000000000b0d | <+307>: | leave| | 0x0000000000000b0e | <+308>: | ret | | bei den Offset <+157> kann man erkennen, dass eine Funktion <strcmp@plt > (String Compare) aufgerufen wird und danach getestet wird ob die Eingabe stimmt. Wenn diese nicht stimmt, wird ein Jump ausgeführt an das Ende vom Programm, ohne die Flag auszugeben. ``` 0x0000000000000a77 <+157>: call 0x890 <strcmp@plt> 0x0000555555400a7c <+162>: test eax,eax 0x0000555555400a7e <+164>: jne 0xae5 <main+267> ``` Man könnte die Zeile <+164> mit "nop" erstezten um an die Flag ```FLAG{xor or not xor}``` zu kommen, aber dadurch kommt man nicht an das Passwort. Da es in der Übung explizit gefragt wird "die Eingabeparameter der Funktion und eventuell Rückgaben" mit einem Breakpoint zu untersuchen, hört unsere Aufgabe hier noch nicht auf. ## Untersuchung mit Breakpoint Um die richtige Stelle für unseren Breakpoint zu finden, sehen wir uns das Programm noch einmal an: Bei Offset <+118> wird eine Funktion aufgerufen, die xor_crypt genannt wird. 0x0000555555400a50 <+118>: call 0xb0f <xor_crypt> Die ersten beiden Parameter, die an eine Funktion übergeben werden, sind normalerweise rdi und rsi. Diese beiden Register wurden zuvor gefüllt. Das Register rsi wurde wahrscheinlich mit einem XOR-verschlüsselten Passwort aus dem Speicher in <+108> geladen, ein Kommentar bestätigt dies zusätzlich. 0x0000555555400a46 <+108>: lea rsi,[rip+0x2025db] # 0x203028 <PASSWORD> Das Register rdi wurde zuvor mit dem Inhalt des rax-Registers im Offset <+115> gefüllt. Das rax-Register wiederum wurde zuvor in Offset <+83> mit einer Speicheradresse gefüllt, die in Offset <+71> und <+76> mit malloc reserviert wurde. 0x0000000000000a21 <+71>: call 0x8b0 <malloc@plt> 0x0000000000000a26 <+76>: mov QWORD PTR [rbp-0x120],rax 0x0000000000000a26 <+76>: mov QWORD PTR [rbp-0x120],rax 0x0000000000000a2d <+83>: mov rax,QWORD PTR [rbp-0x120] 0x0000000000000a4d <+115>: mov rdi,rax Daher kann man davon ausgehen, dass sich das Ergebnis der Funktion xor_crypt entweder im Standard-Rückgaberegister rax oder in der Speicheradresse befindet, die im Register rdi übergeben wurde. Ein sinnvoller Breakpoint wäre ein Moment, nachdem das Programm das Passwort bei Offset <+118> entschlüsselt hat. Wir setzen also unseren Breakpoint bei der Funktion "xor_crypt" und starten das Programm: ``` (gdb) break xor_crypt Breakpoint 1 at 0xb13 (gdb) run Starting program: /home/kali/ree/gitty/Assignment_13/password_check_4 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". ``` Das Programm läuft normal, fragt nach einem Passwort, hier geben wir einen Dummy-Wert z.B. "test" ein und fahren fort, bis wir den gesetzten Breakpoint erreichen: ``` Enter password: test Breakpoint 1, 0x0000555555400b13 in xor_crypt () ``` Jetzt sind wir bei der Funktion, die das Passwort entschlüsselt. Um auf das Ergebnis der Funktion zuzugreifen, müssen wir mit dem Befehl "next" einen Schritt weitergehen. ``` (gdb) next Single stepping until exit from function xor_crypt, which has no line number information. 0x0000555555400a55 in main () ``` Das Passwort ist jetzt entschlüsselt und zwischengespeichert. Wir können uns die Informationen zu den Register mit "info register" anzeigen lassen: ``` (gdb) i r rax 0x8 8 rbx 0x0 0 rcx 0x61 97 rdx 0x33 51 rsi 0x33 51 rdi 0x555555604ac0 93824992955072 rbp 0x7fffffffddc0 0x7fffffffddc0 rsp 0x7fffffffdc90 0x7fffffffdc90 r8 0x10 16 r9 0x77 119 r10 0x5d 93 r11 0x7ffff7df4c60 140737351994464 r12 0x7fffffffded8 140737488346840 r13 0x5555554009da 93824990841306 r14 0x0 0 r15 0x7ffff7ffd020 140737354125344 rip 0x555555400a55 0x555555400a55 <main+123> eflags 0x246 [ PF ZF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 ``` Der Wert des rax-Registers ist 8, es scheint also uninteressant zu sein. Werfen wir einen Blick auf das rdi-Register: ``` (gdb) x /s 0x555555604ac0 0x555555604ac0: "mutti123" ``` Bingo! Im rdi-Register steht die Adresse des unverschlüsselten Passworts, dass wir auslesen können. ## Weitere Überlegungen Bei dem Offset <+61> wird eine Funktion aufgerufen, welche ein Passwort einliest. 0x0000555555400a17 <+61>: call 0xc9e <read_password> Später bei Offset <+157> wird die Funktion strcmp aufgerufen, die testet, ob das entschlüsselte Passwort und das eingebene Passwort übereinstimmen. 0x0000555555400a77 <+157>: call x890 <strcmp@plt> Man könnte auch einen Breakpoint bei strcmp am Offset <+157> setzen, um zu sehen, welche beiden Adressen an die Funktion übergeben werden. Die erste Adresse befindet sich vermutlich im rdi-Register und die zweite Adresse im rsi-Register. Eine der Speicheradressen enthält wahrscheinlich das von uns eingelesene Passwort und die andere Speicheradresse enthält das entschlüsselte Passwort, das hinterlegt wurde und zuvor an Offset <+118> entschlüsselt wurde. Wir haben diese Annahme überprüft und sie scheint richtig zu sein, denn wir erhalten das gleiche Ergebnis wie zuvor im Abschnitt "Untersuchung mit Breakpoint" beschrieben. Wenn die Passwörter nicht übereinstimmt springt das Programm (am Offset <+164> mit jne) an das Ende und beendet sich. 0x0000555555400a7e <+164>: jne 0xae5 <main+267> Wenn das Passwort jedoch übereinstimmt, dann wird am Offset <+218> die Flagge entschlüsselt und am Offset <+247> asugegeben. 0x0000555555400ab4 <+218>: call 0xb0f <xor_crypt> 0x0000555555400ad1 <+247>: call 0x810 <puts@plt> ## Ergebnisse **Flag:** ```FLAG{xor or not xor} ``` **Passwort:** ```mutti123```