Metodologia di pentesting per le estensioni del browser
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.
Informazioni di base
Le estensioni del browser sono scritte in JavaScript e caricate dal browser in background. Hanno il proprio DOM ma possono interagire con il DOM di altri siti. Questo significa che possono compromettere la riservatezza, l’integrità e la disponibilità (CIA) di altri siti.
Componenti principali
Le architetture delle estensioni si comprendono meglio se visualizzate e consistono di tre componenti. Esaminiamo ciascuna componente in dettaglio.
 (1) (1).png)
Content Scripts
Each content script has direct access to the DOM of a single web page and is thereby exposed to potentially malicious input. However, the content script contains no permissions other than the ability to send messages to the extension core.
Extension Core
Il core dell’estensione contiene la maggior parte dei privilegi/accessi dell’estensione, ma l’extension core può interagire con i contenuti web solo tramite [XMLHttpRequest] e content script. Inoltre, l’extension core non ha accesso diretto alla macchina host.
Native Binary
L’estensione può includere un native binary che può accedere alla macchina host con i pieni privilegi dell’utente. Il native binary interagisce con l’extension core tramite la Netscape Plugin Application Programming Interface ([NPAPI]) utilizzata da Flash e da altri plug-in del browser.
Confini
Caution
Per ottenere i pieni privilegi dell’utente, un attaccante deve convincere l’estensione a trasferire input malevoli dal content script all’extension core e dall’extension core al native binary.
Ogni componente dell’estensione è separato dagli altri da forti barriere protettive. Ogni componente viene eseguito in un processo separato del sistema operativo. I content scripts e gli extension cores vengono eseguiti in sandbox processes non accessibili alla maggior parte dei servizi del sistema operativo.
Inoltre, i content scripts sono separati dalle rispettive pagine web associate perché vengono eseguiti in un heap JavaScript separato. Il content script e la pagina web hanno accesso allo stesso DOM sottostante, ma i due non scambiano mai puntatori JavaScript, impedendo il leaking della funzionalità JavaScript.
manifest.json
Un’estensione Chrome è essenzialmente una cartella ZIP con una .crx file extension. Il core dell’estensione è il file manifest.json nella root della cartella, che specifica struttura, permessi e altre opzioni di configurazione.
Esempio:
{
"manifest_version": 2,
"name": "My extension",
"version": "1.0",
"permissions": ["storage"],
"content_scripts": [
{
"js": ["script.js"],
"matches": ["https://example.com/*", "https://www.example.com/*"],
"exclude_matches": ["*://*/*business*"]
}
],
"background": {
"scripts": ["background.js"]
},
"options_ui": {
"page": "options.html"
}
}
content_scripts
Content scripts vengono caricati ogni volta che l’utente naviga verso una pagina corrispondente, nel nostro caso qualsiasi pagina che corrisponde all’espressione https://example.com/* e non corrisponde alla regex *://*/*/business*. Vengono eseguiti come gli script della pagina stessa e hanno accesso arbitrario al Document Object Model (DOM) della pagina.
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
Per includere o escludere più URL è inoltre possibile usare include_globs e exclude_globs.
Questo è un esempio di content script che aggiungerà un pulsante “explain” alla pagina e utilizzerà the storage API per recuperare il valore message dallo storage dell’estensione.
chrome.storage.local.get("message", (result) => {
let div = document.createElement("div")
div.innerHTML = result.message + " <button>Explain</button>"
div.querySelector("button").addEventListener("click", () => {
chrome.runtime.sendMessage("explain")
})
document.body.appendChild(div)
})
.png)
Quando questo pulsante viene cliccato, viene inviato un messaggio alle pagine dell’estensione dal content script tramite l’utilizzo della runtime.sendMessage() API. Ciò è dovuto alla limitazione del content script nell’accesso diretto alle API, con storage tra le poche eccezioni. Per le funzionalità oltre queste eccezioni, i messaggi vengono inviati alle pagine dell’estensione con cui i content script possono comunicare.
Warning
A seconda del browser, le capacità del content script possono variare leggermente. Per i browser basati su Chromium, l’elenco delle capacità è disponibile nella Chrome Developers documentation, e per Firefox, l’MDN funge da fonte principale.
È inoltre importante notare che i content script possono comunicare con i background script, permettendo loro di eseguire azioni e riportare le risposte.
Per visualizzare e fare il debug dei content script in Chrome, il menu Chrome developer tools può essere aperto da Options > More tools > Developer tools OR premendo Ctrl + Shift + I.
Una volta visualizzati i developer tools, cliccare la Source tab, seguita dalla Content Scripts tab. Questo permette di osservare i content script in esecuzione delle varie estensioni e impostare breakpoint per tracciare il flusso di esecuzione.
Content script iniettati
Tip
Nota che Content Scripts non sono obbligatori in quanto è anche possibile iniettare dinamicamente script e iniettarli programmaticamente nelle pagine web tramite
tabs.executeScript. Questo fornisce in realtà controlli più granulari.
Per l’iniezione programmatica di un content script, l’estensione deve avere host permissions per la pagina nella quale gli script devono essere iniettati. Questi permessi possono essere ottenuti sia richiedendoli nel manifest dell’estensione, sia temporaneamente tramite activeTab.
Esempio di estensione basata su activeTab
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- Iniettare un file JS al clic:
// content-script.js
document.body.style.backgroundColor = "orange"
//service-worker.js - Inject the JS file
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["content-script.js"],
})
})
- Iniettare una funzione al clic:
//service-worker.js - Inject a function
function injectedFunction() {
document.body.style.backgroundColor = "orange"
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: injectedFunction,
})
})
Esempio con permessi di scripting
// service-workser.js
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
excludeMatches: ["*://*/*business*"],
js: ["contentScript.js"],
},
])
// Another example
chrome.tabs.executeScript(tabId, { file: "content_script.js" })
Per includere o escludere più URL è anche possibile usare include_globs e exclude_globs.
Script di contenuto run_at
Il campo run_at controlla quando i file JavaScript vengono iniettati nella pagina web. Il valore preferito e di default è "document_idle".
I valori possibili sono:
document_idle: Quando possibiledocument_start: Dopo eventuali file dacss, ma prima che qualsiasi altra parte del DOM venga costruita o che qualsiasi altro script venga eseguito.document_end: Immediatamente dopo che il DOM è completo, ma prima che sottorisorse come immagini e frame siano caricate.
Tramite manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
Tramite service-worker.js
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])
background
I messaggi inviati dai content scripts vengono ricevuti dalla background page, che svolge un ruolo centrale nel coordinare i componenti dell’estensione. È importante notare che la background page persiste per tutta la durata dell’estensione, funzionando in modo discreto senza interazione diretta con l’utente. Possiede il proprio Document Object Model (DOM), permettendo interazioni complesse e la gestione dello stato.
Punti chiave:
- Background Page Role: Agisce come centro nevralgico dell’estensione, garantendo comunicazione e coordinamento tra le varie parti dell’estensione.
- Persistence: È un’entità sempre presente, invisibile all’utente ma integrante per il funzionamento dell’estensione.
- Automatic Generation: Se non definita esplicitamente, il browser creerà automaticamente una background page. Questa pagina auto-generata includerà tutti i background scripts specificati nel manifest dell’estensione, garantendo il funzionamento senza interruzioni delle attività di background dell’estensione.
Tip
La comodità fornita dal browser nel generare automaticamente una background page (quando non dichiarata esplicitamente) garantisce che tutti i background scripts necessari siano integrati e operativi, semplificando il processo di configurazione dell’estensione.
Example background script:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request == "explain") {
chrome.tabs.create({ url: "https://example.net/explanation" })
}
})
Utilizza runtime.onMessage API per ascoltare i messaggi. Quando viene ricevuto un messaggio "explain", usa tabs API per aprire una pagina in una nuova scheda.
Per fare il debug dello script di background puoi andare ai dettagli dell’estensione e ispezionare il service worker, questo aprirà gli strumenti per sviluppatori con lo script di background:
Options pages e altro
Le estensioni del browser possono contenere vari tipi di pagine:
- Action pages vengono visualizzate in un menu a discesa quando l’icona dell’estensione viene cliccata.
- Pagine che l’estensione caricherà in una nuova scheda.
- Option Pages: Questa pagina viene mostrata sopra l’estensione quando viene cliccata. Nel manifest precedente, nel mio caso sono riuscito ad accedere a questa pagina in
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjcao cliccando:
.png)
Nota che queste pagine non sono persistenti come le background pages poiché caricano dinamicamente il contenuto solo quando necessario. Nonostante ciò, condividono alcune capacità con la pagina di background:
- Communication with Content Scripts: Simile alla pagina di background, queste pagine possono ricevere messaggi dai content scripts, facilitando l’interazione all’interno dell’estensione.
- Access to Extension-Specific APIs: Queste pagine hanno pieno accesso alle API specifiche dell’estensione, soggette ai permessi definiti per l’estensione.
permissions & host_permissions
permissions e host_permissions sono voci del manifest.json che indicano quali permessi ha l’estensione del browser (storage, location…) e in quali pagine web.
Poiché le estensioni del browser possono essere così privilegiate, un’estensione malevola o compromessa potrebbe permettere all’attaccante diversi modi per rubare informazioni sensibili e spiare l’utente.
Controlla come funzionano queste impostazioni e in che modo potrebbero essere abusate in:
BrowExt - permissions & host_permissions
content_security_policy
Una content security policy può essere dichiarata anche all’interno del manifest.json. Se è definita, potrebbe essere vulnerabile.
L’impostazione predefinita per le pagine delle estensioni del browser è piuttosto restrittiva:
script-src 'self'; object-src 'self';
Per maggiori informazioni su CSP e possibili bypass consulta:
Content Security Policy (CSP) Bypass
web_accessible_resources
Perché una pagina web possa accedere a una pagina di un’estensione del browser, ad esempio una .html, questa pagina deve essere indicata nel campo web_accessible_resources del manifest.json.
Per esempio:
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
Queste pagine sono accessibili tramite URL come:
chrome-extension://<extension-id>/message.html
Nelle estensioni pubbliche l’extension-id è accessibile:
.png)
Tuttavia, se nel manifest.json viene usato il parametro use_dynamic_url, questo id può essere dinamico.
Tip
Nota che anche se una pagina è menzionata qui, potrebbe essere protetta contro ClickJacking grazie alla Content Security Policy. Quindi devi anche verificarla (sezione frame-ancestors) prima di confermare che un attacco ClickJacking sia possibile.
Il permettere l’accesso a queste pagine le rende potenzialmente vulnerabili a ClickJacking:
Tip
Consentire che queste pagine vengano caricate solo dall’estensione e non da URL casuali potrebbe prevenire attacchi ClickJacking.
Caution
Nota che le pagine indicate in
web_accessible_resourcese altre pagine dell’estensione sono anche in grado di contattare background scripts. Quindi, se una di queste pagine è vulnerabile a XSS potrebbe portare a una vulnerabilità più ampia.Inoltre, tieni presente che puoi aprire solo le pagine indicate in
web_accessible_resourcesall’interno di iframe, ma da una nuova scheda è possibile accedere a qualsiasi pagina dell’estensione conoscendo l’extension ID. Pertanto, se viene trovata una XSS che abusa degli stessi parametri, potrebbe essere sfruttata anche se la pagina non è configurata inweb_accessible_resources.
externally_connectable
Secondo la docs, la proprietà manifest "externally_connectable" dichiara quali extension e pagine web possono connettersi alla tua estensione tramite runtime.connect e runtime.sendMessage.
- Se la chiave
externally_connectablenon è dichiarata nel manifest della tua estensione o è dichiarata come"ids": ["*"], tutte le estensioni possono connettersi, ma nessuna pagina web può connettersi. - Se vengono specificati ID specifici, come in
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], solo quelle applicazioni possono connettersi. - Se sono specificati matches, quelle web app potranno connettersi:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- Se è specificato vuoto:
"externally_connectable": {}, nessuna app o pagina web potrà connettersi.
Meno estensioni e URL sono indicate qui, minore sarà la superficie di attacco.
Caution
Se una pagina web vulnerable to XSS or takeover è indicata in
externally_connectable, un attaccante potrà send messages directly to the background script, aggirando completamente il Content Script e la sua CSP.Quindi, questo è un very powerful bypass.
Inoltre, se il client installa un rogue extension, anche se non è autorizzata a comunicare con l’estensione vulnerabile, potrebbe inject XSS data in an allowed web page o abusare delle API
WebRequestoDeclarativeNetRequestper manipolare le richieste su un dominio target alterando la richiesta di una pagina per un JavaScript file. (Nota che la CSP sulla pagina target potrebbe prevenire questi attacchi). Questa idea proviene from this writeup.
Riepilogo della comunicazione
Extension <–> WebApp
Per comunicare tra il content script e la pagina web si usano solitamente post messages. Pertanto, nell’applicazione web troverai di solito chiamate alla funzione window.postMessage e, nel content script, listener come window.addEventListener. Nota però che l’extension potrebbe anche communicate with the web application sending a Post Message (e quindi l’applicazione web dovrebbe aspettarselo) o semplicemente far caricare alla pagina un nuovo script.
Inside the extension
Solitamente la funzione chrome.runtime.sendMessage è usata per inviare un messaggio all’interno dell’estensione (di solito gestito dallo script background) e per riceverlo e gestirlo viene dichiarato un listener che chiama chrome.runtime.onMessage.addListener.
È anche possibile usare chrome.runtime.connect() per avere una connessione persistente invece di inviare singoli messaggi; può essere usata per inviare e ricevere messaggi come nell’esempio seguente:
chrome.runtime.connect() esempio
```javascript
var port = chrome.runtime.connect()
// Listen for messages from the web page window.addEventListener( “message”, (event) => { // Only accept messages from the same window if (event.source !== window) { return }
// Check if the message type is “FROM_PAGE” if (event.data.type && event.data.type === “FROM_PAGE”) { console.log(“Content script received: “ + event.data.text) // Forward the message to the background script port.postMessage({ type: “FROM_PAGE”, text: event.data.text }) } }, false )
// Listen for messages from the background script port.onMessage.addListener(function (msg) { console.log(“Content script received message from background script:”, msg) // Handle the response message from the background script })
</details>
È anche possibile inviare messaggi da uno script di background a uno script di contenuto presente in una scheda specifica chiamando **`chrome.tabs.sendMessage`**, dove sarà necessario indicare l'**ID of the tab** a cui inviare il messaggio.
### Dalle origini consentite in `externally_connectable` all'estensione
**Web app e estensioni del browser esterne consentite** nella configurazione `externally_connectable` possono inviare richieste usando :
```javascript
chrome.runtime.sendMessage(extensionId, ...
Dove è necessario menzionare l’extension ID.
Native Messaging
È possibile che i background scripts comunichino con binari all’interno del sistema, i quali potrebbero essere soggetti a vulnerabilità critiche come le RCEs se questa comunicazione non è adeguatamente protetta. More on this later.
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
Web ↔︎ Comunicazione con Content Script
Gli ambienti in cui operano i content scripts e quelli in cui risiedono le pagine host sono separati l’uno dall’altro, garantendo isolamento. Nonostante questo isolamento, entrambi possono interagire con il Document Object Model (DOM) della pagina, una risorsa condivisa. Affinché la pagina host comunichi con il content script, o indirettamente con l’estensione tramite il content script, è necessario utilizzare il DOM accessibile a entrambe le parti come canale di comunicazione.
Post Messages
// This is like "chrome.runtime.sendMessage" but to maintain the connection
var port = chrome.runtime.connect()
window.addEventListener(
"message",
(event) => {
// We only accept messages from ourselves
if (event.source !== window) {
return
}
if (event.data.type && event.data.type === "FROM_PAGE") {
console.log("Content script received: " + event.data.text)
// Forward the message to the background script
port.postMessage(event.data.text)
}
},
false
)
document.getElementById("theButton").addEventListener(
"click",
() => {
window.postMessage(
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
"*"
)
},
false
)
Una comunicazione Post Message sicura dovrebbe verificare l’autenticità del messaggio ricevuto, ciò può essere fatto verificando:
event.isTrusted: This is True only if the event was triggered by a users action- Il Content Script potrebbe aspettarsi un messaggio solo se l’utente esegue qualche azione
- origin domain: potrebbe aspettarsi un messaggio solo da una allowlist di domini.
- If a regex is used, be very careful
- Source:
received_message.source !== windowpuò essere usato per verificare se il messaggio era dalla stessa window dove il Content Script sta ascoltando.
I controlli precedenti, anche se eseguiti, potrebbero essere vulnerabili, quindi controlla nella pagina seguente i potenziali bypass di Post Message:
Iframe
Un altro possibile modo di comunicazione può essere tramite Iframe URLs, trovi un esempio in:
DOM
Questo non è “esattamente” un modo di comunicazione, ma il web e il Content Script avranno accesso al web DOM. Quindi, se il Content Script legge alcune informazioni da esso, fidandosi del web DOM, il web potrebbe modificare questi dati (perché il web non dovrebbe essere considerato affidabile, o perché il web è vulnerabile a XSS) e compromettere il Content Script.
Puoi anche trovare un esempio di una DOM based XSS to compromise a browser extension in:
Content Script ↔︎ Background Script Comunicazione
Un Content Script può usare le funzioni runtime.sendMessage() or tabs.sendMessage() per inviare un messaggio monouso serializzabile in JSON.
Per gestire la risposta, usa la Promise restituita. Tuttavia, per compatibilità retroattiva, puoi ancora passare una callback come ultimo argomento.
Esempio di invio di una richiesta da un content script:
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
Invio di una richiesta dall’extension (di solito un background script). Esempio di come inviare un messaggio al content script nella scheda selezionata:
// From https://stackoverflow.com/questions/36153999/how-to-send-a-message-between-chrome-extension-popup-and-content-script
;(async () => {
const [tab] = await chrome.tabs.query({
active: true,
lastFocusedWindow: true,
})
const response = await chrome.tabs.sendMessage(tab.id, { greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
Sul lato ricevente, devi impostare un runtime.onMessage event listener per gestire il messaggio. Funziona allo stesso modo sia da un content script che da una extension page.
// From https://stackoverflow.com/questions/70406787/javascript-send-message-from-content-js-to-background-js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(
sender.tab
? "from a content script:" + sender.tab.url
: "from the extension"
)
if (request.greeting === "hello") sendResponse({ farewell: "goodbye" })
})
Nell’esempio evidenziato, sendResponse() è stato eseguito in modo sincrono. Per modificare l’event handler onMessage per l’esecuzione asincrona di sendResponse(), è necessario includere return true;.
Una considerazione importante è che, in scenari in cui più pagine sono impostate per ricevere eventi onMessage, la prima pagina che esegue sendResponse() per uno specifico evento sarà l’unica in grado di consegnare efficacemente la risposta. Qualsiasi risposta successiva allo stesso evento non verrà presa in considerazione.
Quando si sviluppano nuove estensioni, è preferibile usare promises piuttosto che callbacks. Per quanto riguarda l’uso di callbacks, la funzione sendResponse() è considerata valida solo se viene eseguita direttamente nel contesto sincrono, oppure se l’event handler indica un’operazione asincrona restituendo true. Se nessuno degli handler restituisce true o se la funzione sendResponse() viene rimossa dalla memoria (garbage-collected), il callback associato a sendMessage() verrà eseguito di default.
Native Messaging
Le estensioni del browser consentono inoltre di comunicare con binaries in the system via stdin. L’applicazione deve installare un json che lo dichiari in un json del tipo:
{
"name": "com.my_company.my_application",
"description": "My Application",
"path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
"type": "stdio",
"allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"]
}
Dove il name è la stringa passata a runtime.connectNative() o a runtime.sendNativeMessage() per comunicare con l’applicazione dagli background scripts dell’estensione. Il path è il percorso al binario, esiste un solo type valido che è stdio (use stdin and stdout) e gli allowed_origins indicano le estensioni che possono accedervi (e non possono avere wildcard).
Chrome/Chromium cercherà questo json in alcune chiavi del registro di Windows e in alcuni percorsi su macOS e Linux (maggiori info nella docs).
Tip
L’estensione del browser necessita anche del permesso
nativeMessaingdichiarato per poter usare questa comunicazione.
Ecco un esempio di codice di background script che invia messaggi a un’applicazione nativa:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In this blog post, è proposto un pattern vulnerabile che abusa dei native messages:
- Browser Extension ha un pattern wildcard per il content script.
- Il content script passa messaggi
postMessageallo background script usandosendMessage. - Lo background script passa il messaggio all’applicazione native usando
sendNativeMessage. - L’applicazione native gestisce il messaggio in modo pericoloso, portando a code execution.
E al suo interno è spiegato un esempio di come passare da qualsiasi pagina a RCE abusando di un browser extension.
Sensitive Information in Memory/Code/Clipboard
Se una Browser Extension memorizza informazioni sensibili nella sua memoria, queste possono essere dumpate (soprattutto su macchine Windows) e ricercate per ottenere tali informazioni.
Pertanto, la memoria della Browser Extension non dovrebbe essere considerata sicura e le informazioni sensibili come credenziali o frasi mnemoniche non dovrebbero essere memorizzate.
Ovviamente, non mettere informazioni sensibili nel codice, poiché saranno pubbliche.
Per dumpare la memoria dal browser puoi dumpare la memoria del processo oppure andare nelle impostazioni dell’estensione del browser cliccare su Inspect pop-up -> Nella sezione Memory -> Take a snaphost e usare CTRL+F per cercare all’interno dello snapshot informazioni sensibili.
Inoltre, informazioni altamente sensibili come chiavi mnemonic o password non dovrebbero poter essere copiate negli appunti (o almeno rimosse dagli appunti dopo pochi secondi) perché allora processi che monitorano gli appunti potranno recuperarle.
Loading an Extension in the Browser
- Scarica la Browser Extension e decomprimila
- Vai a
chrome://extensions/e abilita laDeveloper Mode - Clicca sul pulsante
Load unpacked
In Firefox vai su about:debugging#/runtime/this-firefox e clicca sul pulsante Load Temporary Add-on.
Getting the source code from the store
Il sorgente di una Chrome extension può essere ottenuto tramite vari metodi. Qui sotto sono fornite spiegazioni dettagliate e istruzioni per ogni opzione.
Download Extension as ZIP via Command Line
Il sorgente di una Chrome extension può essere scaricato come file ZIP usando la command line. Questo implica l’uso di curl per recuperare il file ZIP da una URL specifica e poi estrarre il contenuto del ZIP in una directory. Ecco i passaggi:
- Sostituisci
"extension_id"con l’ID reale dell’estensione. - Esegui i seguenti comandi:
extension_id=your_extension_id # Replace with the actual extension ID
curl -L -o "$extension_id.zip" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&nacl_arch=x86-64&prod=chromecrx&prodchannel=stable&prodversion=44.0.2403.130&x=id%3D$extension_id%26uc"
unzip -d "$extension_id-source" "$extension_id.zip"
Usa il sito CRX Viewer
Usa l’estensione CRX Viewer
Un altro metodo comodo è usare il Chrome Extension Source Viewer, che è un progetto open-source. Può essere installato dal Chrome Web Store. Il codice sorgente del viewer è disponibile nel suo GitHub repository.
Visualizza il sorgente di un’estensione installata localmente
Chrome extensions installate localmente possono anche essere ispezionate. Ecco come:
- Accedi alla directory del profilo locale di Chrome visitando
chrome://version/e individuando il campo “Profile Path”. - Vai nella sottocartella
Extensions/all’interno della directory del profilo. - Questa cartella contiene tutte le estensioni installate, di solito con il codice sorgente in un formato leggibile.
Per identificare le estensioni, puoi mappare i loro ID ai nomi:
- Abilita Developer Mode nella pagina
about:extensionsper vedere gli ID di ciascuna estensione. - All’interno della cartella di ogni estensione, il file
manifest.jsoncontiene un campo leggibilename, che aiuta a identificare l’estensione.
Usa un archiviatore di file o un unpacker
Vai al Chrome Web Store e scarica l’estensione. Il file avrà estensione .crx. Cambia l’estensione del file da .crx a .zip. Usa un qualsiasi archiviatore (come WinRAR, 7-Zip, ecc.) per estrarre il contenuto del file ZIP.
Usa Developer Mode in Chrome
Apri Chrome e vai su chrome://extensions/. Abilita “Developer mode” in alto a destra. Clicca su “Load unpacked extension…”. Naviga fino alla directory della tua estensione. Questo non scarica il codice sorgente, ma è utile per visualizzare e modificare il codice di un’estensione già scaricata o sviluppata.
Chrome extension manifest dataset
Per provare a individuare estensioni del browser vulnerabili potresti usare il https://github.com/palant/chrome-extension-manifests-dataset e controllare i loro file manifest per segni potenzialmente vulnerabili. Ad esempio, per controllare estensioni con più di 25000 utenti, content_scripts e il permesso nativeMessaing:
# Query example from https://spaceraccoon.dev/universal-code-execution-browser-extensions/
node query.js -f "metadata.user_count > 250000" "manifest.content_scripts?.length > 0 && manifest.permissions?.includes('nativeMessaging')"
Post-exploitation: Forced extension load & persistence (Windows)
Tecnica stealth per inserire un backdoor in Chromium modificando direttamente le Preferences per utente e forgiando HMACs validi, facendo sì che il browser accetti e attivi un unpacked extension arbitrario senza prompt o flag.
Forced Extension Load Preferences Mac Forgery Windows
Detecting Malicious Extension Updates (Static Version Diffing)
Le compromissioni della supply-chain spesso si presentano come malicious updates a estensioni precedentemente benigni. Un approccio pratico e a basso rumore è confrontare un nuovo pacchetto di estensione con l’ultima versione conosciuta come buona usando analisi statica (per esempio, Assemblyline). L’obiettivo è allertare su delta ad alto segnale piuttosto che su qualsiasi cambiamento.
Workflow
- Inviare entrambe le versioni (old + new) allo stesso profilo di static-analysis.
- Segnalare nuovi o aggiornati background/service worker scripts (persistenza + logica privilegiata).
- Segnalare nuovi o aggiornati content scripts (accesso al DOM e raccolta dati).
- Segnalare nuove permissions/host_permissions aggiunte in
manifest.json. - Segnalare nuovi domini estratti dal codice (possibili endpoint C2/exfil).
- Segnalare nuove rilevazioni di static-analysis (es. base64 decode, cookie harvesting, network-request builders, pattern di obfuscation).
- Segnalare anomalie statistiche come improvvisi aumenti di entropy o z-score anomali negli script modificati.
Detecting script changes accurately
- Nuovo script aggiunto → rilevare tramite diff di
manifest.json. - Script esistente modificato (manifest invariato) → confrontare gli hash per-file dell’albero dei file estratti (es. output
Extractdi Assemblyline). Questo cattura aggiornamenti stealth a worker esistenti o content scripts.
Pre-disclosure detections
Per evitare rilevamenti “easy mode” basati su IOCs già noti, disabilitare servizi alimentati da threat-intel e fare affidamento su segnali intrinseci (domini, firme euristiche, delta degli script, anomalie di entropy). Questo aumenta le probabilità di catturare aggiornamenti malevoli prima della segnalazione pubblica.
Example high-confidence alert logic
- Low-noise combo: new domains + new static-analysis detections + updated background/service worker + updated or added content scripts.
- Broader catch: new domain + new or updated background/service worker (maggiore recall, più rumore).
Servizi chiave di Assemblyline per questo workflow:
- Extract: disimballa l’estensione e fornisce hash per-file.
- Characterize: calcola caratteristiche dei file (es. entropy).
- JsJAWS / FrankenStrings / URLCreator: estraggono euristiche JS, stringhe e domini da differenziare tra le versioni.
Security Audit Checklist
Anche se le estensioni del browser hanno una superficie di attacco limitata, alcune potrebbero contenere vulnerabilità o possibili miglioramenti di hardening. Le seguenti sono le più comuni:
- Limitare il più possibile le richieste di
permissions - Limitare il più possibile le
host_permissions - Usare una strong
content_security_policy - Limitare il più possibile
externally_connectable; se non necessario, non lasciarlo di default, specificare{} - Se è menzionata un URL vulnerabile a XSS o a takeover, un attaccante potrà inviare messaggi direttamente ai background scripts. Bypass molto potente.
- Limitare il più possibile le
web_accessible_resources, anche vuote se possibile. - Se
web_accessible_resourcesnon è none, controllare per ClickJacking - Se qualsiasi comunicazione avviene dall’extension alla web page, controllare XSS vulnerabilities causate nella comunicazione.
- Se vengono usati Post Messages, controllare per Post Message vulnerabilities.
- Se il Content Script accede ai dettagli del DOM, verificare che non introduca XSS se viene modificato dalla pagina web
- Dare particolare attenzione se questa comunicazione coinvolge anche la Content Script -> Background script communication
- Se il background script comunica via native messaging verificare che la comunicazione sia sicura e sanitizzata
- Informazioni sensibili non dovrebbero essere memorizzate all’interno del codice dell’extension
- Informazioni sensibili non dovrebbero essere memorizzate nella memoria dell’extension
- Informazioni sensibili non dovrebbero essere memorizzate nel file system non protetto
Browser Extension Risks
- L’app https://crxaminer.tech/ analizza alcuni dati come le permissions richieste dall’estensione del browser per fornire un livello di rischio nell’uso dell’estensione.
Tools
Tarnish
- Recupera qualsiasi Chrome extension da un link fornito del Chrome webstore.
- manifest.json viewer: mostra semplicemente una versione prettified JSON del manifest dell’estensione.
- Fingerprint Analysis: rilevamento di web_accessible_resources e generazione automatica di JavaScript per fingerprinting delle Chrome extension.
- Potential Clickjacking Analysis: rilevamento di pagine HTML dell’estensione con la direttiva web_accessible_resources impostata. Queste possono essere potenzialmente vulnerabili a clickjacking a seconda dello scopo delle pagine.
- Permission Warning(s) viewer: mostra la lista di tutti gli avvisi di permission prompt di Chrome che verranno visualizzati quando un utente tenta di installare l’estensione.
- Dangerous Function(s): mostra la posizione di funzioni pericolose che potrebbero essere sfruttate da un attaccante (es. innerHTML, chrome.tabs.executeScript).
- Entry Point(s): mostra dove l’estensione riceve input dall’utente/esterno. Utile per comprendere la superficie dell’estensione e cercare punti potenzialmente sfruttabili per inviare dati malevolmente crafted all’estensione.
- Sia lo scanner Dangerous Function(s) che Entry Point(s) forniscono per gli avvisi generati:
- Snippet di codice rilevante e la riga che ha causato l’avviso.
- Descrizione dell’issue.
- Un pulsante “View File” per visualizzare il file sorgente completo contenente il codice.
- Il path del file segnalato.
- L’URI completo dell’estensione Chrome del file segnalato.
- Il tipo di file, come Background Page script, Content Script, Browser Action, ecc.
- Se la riga vulnerabile è in un file JavaScript, i path di tutte le pagine dove è incluso e il tipo di queste pagine, e lo stato di web_accessible_resource.
- Content Security Policy (CSP) analyzer and bypass checker: indica debolezze nella CSP dell’estensione e illumina eventuali modi per bypassarla dovuti a CDN whitelistate, ecc.
- Known Vulnerable Libraries: usa Retire.js per verificare l’uso di librerie JavaScript note come vulnerabili.
- Download dell’estensione e versioni formattate.
- Download dell’estensione originale.
- Download di una versione beautified dell’estensione (HTML e JavaScript auto-prettified).
- Caching automatico dei risultati della scansione; eseguire una scansione richiederà tempo la prima volta, mentre una seconda esecuzione sarà quasi istantanea se l’estensione non è stata aggiornata.
- URL di report linkabili, per condividere facilmente il report generato da tarnish.
Neto
Project Neto è un package Python 3 concepito per analizzare e svelare funzionalità nascoste di plugin ed extension per browser noti come Firefox e Chrome. Automatizza il processo di unzip dei file confezionati per estrarre queste funzionalità da risorse rilevanti in un’estensione come manifest.json, cartelle di localizzazione o file sorgente Javascript e HTML.
References
- Thanks to @naivenom for the help with this methodology
- https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing
- https://palant.info/2022/08/10/anatomy-of-a-basic-extension/
- https://palant.info/2022/08/24/attack-surface-of-extension-pages/
- https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/
- https://help.passbolt.com/assets/files/PBL-02-report.pdf
- https://developer.chrome.com/docs/extensions/develop/concepts/content-scripts
- https://developer.chrome.com/docs/extensions/mv2/background-pages
- https://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/
- https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0
- https://redcanary.com/blog/threat-detection/assemblyline-browser-extensions/
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.


