Added writeups

This commit is contained in:
m0rph3us1987
2026-03-08 12:22:39 +01:00
parent a566ea77d1
commit a79656b647
43 changed files with 6940 additions and 0 deletions

133
de/cryptoracle_v2.md Normal file
View File

@@ -0,0 +1,133 @@
# CryptOracle v2
`CryptOracle v2` ist die "gehärtete" Version des HSM-Simulators. Die Schwachstelle des direkten Speicherlesens aus v1 wurde behoben, aber eine neue "Kryptographische Engine" wurde hinzugefügt. Das Ziel ist dasselbe: den geheimen Schlüssel aus dem sicheren Speicherbereich bei `0x10000` zu dumpen.
## Informationsbeschaffung
Nachdem wir uns mit dem Server verbunden haben, sehen wir eine vertraute Oberfläche mit neuen Befehlen wie `enc` und `dec`.
```
CryptOracle v2.0 (Hardened!)
Setting up memory...
0x10000 - 0x11000 : Secure Memory (Keys/ROM)
0x20000 - 0x28000 : User Memory
Type 'help' for commands.
```
## Reverse Engineering
Wir öffnen die Binärdatei in Ghidra und überprüfen die Funktionen, die sich geändert haben.
### 1. Der Patch (`do_read`)
Die `do_read`-Funktion enthält jetzt eine explizite Prüfung, die jeden Versuch blockiert, von Adressen unterhalb des Benutzerspeicherbereichs zu lesen.
```c
void do_read(uint32_t offset,uint32_t len)
{
uint8_t *data;
// Diese Prüfung verhindert, dass wir 0x10000 direkt lesen.
if (offset < 0x20000) {
puts("ERR_ACCESS_VIOLATION");
}
else {
// ... (Rest der Funktion)
}
return;
}
```
Das einfache `rm 0x10000 32` aus v1 funktioniert nicht mehr.
### 2. Die Kryptographische Engine (`do_cipher`)
Da die Schwachstelle des direkten Lesens aus v1 gepatcht wurde, müssen wir nun andere Befehle als potenzielle Angriffsfläche untersuchen. Die Befehle `enc` und `dec`, die zuvor schon vorhanden waren, rücken nun in unseren Fokus. Sie werden von der `do_cipher`-Funktion behandelt. Sie ermöglicht das Verschlüsseln oder Entschlüsseln von Daten von einer Quelladresse zu einer Zieladresse unter Verwendung eines Schlüssels, der in einem sicheren "Slot" gespeichert ist.
```c
void do_cipher(char mode, uint32_t src_off, uint32_t len, int slot, uint32_t dst_off)
{
// ...
// Zeiger auf Quellpuffer abrufen (kann überall sein)
src_ptr = get_ptr(src_off, len, 0);
// Zeiger auf Zielpuffer abrufen (muss beschreibbar sein)
dst_ptr = get_ptr(dst_off, len, 1);
// Zeiger auf den Schlüssel aus einem sicheren Slot abrufen
// Adresse wird berechnet als 0x10000 + slot * 32
key_ptr = get_ptr((slot + 0x800) * 0x20, 0x20, 0);
if (/* alle Zeiger sind gültig */) {
// ... führt AES-Verschlüsselung/-Entschlüsselung blockweise durch ...
}
}
```
Die wichtigste Erkenntnis liegt darin, wie die Zeiger validiert werden, was alles innerhalb der `get_ptr`-Funktion geschieht.
### 3. Schwachstellenanalyse (`get_ptr`)
Hier ist die dekompilierte `get_ptr`-Funktion aus Ghidra. Sie nimmt einen Offset, eine Länge und ein Flag `is_write` entgegen, das `1` für Schreiboperationen und `0` für Leseoperationen ist.
```c
uint8_t * get_ptr(uint32_t offset,uint32_t len,int is_write)
{
uint8_t *puVar1;
if (len + offset < offset) {
puVar1 = (uint8_t *)0x0;
}
else if ((offset < 0x10000) || (0x11000 < len + offset)) {
if ((offset < 0x20000) || (0x28000 < len + offset)) {
puVar1 = (uint8_t *)0x0;
}
else {
puVar1 = (uint8_t *)(ulong)offset;
}
}
else if ((is_write == 0) || (0x7ff < offset - 0x10000)) {
puVar1 = (uint8_t *)(ulong)offset;
}
else {
puVar1 = (uint8_t *)0x0;
}
return puVar1;
}
```
**Die Schwachstelle:**
Die Logik im letzten `else if`-Block ist fehlerhaft. Verfolgen wir sie für eine Leseoperation (`is_write == 0`) im sicheren Flaggenbereich (`offset = 0x10000`).
* Der Ausdruck ist `(is_write == 0) || (0x7ff < offset - 0x10000)`.
* Da `is_write` `0` ist, ist der erste Teil des ODER `(0 == 0)` **wahr**.
* Der gesamte Ausdruck wird `wahr`, und der Zugriff wird gewährt, wodurch ein gültiger Zeiger zurückgegeben wird.
Die Prüfung, die das Schreiben in die ersten 2KB des sicheren Speichers (`0x7ff < offset - 0x10000`) verhindern sollte, wird für jede Leseoperation vollständig umgangen. Die `do_cipher`-Funktion missbraucht dies, indem sie ein Lesen (`is_write=0`) auf der sicheren Flagge anfordert, was `get_ptr` erlaubt. Dies erzeugt ein **Confused Deputy**-Szenario, bei dem wir die legitimen Leseberechtigungen des Orakels nutzen, um Daten zu exfiltrieren.
## Lösung
Der Angriff ist ein zweistufiger Prozess:
1. **Verschlüsseln**: Verwenden Sie den `enc`-Befehl, um das Orakel anzuweisen, aus dem sicheren Flaggenbereich (`0x10000`) zu lesen und das verschlüsselte Ergebnis (Chiffretext) in den benutzerzugänglichen Speicher (`0x20000`) zu schreiben.
2. **Entschlüsseln**: Verwenden Sie den `dec`-Befehl, um das Orakel anzuweisen, den Chiffretext aus dem Benutzerspeicher (`0x20000`) zu lesen und das entschlüsselte Ergebnis (Klartext) zurück an eine andere Stelle im Benutzerspeicher (`0x20100`) zu schreiben.
3. **Lesen**: Verwenden Sie den jetzt reparierten `rm`-Befehl, um die Klartext-Flagge von `0x20100` zu lesen.
### Ausführung
```bash
# Schritt 1: Verschlüsseln der Flagge aus dem sicheren Speicher in den Benutzerspeicher
> enc 0x10000 32 30 0x20000
OK
# Schritt 2: Entschlüsseln des Chiffretextes aus dem Benutzerspeicher an eine andere Stelle im Benutzerspeicher
> dec 0x20000 32 30 0x20100
OK
# Schritt 3: Lesen der Klartext-Flagge aus dem Benutzerspeicher
> rm 0x20100 32
00020100: 7b 66 6c 61 67 3a 20 73 65 6c 66 5f 65 6e 63 72 {flag: self_encr
00020110: 79 70 74 69 6f 6e 5f 69 73 5f 6e 69 63 65 21 7d yption_is_nice!}
```
Die Flagge wird enthüllt: `{flag: self_encryption_is_nice!}`