rebreak-monorepo/docs/specs/magic-re-hardening.md
chahinebrini 5fb441817f feat(magic): RE-hardening Quick Wins (ACL, #if DEBUG guards, rate-limit)
Härtung der öffentlich downloadbaren Magic-Apps gegen Reverse Engineering
(Assessment: docs/specs/magic-re-hardening.md):
- Windows: protection.json per ACL auf SYSTEM+Admins (DNS-Token nicht mehr von
  Standard-Usern lesbar) — setup.rs
- Mac: MacProfileInstaller.remove() + Debug-Supervision-Modi/Reset nur noch
  #if DEBUG (kein Removal-/Debug-Pfad im Release-Binary)
- Mac: staging-URL einmal als Konstante statt 4x Literal; interne Infra-Notizen
  aus String-Literalen raus
- Backend: Rate-Limit (10/IP/min) auf /api/magic/pair/redeem

NUR Backend-Teil deployt via Push; Mac/Win brauchen Xcode-/Cargo-Release-Build
(zied) + Smoke-Tests vor Release. MagicAPIClient.swift trägt etwas vorbestehenden
WIP mit (gleiche Magic-Client-Domäne).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 05:19:10 +02:00

17 KiB
Raw Permalink Blame History

ReBreak Magic — RE-Hardening Assessment & Plan

Erstellt: 2026-06-09
Scope: apps/rebreak-magic-mac/ · apps/rebreak-magic-win/ · relevante Backend-Berührungspunkte
Status: Assessment + Plan zur Founder-Abnahme. Keine Implementierung.


1. RE-Exposure-Analyse: Was liegt aktuell offen?

1.1 Mac-App (SwiftUI, .app-Bundle)

Technische Ausgangslage: Swift-Binaries sind Mach-O, kompiliert mit Optimierungen. String-Literale im __TEXT-Segment bleiben im Binary. strings-Analyse + Class-Dump (mit class-dump oder Ghidra) reicht für alles Relevante.

Angriffsvektor Was ist extrahierbar? Sicherheitskritisch?
String-Scan des Binary https://staging.rebreak.org, https://dns.rebreak.org/dns-query, org.rebreak.magic, org.rebreak.protection.dns.filter, org.rebreak.protection.profile Niedrig — Base-URLs sind keine Secrets
REBREAK_BACKEND_URL env-Override Hardcoded String + Kommentar im Binary: „Default to staging (app.rebreak.org hat aktuell falsches TLS-Zert)" Mittel — zeigt interne Infrastruktur-Anmerkungen
Keychain-Keys org.rebreak.magic / magic-session — kein Secret-Wert, nur Service/Account-Namen Niedrig
mgc_-Token-Prefix Token-Format mgc_<base64url> im Binary erkennbar Niedrig
Profil-PayloadIdentifier org.rebreak.protection.dns.filter.* im Binary + .mobileconfig-Dateiname Niedrig
MacProfileInstaller.remove() Vollständiger Removal-Pfad via profiles remove -identifier org.rebreak.protection.profile.* sichtbar Mittel-hoch — RE kann Removal-Kommando 1:1 nachbauen
profiles show -type configuration Identifier-Scan-Logik offenbart die exakten Identifier des Schutzes Mittel
Debug-State in WizardModel DebugSupervisionMode mit forceSupervised/forceUnsupervised im Release-Build sichtbar Mittel — gibt Hinweise auf interne States
Removal-Password NICHT im Binary. Kommt server-seitig via /api/magic/profile.mobileconfig. Liegt in Keychain auf dem Device. Kein Exposure-Risiko im Binary
AdGuard-Creds NICHT im Binary. Nur im Backend via Infisical. Kein Exposure-Risiko

Kritische Erkenntnis Mac:
Das eigentliche Schutz-Bypass-Risiko liegt nicht im Binary, sondern im Mechanismus selbst: Der User hat Admin-Passwort. Mit Admin-Passwort kann er das .mobileconfig-Profil über System Settings → Geräteverwaltung entfernen — unabhängig vom Binary-Wissen. Das ProfileRemovalPassword ändert das erst dann, wenn es korrekt vom Backend injiziert wird. Das ist der echte Lock.


1.2 Windows-App (Tauri 2 / Rust)

Technische Ausgangslage: Rust-Binaries sind kompilierter Maschinencode. Ohne Debug-Symbols sind Funktionsnamen weg — aber String-Literale sind direkt extrahierbar mit strings. Tauri-Apps haben zusätzlich einen eingebetteten WebView mit React-Bundle (JavaScript-Klartext).

Angriffsvektor Was ist extrahierbar? Sicherheitskritisch?
strings auf .exe https://staging.rebreak.org, dns.rebreak.org, 178.105.101.137 (Fallback-IP), RebreakProtection (Service-Name), HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters, Registry-Pfade für Browser-Policies Mittel
PowerShell-Scripts als String-Literale Komplett lesbarapply_script(), teardown_script(), check_script() sind reine Strings im Binary. Jeder sieht exakt was geschrieben und gelöscht wird Hoch — Angreifer kann Teardown-Sequenz 1:1 reproduzieren
Service-Name RebreakProtection Im sc.exe-Aufruf als Literal; Service kann per Name gestoppt werden Hochsc.exe stop RebreakProtection + sc.exe delete RebreakProtection reicht für Bypass
DoH-Template https://dns.rebreak.org/dns-query/{token} Token-Schema erkennbar Niedrig
protection.json unter %ProgramData%\ReBreak\ Pfad im Binary. Datei enthält dnsToken, serverIp, dohTemplate, backendUrl, deviceId im Klartext Kritisch — wer Pfad kennt, kann DNS-Token + Status-Polling-URL direkt lesen
Credential Manager Keys org.rebreak.magic / session-token / dns-token — Keynames extrahierbar. Zugriff auf Werte braucht SYSTEM/selben User-Kontext Mittel
WebView-Bundle (JS) React-Frontend-Code im Klartext, komplett readable. Enthält keine Secrets (Token nie im Frontend), aber alle UI-Strings, State-Typen, IPC-Command-Namen Niedrig — keine Secrets
--console-Debug-Flag Im Binary sichtbar: rebreak-protection-service.exe --console startet den Service im Vordergrund Niedrig — Debug-Feature, kein Angriffspfad
DOH_FALLBACK_IP 178.105.101.137 Hetzner-Box direkt im Binary Mittel — IP-Wissen; aber auch über DNS auflösbar

Kritische Erkenntnis Windows:

Das protection.json-File ist das größte Exposure-Problem. Es liegt unter %ProgramData%\ReBreak\protection.json als lesbare JSON-Datei, enthält den DNS-Token im Klartext und ist für jeden User des Systems lesbar (ProgramData ist nicht ACL-beschränkt auf Nicht-Admin-User in Standardkonfiguration). Wer den Token kennt, kann /api/magic/status?token=<token> selbst pollen und damit theoretisch den Status-Check-Mechanismus verstehen.

Der Service-Name-Bypass ist das kritischste operative Risiko: Da RebreakProtection im Klartext im Binary steht und der Service mit sc.exe verwaltet wird, kann ein technisch versierter User mit Admin-Rechten:

  1. sc.exe stop RebreakProtection ausführen
  2. DoH manuell zurücksetzen (Registry/PowerShell)
  3. Schutz ist weg — bis zum nächsten Service-Start (alle 5min Auto-Restart greift, aber Fenster ist offen)

Gegenargument: Das braucht Admin-Rechte. Jemand mit Admin kann ohnehin alles. Aber es macht es trivial und skriptbar.


1.3 Backend-Berührungspunkte

Punkt Exposure Kritisch?
/api/magic/status?token= ist unauthentifiziert Design-gewollt — Token ist das Secret. 48 hex chars = 192 bit Entropie → praktisch nicht brute-forcebar Nein
Tamper-Service pollt diesen Endpoint Jeder der den Token aus protection.json liest, kann denselben Request abschicken und sieht active=true/false Theoretisch — kein zusätzlicher Bypass damit möglich
profile.mobileconfig?token= ist unauthentifiziert Wie oben — Token-basierter Auth. Profil enthält RemovalPassword im Klartext (für macOS) Mittel — Removal-PW liegt im Profil-XML falls jemand das Profil-File auf dem Mac lesen kann
AdGuard-Creds Nur Backend / Infisical. Kein Client-Exposure Kein Risiko
Pairing-Code 6 Ziffern (1M Raum) 10min TTL, max 5 aktive Attempts unwahrscheinlich throttled Niedrig — kurze TTL schützt

2. Sicherheitsbewertung: Was ist tatsächlich kritisch?

Kritisch (direkter Bypass möglich)

  • Windows protection.json lesbar: DNS-Token im Klartext für lokale User
  • Windows Service-Stop via bekanntem Namen + Auto-Restart-Fenster: 5min-Fenster zwischen Service-Stop und Restart (aber: braucht Admin)

Mittel (kein direkter Bypass, aber schlechte Praxis / Competitor-Wissen)

  • PowerShell-Teardown-Script vollständig im Binary: Competitor kann Setup/Teardown exakt kopieren
  • Mac profiles remove Kommando-Syntax im Binary: Analog zum DNS-Profil-Removal
  • protection.json-Pfad bekannt: Komfort-Angriff

Niedrig (kein operativer Bypass)

  • Base-URLs im Binary — ohnehin über Proxy/Network sichtbar
  • Service/Keychain-Namen — braucht lokalen Zugriff
  • Debug-Flags im Release-Build

Kein Risiko

  • Removal-Password (server-gehalten, nicht im Binary)
  • AdGuard-Creds (Infisical-only)
  • JWT/mgc-Tokens (Keychain/Credential Manager)

3. Härtungs-Plan (priorisiert)

Priorität 1 — Quick Wins (13 Tage Aufwand)

3.1 Windows protection.json ACL härten

Problem: Datei unter %ProgramData%\ReBreak\ ist für Standard-User lesbar.
Fix: Im elevated Setup-Script ACL direkt nach dem Schreiben setzen:

$acl = Get-Acl $state_path
$acl.SetAccessRuleProtection($true, $false)
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("SYSTEM","FullControl","Allow")
$acl.SetAccessRule($rule)
$rule2 = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrators","FullControl","Allow")
$acl.SetAccessRule($rule2)
# Standard-User: kein Zugriff
Set-Acl $state_path $acl

Effekt: DNS-Token nicht mehr über Datei extrahierbar ohne Admin-Rechte.
Aufwand: ~2h, nur protection-core/src/lib.rs + setup.rs-Script. Kein Backend-Change.

3.2 Debug-Code aus Mac Release-Build entfernen

Problem: DebugSupervisionMode enum + Debug-Reset-Logik in WizardModel.swift ist im Release-Build sichtbar.
Fix: #if DEBUG Guards um alle Debug-Felder und startDebugReset()-Methode.
Aufwand: ~1h.

3.3 Service-Name verschleiern (Windows)

Problem: RebreakProtection ist ein trivialer Stop-Angriff-Vektor.
Diskussion: Echter Schutz dagegen ist unmöglich — jeder Service-Name kann in der Service-Liste gesehen werden. Aber: einen weniger offensichtlichen Namen verwenden (z.B. rbkdnsd oder SystemDnsOptimizer) erhöht die Hürde für Script-Kiddies.
Aufwand: ~1h, aber Service-Name muss in protection-core, setup.rs, service/main.rs konsistent sein. + Re-Deploy.
Warnung: Security-Theater-Komponente. Echter Schutz: Windows Protected Services (nächste Priorität).

3.4 Intern-Kommentar-Strings aus Mac-Binary entfernen

Problem: Kommentare wie „app.rebreak.org hat aktuell falsches TLS-Zert" sind als Swift-String-Literals im Binary.
Fix: Kommentare in Code-Kommentare umwandeln (nicht String-Literals), Infobox-Texte externalisieren.
Aufwand: ~30min.


Priorität 2 — Mittlerer Aufwand (12 Wochen)

3.5 Windows: Protected Service / PPL (Größter Tamper-Schutz)

Problem: sc.exe stop RebreakProtection mit Admin reicht zum Bypass.
Lösung: Windows Protected Processes / Service Protection Level. Via sc.exe sdset + DACL oder (besser) Service als Protected Service signieren — verhindert Stop/Delete auch durch lokale Admins.
Realistisch: Echter PPL braucht Microsoft ELAM-Zertifikat (teuer + aufwändig). Alternativer Ansatz: DACL-Restriktion — Setup-Script entfernt die WRITE/STOP-Berechtigung von der "Administrators"-Gruppe auf dem Service-Object. Zwingt Angreifer zu mehr Aufwand (Token-Impersonation o.ä.).
Aufwand: ~3 Tage (Recherche + Test auf verschiedenen Windows-Versionen). Hypothese, ungeprüft — Windows Service DACL-Manipulation braucht sorgfältiges Testing.
Eskalation an rebreak-ops für Deploy, kein Backend-Change nötig.

3.6 Windows: PowerShell-Scripts verschlüsseln / nicht als String-Literal

Problem: Kompletter Teardown-Pfad im Binary.
Lösung A (einfach): Scripts zur Compile-Zeit mit einem festen XOR-Key oder AES-Key verschlüsseln, zur Laufzeit dekryptieren. Kein echter Schutz gegen entschlossenen Analysten, aber verhindert triviale strings-Analyse. Security-Theater-Level ist hoch.
Lösung B (besser): PowerShell-Scripts server-seitig halten. Client pollt bei Setup ein signiertes Script-Template vom Backend, führt es aus. Vorteil: Scripts updatebar ohne App-Release. Nachteil: Offline-Setup geht nicht.
Empfehlung: Lösung B für Teardown-Script (ohnehin server-getriggert), Lösung A für Setup (muss offline gehen).
Aufwand: Lösung A ~1 Tag; Lösung B ~3 Tage (+ Backend-Endpoint).

3.7 Mac: Profil-Removal-Kommando nicht im Binary

Problem: profiles remove -identifier org.rebreak.protection.profile.* im Source.
Kontext: Diese Funktion wird bewusst für Testing/Reset verwendet (MacProfileInstaller.remove()). Im finalen User-Flow ist sie nicht mehr erreichbar. Trotzdem im Binary vorhanden.
Lösung: remove() Methode in #if DEBUG wrappen. Im Release-Build nicht kompilieren.
Aufwand: ~30min.

3.8 Pairing-Code: Rate-Limiting auf Backend

Problem: 6-stelliger Code, 10min TTL. Aktuell kein explizites Rate-Limiting im /api/magic/pair/redeem-Endpoint sichtbar (IP-basiertes Rate-Limiting unklar).
Fix: Max. 10 Redeem-Attempts pro IP + 5 pro Code, danach 429. Im Nitro-Middleware oder Endpoint.
Aufwand: ~2h. Eskalation an rebreak-backend für generisches Rate-Limiting-Middleware falls noch nicht vorhanden.

3.9 protection.json DNS-Token verschlüsseln (Windows)

Problem: DNS-Token liegt im Klartext in der JSON-Datei.
Lösung: DNS-Token mit einem Geräteschlüssel (DPAPI unter Windows — ProtectedData.Protect mit DataProtectionScope.LocalMachine) verschlüsseln vor Speichern in protection.json. DPAPI bindet an die Machine — entschlüsselbar nur auf demselben Gerät, nicht auf einem anderen PC.
Effekt: Datei-Exfiltration nützt nichts. Lokaler Admin-Zugriff für Entschlüsselung nötig (aber dann eh vorbei).
Aufwand: ~2 Tage. Rust DPAPI via windows-sys Crate, braucht Windows-only Conditional Compilation.


Priorität 3 — Größerer Umbau / Nice-to-Have

3.10 Binary-Obfuscation

Mac (Swift): Swift hat keine etablierten Open-Source-Obfuskatoren. ProGuard-Äquivalent existiert nicht. Möglichkeiten:

  • Symbol-Stripping (ist Standard bei Release-Builds): reduziert Klassen/Methodennamen — bereits gut
  • swiftc mit Optimierungen + strip — kein echter RE-Schutz
  • Kommerzielle Tools (Obfusco, iXGuard) — teuer, fragile, selten Worth-it bei Swift

Windows (Rust): Rust-Binaries sind nach Release-Kompilierung bereits gut obfusziert (keine Klassen/Methoden-Namen ohne DWARF-Symbole). String-Literale bleiben das Problem (siehe 3.6). Packer wie UPX sind möglich aber:

  • AV-Programme flaggen UPX-gepackte Binaries häufig
  • Kein echter Security-Gain gegen entschlossenen Analysten

Empfehlung: Nicht investieren. ROI zu niedrig. Focus auf Secrets-Management + Service-Schutz.

3.11 Certificate Pinning für Backend-Calls

Aktuell: Standard-TLS (kein Pinning). MITM-Angriff theoretisch möglich wenn User eigenes Root-Cert installiert.
Mac: URLSession mit Custom URLSessionDelegate + Pinning auf staging.rebreak.org-Cert / SPKI.
Windows: reqwest mit Custom Certificate Verifier.
Aufwand: ~3 Tage. Wartungsaufwand hoch (Cert-Rotationen). Relevant vor allem wenn App auf app.rebreak.org (Prod) umgestellt wird.

3.12 Code-Signing Status

Mac (aktuell unbekannt): Notarization-Status des .app-Bundles ist unklar. Ohne Notarization zeigt macOS Gatekeeper-Warning beim ersten Start. Zuständigkeit: User + zied (Developer-ID Credentials).
Windows (aktuell unbekannt): Authenticode-Signatur des .exe. Ohne Signatur: SmartScreen-Warning bei Download/Start. Signatur mit EV Code Signing Cert (OV reicht nicht mehr für SmartScreen-Reputations-Aufbau). Zuständigkeit: User + zied.

Diese Punkte sind keine RE-Härtung, aber essentiell für User-Trust und Download-Conversion.


4. Zusammenfassung nach Plattform

Mac

# Maßnahme Aufwand Priorität
3.2 Debug-Code aus Release entfernen 1h Quick Win
3.4 Intern-Strings/Kommentare bereinigen 30min Quick Win
3.7 remove() auf #if DEBUG 30min Mittel
3.11 Cert-Pinning 3 Tage Nice-to-have
3.12 Notarization (User/zied) extern Eskalation

Windows

# Maßnahme Aufwand Priorität
3.1 protection.json ACL härten 2h Quick Win
3.3 Service-Name weniger offensichtlich 1h Quick Win
3.5 Service DACL-Restriktion (Prüfen) 3 Tage Mittel
3.6 PS-Scripts nicht als Klartext-Strings 13 Tage Mittel
3.9 DNS-Token DPAPI-verschlüsseln 2 Tage Mittel
3.12 Authenticode-Signatur (User/zied) extern Eskalation

Backend

# Maßnahme Aufwand Priorität
3.8 Pairing-Code Rate-Limiting 2h Quick Win

5. Was die Härtung NICHT schützt (Grenzen klar kommunizieren)

  • Admin-User kann alles aufheben. Das ist kein Bug, das ist Windows und macOS. Der echte Schutz ist der Cooldown-Server + die Psychologie (24h reichen oft für den Impuls zu vergehen).
  • Binary-Obfuscation ≠ Schutz. Ein entschlossener Competitor mit einem Analysten und einem Tag Zeit kommt an alles ran. Das Ziel ist: erhöhte Hürde für Gelegenheits-RE, nicht Unmöglichkeit.
  • Die Kern-Sicherheit liegt im Backend: Token-Revocation ist server-seitig. Kein lokaler Angriff kann ein revoked Token reaktivieren. Das ist die richtige Architektur-Entscheidung und bleibt so.

6. Empfohlene Implementierungs-Reihenfolge

  1. Sofort (vor Public-Download): 3.1 (ACL) + 3.2 (Debug-Guards) + 3.7 (Remove-Method) + 3.8 (Rate-Limiting) — zusammen ~1 Tag
  2. Sprint 1 (Woche 1): 3.9 (DPAPI) + 3.6 Lösung A (Script-Obfuskation, keine echte Sicherheit aber reduziert Einblick)
  3. Sprint 2 (Woche 23): 3.5 (Service-DACL, mit Test-Aufwand) + 3.11 (Cert-Pinning wenn auf Prod)
  4. Parallel, Founder/zied: 3.12 Notarization + Authenticode — blockieren Download-Funnel ohne sie

7. Dateipfade für Implementierung

Quick Wins betreffen:

  • apps/rebreak-magic-win/src-tauri/protection-core/src/lib.rs — ACL im Setup-Script-Generator, Service-Name
  • apps/rebreak-magic-win/src-tauri/src/setup.rs — ACL-Kommando im build_setup_script
  • apps/rebreak-magic-mac/Sources/Models/WizardModel.swift — #if DEBUG Guards
  • apps/rebreak-magic-mac/Sources/Services/MacProfileInstaller.swift — remove() in #if DEBUG
  • apps/rebreak-magic-mac/Sources/Services/MagicAPIClient.swift — Kommentar-Strings
  • backend/server/api/magic/pair/redeem.post.ts — Rate-Limiting