Added writeups
This commit is contained in:
166
de/twisted.md
Normal file
166
de/twisted.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# Twisted
|
||||
|
||||
`twisted` ist eine Reverse-Engineering-Challenge, bei der wir eine Flagge aus einer bereitgestellten Binärdatei und einem verschlüsselten Ausgabestring wiederherstellen müssen.
|
||||
|
||||
## Informationsbeschaffung
|
||||
|
||||
Wir beginnen mit der Analyse des Dateityps der `twisted`-Binärdatei:
|
||||
|
||||
```bash
|
||||
$ file twisted
|
||||
twisted: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, ... stripped
|
||||
```
|
||||
|
||||
Die Binärdatei ist "stripped", was bedeutet, dass ihr Debugging-Symbole wie Funktionsnamen fehlen. Wenn wir uns mit dem Challenge-Server verbinden, erhalten wir die verschlüsselte Flagge:
|
||||
|
||||
```
|
||||
Here is your twisted flag: 34d133c640536c58ffcebb864a836aaf3bc432c3606b331df2d981a472bd6e80
|
||||
```
|
||||
|
||||
## Reverse Engineering
|
||||
|
||||
Wir öffnen die Binärdatei in Ghidra, um ihre Logik zu analysieren. Da die Binärdatei gestrippt ist, suchen wir zuerst den Einsprungpunkt (`entry`), der `__libc_start_main` aufruft. Das erste Argument für `__libc_start_main` ist die Adresse der `main`-Funktion. Diesem Pfad folgend gelangen wir zur Funktion bei `0x40190a`, die wir in `main` umbenennen.
|
||||
|
||||
### Main-Funktion (`0x40190a`)
|
||||
|
||||
Der dekompilierte Code für `main` enthüllt die erwarteten Argumente und eine grundlegende Validierung:
|
||||
|
||||
```c
|
||||
undefined8 main(int param_1,long param_2)
|
||||
|
||||
{
|
||||
size_t sVar1;
|
||||
|
||||
if (param_1 < 2) {
|
||||
printf("Usage: %s <flag>\n",*(undefined8 *)(param_2 + 8)); // Usage-String bei 0x49e081
|
||||
return 1;
|
||||
}
|
||||
sVar1 = strlen(*(char **)(param_2 + 8));
|
||||
if (sVar1 == 32) {
|
||||
FUN_004017b5(*(undefined8 *)(param_2 + 8));
|
||||
return 0;
|
||||
}
|
||||
printf("Error: Flag must be exactly %d characters long.\n",32); // Error-String bei 0x49e098
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
Daraus lernen wir, dass die Eingabeflagge genau **32 Zeichen** lang sein muss. Wenn die Länge korrekt ist, ruft sie `FUN_004017b5` auf.
|
||||
|
||||
### Transformationsfunktion (`0x4017b5`)
|
||||
|
||||
Wir analysieren `FUN_004017b5`, welche die Kernverschlüsselungslogik enthält. Sie führt zwei verschiedene Operationen auf dem Eingabestring aus.
|
||||
|
||||
```c
|
||||
void FUN_004017b5(long param_1)
|
||||
|
||||
{
|
||||
long lVar1;
|
||||
int local_84; // Zähler für Schleife 1
|
||||
int local_80; // Zähler für Schleife 2
|
||||
int local_7c; // Zähler für Schleife 3
|
||||
byte local_70 [32]; // Gemischter Puffer
|
||||
byte local_50 [32]; // Finaler XOR-Puffer
|
||||
byte local_30 [32]; // Eingabekopie
|
||||
|
||||
// ... Setup und Kopieren der Eingabe nach local_30 ...
|
||||
|
||||
// --- SCHRITT 1: Permutation ---
|
||||
local_84 = 0;
|
||||
while (local_84 < 32) {
|
||||
// Lade Byte aus Permutationstabelle bei 0x49e020
|
||||
// Verwende es als Index in den Eingabestring
|
||||
local_70[local_84] = local_30[(int)(uint)(byte)(&DAT_0049e020)[local_84]];
|
||||
local_84 = local_84 + 1;
|
||||
}
|
||||
|
||||
// --- SCHRITT 2: XOR-Verschlüsselung ---
|
||||
local_80 = 0;
|
||||
while (local_80 < 32) {
|
||||
// XOR das gemischte Byte mit einem Schlüsselbyte von 0x49e040
|
||||
local_50[local_80] = local_70[local_80] ^ (&DAT_0049e040)[local_80];
|
||||
local_80 = local_80 + 1;
|
||||
}
|
||||
|
||||
// --- Ergebnis drucken ---
|
||||
printf("Here is your twisted flag: "); // String bei 0x49e060
|
||||
local_7c = 0;
|
||||
while (local_7c < 32) {
|
||||
printf("%02x",(ulong)local_50[local_7c]);
|
||||
local_7c = local_7c + 1;
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Der Algorithmus ist:
|
||||
1. **Permutation**: Verwende das Array bei `0x49e020`, um die Eingabezeichen neu anzuordnen.
|
||||
`shuffled[i] = input[PERM[i]]`
|
||||
2. **XOR**: XOR die neu angeordneten Zeichen mit dem Array bei `0x49e040`.
|
||||
`encrypted[i] = shuffled[i] ^ KEY[i]`
|
||||
|
||||
### Datenextraktion
|
||||
|
||||
Wir untersuchen den Speicher an den identifizierten Adressen, um die Permutationstabelle und den XOR-Schlüssel abzurufen.
|
||||
|
||||
**Permutationstabelle (`0x49e020`):**
|
||||
Werte: `3, 0, 1, 2, 7, 4, 5, 6, 10, 11, 8, 9, 15, 12, 13, 14, 19, 16, 17, 18, 22, 23, 20, 21, 25, 26, 27, 24, 31, 28, 29, 30`
|
||||
|
||||
**XOR-Schlüssel (`0x49e040`):**
|
||||
Werte (Hex): `55, AA, 55, AA, 12, 34, 56, 78, 9A, BC, DE, F0, 0F, F0, 0F, F0, 55, AA, 55, AA, 12, 34, 56, 78, 9A, BC, DE, F0, 0F, F0, 0F, F0`
|
||||
|
||||
## Lösung
|
||||
|
||||
Um die Flagge `34d133c6...` zu entschlüsseln, kehren wir die Operationen um:
|
||||
1. **XOR umkehren**: `shuffled[i] = encrypted[i] ^ KEY[i]`
|
||||
2. **Permutation umkehren**: `input[PERM[i]] = shuffled[i]`
|
||||
|
||||
### Solver-Skript
|
||||
|
||||
```python
|
||||
import sys
|
||||
|
||||
# Extrahiert von 0x49e020
|
||||
PERM = [
|
||||
3, 0, 1, 2, 7, 4, 5, 6,
|
||||
10, 11, 8, 9, 15, 12, 13, 14,
|
||||
19, 16, 17, 18, 22, 23, 20, 21,
|
||||
25, 26, 27, 24, 31, 28, 29, 30
|
||||
]
|
||||
|
||||
# Extrahiert von 0x49e040
|
||||
KEY = [
|
||||
0x55, 0xAA, 0x55, 0xAA, 0x12, 0x34, 0x56, 0x78,
|
||||
0x9A, 0xBC, 0xDE, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0,
|
||||
0x55, 0xAA, 0x55, 0xAA, 0x12, 0x34, 0x56, 0x78,
|
||||
0x9A, 0xBC, 0xDE, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0
|
||||
]
|
||||
|
||||
def solve(hex_string):
|
||||
encrypted_bytes = bytes.fromhex(hex_string)
|
||||
|
||||
if len(encrypted_bytes) != 32:
|
||||
print("Error: Length mismatch")
|
||||
return
|
||||
|
||||
# 1. XOR umkehren
|
||||
shuffled = [0] * 32
|
||||
for i in range(32):
|
||||
shuffled[i] = encrypted_bytes[i] ^ KEY[i]
|
||||
|
||||
# 2. Permutation umkehren
|
||||
original = [0] * 32
|
||||
for i in range(32):
|
||||
target_idx = PERM[i]
|
||||
original[target_idx] = shuffled[i]
|
||||
|
||||
print("Flag: " + "".join(chr(b) for b in original))
|
||||
|
||||
if __name__ == "__main__":
|
||||
solve("34d133c640536c58ffcebb864a836aaf3bc432c3606b331df2d981a472bd6e80")
|
||||
```
|
||||
|
||||
Das Ausführen des Skripts gibt uns die Flagge:
|
||||
`{flag: Reverse_Engineer_The_Map}`
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user