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

130
de/variable_security.md Normal file
View File

@@ -0,0 +1,130 @@
# Variable Security
`Variable Security` ist eine Kryptographie-Challenge, die eine Schwachstelle in einem benutzerdefinierten HMAC-Signierdienst ausnutzt. Der Dienst ermöglicht es Benutzern, HMAC-SHA256-Signaturen für beliebige Nachrichten unter Verwendung eines geheimen Schlüssels (der Flagge) zu generieren. Entscheidend ist, dass der Dienst eine Funktion "Key Optimization Level" bietet, mit der der Benutzer festlegen kann, wie viele Bytes des geheimen Schlüssels für das Signieren verwendet werden sollen.
## Informationsbeschaffung
Uns wird eine Webinterface namens "SecureSign Enterprise" präsentiert. Es bietet ein Formular mit zwei Feldern:
1. **Message Content**: Texteingabe für die zu signierende Nachricht.
2. **Key Optimization Level**: Eine numerische Eingabe, die die Länge des zu verwendenden Schlüssels angibt.
Aus der Challenge-Beschreibung ("Wir erlauben Clients, das 'Key Optimization'-Level anzupassen") und dem Formularfeld `key_len` können wir ableiten, dass die Backend-Logik etwa so aussieht:
```python
# Abgeleitete Logik
# key_len kommt von der Benutzereingabe
current_key = SECRET_KEY[:key_len] # Schwachstelle: Verwendet nur die ersten N Bytes
h = hmac.new(current_key, message.encode(), hashlib.sha256)
signature = h.hexdigest()
```
Die Anwendung erstellt eine HMAC-Signatur unter Verwendung eines Teilstücks des geheimen Schlüssels, bestimmt durch die Benutzereingabe `key_len`. Dies ermöglicht es uns, Nachrichten unter Verwendung von nur den ersten $N$ Bytes der Flagge zu signieren.
## Die Schwachstelle
Dieses Setup erstellt ein **Orakel**, das Informationen über den Schlüssel Byte für Byte preisgibt. Die Schwachstelle liegt in der Tatsache, dass wir genau steuern können, wie viel des unbekannten Schlüssels in der kryptographischen Operation verwendet wird. Dies ermöglicht es uns, das Problem, den gesamten Schlüssel zu finden, darauf herunterzubrechen, ihn Zeichen für Zeichen zu finden.
Hier ist die Strategie:
**1. Finden des ersten Bytes:**
Wir kennen den Schlüssel nicht, aber wir können den Server bitten, eine Nachricht (z.B. "test") unter Verwendung von nur **1 Byte** des Schlüssels zu signieren (`key_len=1`).
* Der Server berechnet `HMAC(key[0], "test")` und gibt die Signatur zurück.
* Wir können dies lokal replizieren! Wir versuchen jedes mögliche Zeichen (A, B, C...) als Schlüssel.
* Wir berechnen `HMAC("A", "test")`, `HMAC("B", "test")`, usw.
* Wenn unsere lokale Signatur mit der Signatur des Servers übereinstimmt, wissen wir, dass wir das erste Byte des geheimen Schlüssels gefunden haben.
**2. Finden des zweiten Bytes:**
Jetzt, da wir das erste Byte kennen (sagen wir, es ist `{`), bitten wir den Server, "test" unter Verwendung von **2 Bytes** des Schlüssels zu signieren (`key_len=2`).
* Der Server berechnet `HMAC("{?", "test")`.
* Wir führen wieder Brute-Force für das unbekannte zweite Zeichen lokal durch. Wir versuchen `{A`, `{B`, `{C`...
* Wir berechnen `HMAC("{A", "test")`, `HMAC("{B", "test")`...
* Die Übereinstimmung enthüllt das zweite Byte.
**3. Wiederholen:**
Wir setzen diesen Prozess für `key_len=3`, `key_len=4` usw. fort, bis wir die gesamte Flagge wiederhergestellt haben.
## Lösung
Wir können ein Skript schreiben, um diesen Byte-für-Byte-Brute-Force-Angriff zu automatisieren.
### Solver-Skript
```python
import requests
import hmac
import hashlib
import string
import re
# Konfiguration
TARGET_URL = "http://127.0.0.1:5000" # Nach Bedarf anpassen
MESSAGE = "test"
MAX_LEN = 33 # Maximale Länge der Flagge (abgeleitet oder durch Ausprobieren gefunden)
def get_signature(length):
"""Fordere Signatur vom Server mit spezifischer Schlüssellänge an."""
try:
resp = requests.post(TARGET_URL, data={'message': MESSAGE, 'key_len': length})
# Extrahiere Hex-Signatur aus der HTML-Antwort
match = re.search(r'([a-f0-9]{64})', resp.text)
return match.group(1) if match else None
except:
return None
def solve():
known_flag = b""
print(f"[*] Starting attack on {TARGET_URL}...")
# Iteriere durch jede Byte-Position
for length in range(1, MAX_LEN + 1):
# 1. Hole die Zielsignatur vom Server
# Diese Signatur wird unter Verwendung der echten ersten 'length' Bytes der Flagge generiert
target_sig = get_signature(length)
if not target_sig:
print(f"[-] Failed to get signature for length {length}")
break
# 2. Brute-Force das nächste Zeichen
found = False
# Versuche alle druckbaren Zeichen
for char_code in string.printable.encode():
char = bytes([char_code])
# Konstruiere unseren Rateversuch: Der Teil, den wir schon kennen + das neue Zeichen, das wir testen
candidate_key = known_flag + char
# Berechne HMAC lokal mit unserem Rateversuch
local_sig = hmac.new(candidate_key, MESSAGE.encode(), hashlib.sha256).hexdigest()
# Wenn die Signaturen übereinstimmen, ist unser Rateversuch für das neue Zeichen korrekt
if local_sig == target_sig:
known_flag += char
print(f"[+] Byte {length}: {char.decode()} -> {known_flag.decode()}")
found = True
break
if not found:
print("[-] Character not found in printable range.")
break
print(f"\n[!] Final Flag: {known_flag.decode()}")
if __name__ == "__main__":
solve()
```
### Ausführung
Das Ausführen des Skripts stellt die Flagge Zeichen für Zeichen wieder her:
```bash
$ python3 solve.py
[*] Starting attack on http://127.0.0.1:5000...
[+] Byte 1: { -> {
[+] Byte 2: f -> {f
[+] Byte 3: l -> {fl
...
[+] Byte 32: } -> {flag: byte_by_byte_we_get_rich}
[!] Final Flag: {flag: byte_by_byte_we_get_rich}
```