41 KiB
Metodologija Browser Extension Pentesting
{{#include ../../banners/hacktricks-training.md}}
Osnovne informacije
Browser ekstenzije su napisane u JavaScript i učitavaju se u pozadini pregledača. Imaju svoj DOM ali mogu da interaguju sa DOM-ovima drugih sajtova. To znači da mogu ugroziti poverljivost, integritet i dostupnost (CIA).
Glavne komponente
Izgled ekstenzije najbolje je vizuelizovati i sastoji se iz tri komponente. Pogledajmo svaku komponentu detaljno.

Skripte sadržaja (Content Scripts)
Svaka skripta sadržaja ima direktan pristup DOM-u jedne web stranice i time je izložena potencijalno zlonamernom unosu. Međutim, skripta sadržaja nema dozvole osim mogućnosti slanja poruka jezgru ekstenzije.
Jezgro ekstenzije (Extension Core)
Jezgro ekstenzije sadrži većinu privilegija/pristupa ekstenzije, ali jezgro ekstenzije može da interaguje sa web sadržajem samo putem XMLHttpRequest i content scripts. Takođe, jezgro ekstenzije nema direktan pristup host mašini.
Native Binary
Ekstenzija dozvoljava nativni binarni fajl koji može da pristupi host mašini sa punim privilegijama korisnika. Nativni binarni fajl komunicira sa jezgrom ekstenzije kroz standardni Netscape Plugin Application Programming Interface (NPAPI) koji koriste Flash i drugi browser plug-inovi.
Granice
Caution
Da bi napadač dobio pune privilegije korisnika, mora ubediti ekstenziju da prosledi zlonamerni unos iz skripte sadržaja u jezgro ekstenzije i iz jezgra ekstenzije u nativni binarni fajl.
Svaka komponenta ekstenzije je odvojena od ostalih snažnim zaštitnim granicama. Svaka komponenta se izvršava u zasebnom procesu operativnog sistema. Skripte sadržaja i jezgra ekstenzije rade u sandbox procesima koji nisu dostupni većini servisa operativnog sistema.
Štaviše, skripte sadržaja su odvojene od povezanih web stranica tako što se izvršavaju u zasebnom JavaScript heap-u. Skripta sadržaja i web stranica imaju pristup istom osnovnom DOM-u, ali ta dva nikada ne razmenjuju JavaScript pokazivače, sprečavajući leaking JavaScript funkcionalnosti.
manifest.json
Chrome ekstenzija je u suštini ZIP folder sa .crx file extension. Jezgro ekstenzije je manifest.json
fajl u korenu foldera, koji specificira izgled, dozvole i druge konfiguracione opcije.
Primer:
{
"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 se učitavaju kad god korisnik navigira na odgovarajuću stranicu, u našem slučaju bilo kojoj stranici koja odgovara izrazu https://example.com/*
i koja ne odgovara regexu *://*/*/business*
. Izvršavaju se kao skripte same stranice i imaju proizvoljan pristup stranici Document Object Model (DOM).
"content_scripts": [
{
"js": [
"script.js"
],
"matches": [
"https://example.com/*",
"https://www.example.com/*"
],
"exclude_matches": ["*://*/*business*"],
}
],
Da biste uključili ili isključili više URL-ova, možete koristiti i include_globs
i exclude_globs
.
Ovo je primer content script-a koji će dodati dugme 'explain' na stranicu i koristiti the storage API da preuzme vrednost message
iz skladišta ekstenzije.
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)
})

Poruka se šalje na extension pages od strane content scripta kada se ovaj dugme klikne, kroz korišćenje runtime.sendMessage() API. To je zbog ograničenja content scripta u direktnom pristupu API-ima, pri čemu je storage
među retkim izuzecima. Za funkcionalnosti koje prelaze ove izuzetke, poruke se šalju na extension pages sa kojima content scripts mogu da komuniciraju.
Warning
U zavisnosti od pregledača, mogućnosti content scripta se mogu blago razlikovati. Za Chromium-based browsers, lista mogućnosti je dostupna u Chrome Developers documentation, a za Firefox, MDN služi kao glavni izvor.
Takođe je vredno napomenuti da content scripts imaju mogućnost komunikacije sa background scripts, što im omogućava da izvrše akcije i proslede odgovore nazad.
Za pregled i debugovanje content scripts u Chrome-u, meni Chrome developer tools može se pristupiti iz Options > More tools > Developer tools ILI pritiskom na Ctrl + Shift + I.
Kada se developer tools prikažu, kliknite na Source tab, potom na Content Scripts tab. Ovo omogućava posmatranje pokrenutih content scripts iz različitih ekstenzija i postavljanje breakpoints-a za praćenje toka izvršavanja.
Injected content scripts
Tip
Imajte na umu da Content Scripts nisu obavezni jer je takođe moguće dinamički injektovati skripte i programatski ih injektovati u web stranice putem
tabs.executeScript
. Ovo zapravo pruža više granular controls.
Za programatsko injektovanje content scripta, ekstenzija mora imati host permissions za stranicu u koju će skripte biti injektovane. Ove dozvole mogu se obezbediti ili njihovim zahtevanjem u manifestu ekstenzije ili privremeno putem activeTab.
Primer ekstenzije zasnovane na activeTab
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
- Inject JS fajl na klik:
// 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"],
})
})
- Inject a function na klik:
//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,
})
})
Primer sa dozvolama za skriptovanje
// 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" })
Da biste uključili ili isključili više URL-ova, moguće je koristiti include_globs
i exclude_globs
.
Content Scripts run_at
Polje run_at
kontroliše kada se JavaScript fajlovi ubacuju u web stranicu. Poželjna i podrazumevana vrednost je "document_idle"
.
Moguće vrednosti su:
document_idle
: Kad god je mogućedocument_start
: Nakon svih fajlova izcss
, ali pre nego što se ostali delovi DOM-a konstruišu ili pre nego što se pokrene bilo koji drugi skript.document_end
: Odmah nakon što je DOM kompletan, ali pre nego što podresursi poput slika i frejmova budu učitani.
Putem manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.example.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
Putem service-worker.js
chrome.scripting.registerContentScripts([
{
id: "test",
matches: ["https://*.example.com/*"],
runAt: "document_idle",
js: ["contentScript.js"],
},
])
background
Poruke koje šalju content scripts primaju se na background page, koja ima centralnu ulogu u koordinaciji komponenti ekstenzije. Važno je da background page opstaje tokom celog životnog veka ekstenzije, radi diskretno bez direktne interakcije sa korisnikom. Ona poseduje sopstveni Document Object Model (DOM), što omogućava kompleksne interakcije i upravljanje stanjem.
Key Points:
- Background Page Role: Deluje kao centralni nervni centar ekstenzije, obezbeđujući komunikaciju i koordinaciju između različitih delova ekstenzije.
- Persistence: To je stalna komponenta, nevidljiva korisniku ali ključna za funkcionalnost ekstenzije.
- Automatic Generation: Ako nije eksplicitno definisana, browser će automatski kreirati background page. Ova automatski generisana stranica uključiće sve background skripte navedene u manifestu ekstenzije, osiguravajući neometan rad background zadataka ekstenzije.
Tip
Pogodnost koju browser pruža automatskim generisanjem background page (kada nije eksplicitno deklarisana) osigurava da su sve neophodne background skripte integrisane i operativne, pojednostavljujući proces podešavanja ekstenzije.
Example background script:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request == "explain") {
chrome.tabs.create({ url: "https://example.net/explanation" })
}
})
It uses runtime.onMessage API to listen to messages. When an "explain"
message is received, it uses tabs API to open a page in a new tab.
Koristi runtime.onMessage API za osluškivanje poruka. Kada se primi poruka "explain"
, koristi tabs API da otvori stranicu u novoj kartici.
To debug the background script you could go to the extension details and inspect the service worker, this will open the developer tools with the background script:
Da biste otklonili greške u background skripti, možete otići na extension details and inspect the service worker, što će otvoriti developer tools sa background skriptom:
Options pages and other
Options pages and other
Browser extensions can contain various kinds of pages:
Browser ekstenzije mogu sadržati različite vrste stranica:
-
Action pages are displayed in a drop-down when the extension icon is clicked.
-
Pages that the extension will load in a new tab.
-
Option Pages: This page displays on top of the extension when clicked. In the previous manifest In my case I was able to access this page in
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca
or clicking: -
Action pages se prikazuju u obliku drop-down menija kada se klikne ikona ekstenzije.
-
Stranice koje ekstenzija učitava u novoj kartici.
-
Option Pages: Ova stranica se prikazuje iznad ekstenzije kada se klikne. U mom slučaju, u starom manifestu uspeo sam da pristupim ovoj stranici preko
chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca
ili klikom:

Note that these pages aren't persistent like background pages as they load dynamically content on necessity. Despite this, they share certain capabilities with the background page:
Imajte na umu da ove stranice nisu persistentne kao background pages — učitavaju se dinamički po potrebi. Uprkos tome, dele određene mogućnosti sa background page:
-
Communication with Content Scripts: Similar to the background page, these pages can receive messages from content scripts, facilitating interaction within the extension.
-
Access to Extension-Specific APIs: These pages enjoy comprehensive access to extension-specific APIs, subject to the permissions defined for the extension.
-
Komunikacija sa Content Scripts: Slično background page, ove stranice mogu primati poruke od content scripts, olakšavajući interakciju unutar ekstenzije.
-
Pristup extension-specific APIs: Ove stranice imaju širi pristup extension-specific APIs, u okviru permisija definisanih za ekstenziju.
permissions
& host_permissions
permissions
& host_permissions
permissions
and host_permissions
are entries from the manifest.json
that will indicate which permissions the browser extensions has (storage, location...) and in which web pages.
Pošto su browser ekstenzije često vrlo privilegovane, maliciozna ekstenzija ili kompromitovana ekstenzija može napadaču omogućiti različite načine za krađu osetljivih informacija i nadgledanje korisnika.
Proverite kako ova podešavanja funkcionišu i kako se mogu zloupotrebiti u:
permissions
i host_permissions
su unosi u manifest.json
koji ukazuju koje permisije ekstenzija zahteva (storage, location...) i na kojim web stranicama.
Pošto su browser ekstenzije često veoma privilegovane, maliciozna ili kompromitovana ekstenzija može napadaču omogućiti različite načine za krađu osetljivih informacija i nadgledanje korisnika.
Check how these settings work and how they could get abused in:
Pogledajte kako ova podešavanja funkcionišu i kako se mogu zloupotrebiti u:
{{#ref}} browext-permissions-and-host_permissions.md {{#endref}}
content_security_policy
content_security_policy
A content security policy can be declared also inside the manifest.json
. If there is one defined, it could be vulnerable.
U manifest.json
se može deklarisati i content security policy. Ako je definisana, ona može biti ranjiva.
The default setting for browser extension pages is rather restrictive:
Podrazumevana podešavanja za stranice ekstenzije su prilično restriktivna:
script-src 'self'; object-src 'self';
Za više informacija o CSP i potencijalnim bypass-ima pogledajte:
{{#ref}} ../content-security-policy-csp-bypass/ {{#endref}}
web_accessible_resources
Da bi web stranica mogla da pristupi stranici Browser Extension-a, na primer .html
stranici, ta stranica mora biti navedena u polju web_accessible_resources
u manifest.json
.\
Na primer:
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
Ove stranice su dostupne na URL-ovima poput:
chrome-extension://<extension-id>/message.html
In public extensions the extension-id is accesible:

Although, if the manifest.json
parameter use_dynamic_url
is used, this id can be dynamic.
Tip
Imajte na umu da čak i ako je neka stranica ovde pomenuta, ona može biti zaštićena protiv ClickJacking zahvaljujući Content Security Policy. Zato je potrebno proveriti i to (frame-ancestors section) pre nego što potvrdite da je ClickJacking napad moguć.
Being allowed to access these pages make these pages potentially vulnerable ClickJacking:
{{#ref}} browext-clickjacking.md {{#endref}}
Tip
Dozvoljavanje da se ove stranice učitavaju samo od strane ekstenzije, a ne sa nasumičnih URL-ova, može sprečiti ClickJacking napade.
Caution
Imajte na umu da stranice iz
web_accessible_resources
i druge stranice ekstenzije takođe mogu da kontaktiraju background scripts. Dakle, ako je jedna od ovih stranica ranjiva na XSS, to može otvoriti veću ranjivost.Štaviše, napomena da možete otvoriti samo stranice navedene u
web_accessible_resources
unutar iframe-ova, ali iz novog taba je moguće pristupiti bilo kojoj stranici u ekstenziji znajući extension ID. Dakle, ako se pronađe XSS koji zloupotrebljava iste parametre, mogao bi se iskoristiti čak i ako stranica nije konfigurirana uweb_accessible_resources
.
externally_connectable
A per the docs, The "externally_connectable"
manifest property declares which extensions and web pages can connect to your extension via runtime.connect and runtime.sendMessage.
- If the
externally_connectable
key is not declared in your extension's manifest or it's declared as"ids": ["*"]
, all extensions can connect, but no web pages can connect. - If specific IDs are specified, like in
"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
, only those applications can connect. - If matches are specified, those web apps will be able to connect:
"matches": [
"https://*.google.com/*",
"*://*.chromium.org/*",
- If it's specified as empty:
"externally_connectable": {}
, nijedan app ili web neće moći da se poveže.
Što je manje extensions i URLs ovde navedeno, to će površina napada biti manja.
Caution
Ako je na strani naveden web page vulnerable to XSS or takeover u
externally_connectable
, napadač će moći da send messages directly to the background script, potpuno zaobišavši Content Script i njegov CSP.Dakle, ovo je veoma jak bypass.
Štaviše, ako klijent instalira zlonamerni extension, čak i ako mu nije dozvoljeno da komunicira sa ranjivim extension-om, mogao bi da injektuje XSS data in an allowed web page ili da zloupotrebi
WebRequest
iliDeclarativeNetRequest
API-je da manipuliše request-ovima na ciljanom domenu menjajući zahtev stranice za JavaScript file. (Imajte na umu da CSP na ciljanoj stranici može da spreči ove napade). Ova ideja dolazi from this writeup.
Communication summary
Extension <--> WebApp
Za komunikaciju između content script-a i web stranice obično se koriste post messages. Zato ćete u web aplikaciji obično naći pozive funkciji window.postMessage
i u content script-u listenere kao window.addEventListener
. Ipak, treba napomenuti da extension takođe može communicate with the web application sending a Post Message (i samim tim web treba da to očekuje) ili jednostavno naterati web da učita novi script.
Inside the extension
Obično se funkcija chrome.runtime.sendMessage
koristi za slanje poruke unutar extension-a (obično obrađuje background
script) i da bi se primila i obradila, deklariše se listener pozivom chrome.runtime.onMessage.addListener
.
Takođe je moguće koristiti chrome.runtime.connect()
da se uspostavi persistent connection umesto slanja pojedinačnih poruka; moguće ga je koristiti za send i receive messages kao u sledećem primeru:
chrome.runtime.connect()
example
```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>
Takođe je moguće slati poruke iz background skripta do content skripta koji se nalazi u određenom tab-u pozivanjem **`chrome.tabs.sendMessage`**, gde ćete morati da navedete **ID of the tab** kome se poruka šalje.
### Iz dozvoljenih `externally_connectable` ka ekstenziji
**Web aplikacije i eksterni browser extensions koji su dozvoljeni** u konfiguraciji `externally_connectable` mogu slati zahteve koristeći :
```javascript
chrome.runtime.sendMessage(extensionId, ...
Gde je potrebno pomenuti extension ID.
Native Messaging
Moguće je da background scripts komuniciraju sa binaries u sistemu, što može dovesti do kritičnih ranjivosti kao što su RCEs ako ova komunikacija nije pravilno osigurana. Više o tome kasnije.
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
Web ↔︎ Content Script komunikacija
Okruženja u kojima rade content scripts i u kojima postoje host stranice su odvojena jedno od drugog, obezbeđujući izolaciju. Uprkos toj izolaciji, oba imaju mogućnost interakcije sa Document Object Model (DOM) stranice, koji je zajednički resurs. Da bi host stranica ostvarila komunikaciju sa content script, ili indirektno sa ekstenzijom preko content script, potrebno je koristiti DOM koji je dostupan obema stranama kao kanal komunikacije.
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
)
Sigurna Post Message komunikacija treba da proveri autentičnost primljene poruke; to se može uraditi proverom:
event.isTrusted
: Ovo je True samo ako je događaj pokrenut akcijom korisnika- content script može očekivati poruku samo ako korisnik izvrši neku radnju
- origin domain: može očekivati poruku samo sa dozvoljene liste domena.
- Ako se koristi regex, budite veoma oprezni
- Source:
received_message.source !== window
možete koristiti da proverite da li je poruka iz istog prozora u kome Content Script osluškuje.
Prethodne provere, čak i ako su izvršene, mogu biti ranjive, zato proverite na sledećoj stranici potencijalne Post Message bypasses:
{{#ref}} ../postmessage-vulnerabilities/ {{#endref}}
Iframe
Još jedan mogući način komunikacije može biti preko Iframe URLs, primer možete naći u:
{{#ref}} browext-xss-example.md {{#endref}}
DOM
Ovo nije "tačno" način komunikacije, ali web i content script će imati pristup web DOM-u. Dakle, ako content script čita neke informacije iz njega, verujući web DOM-u, web može izmeniti ove podatke (jer webu se ne treba verovati, ili zato što je web ranjiv na XSS) i kompromitovati Content Script.
Takođe možete naći primer DOM based XSS to compromise a browser extension u:
{{#ref}} browext-xss-example.md {{#endref}}
Komunikacija Content Script ↔︎ Background Script
Content Script može koristiti funkcije runtime.sendMessage() ili tabs.sendMessage() da pošalje one-time JSON-serializable poruku.
Za rukovanje response, koristite vraćeni Promise. Ipak, radi kompatibilnosti unazad, i dalje možete proslediti callback kao poslednji argument.
Slanje zahteva iz content script izgleda ovako:
;(async () => {
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
// do something with response here, not outside the function
console.log(response)
})()
Slanje zahteva iz extension (obično iz background script). Primer kako poslati poruku content script-u u izabranom tab-u:
// 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)
})()
Na strani koja prima, treba da postavite runtime.onMessage event listener da obradite poruku. Ovo izgleda isto u content scriptu ili na extension page-u.
// 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" })
})
U prikazanom primeru, sendResponse()
je izvršen sinhrono. Da biste izmenili onMessage
event handler da asinhrono izvršava sendResponse()
, neophodno je uključiti return true;
.
Bitno je napomenuti da u scenarijima gde više stranica prima onMessage
događaje, prva stranica koja izvrši sendResponse()
za određeni događaj biće jedina koja može efikasno dostaviti odgovor. Svaki naknadni odgovor na isti događaj neće biti uzet u obzir.
Prilikom izrade novih ekstenzija, treba davati prednost promises umesto callbacks. Što se tiče upotrebe callbacks, funkcija sendResponse()
važi samo ako se izvrši direktno u sinhronom kontekstu, ili ako event handler označi asinhronu operaciju vraćanjem true
. Ako nijedan od handlera ne vrati true
ili ako je funkcija sendResponse()
uklonjena iz memorije (garbage-collected), callback povezan sa sendMessage()
biće po defaultu pozvan.
Native Messaging
Ekstenzije pregledača takođe omogućavaju komunikaciju sa binaries in the system via stdin. Aplikacija mora instalirati json koji to navodi u json fajlu poput:
{
"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/"]
}
Gde je name
string koji se prosleđuje funkcijama runtime.connectNative()
ili runtime.sendNativeMessage()
da bi se komuniciralo sa aplikacijom iz pozadinskih skripti ekstenzije preglednika. path
je putanja do binarnog fajla, postoji samo 1 važeći type
koji je stdio (koristi stdin i stdout), a allowed_origins
označavaju ekstenzije koje mogu da mu pristupe (i ne mogu imati wildcard).
Chrome/Chromium će tražiti ovaj json u nekim Windows registry-ima i nekim putanjama na macOS i Linuxu (više informacija u docs).
Tip
Ekstenzija preglednika takođe mora imati deklarisanu
nativeMessaing
permission da bi mogla da koristi ovu komunikaciju.
Ovako izgleda kod pozadinske skripte koja šalje poruke native aplikaciji:
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
function (response) {
console.log("Received " + response)
}
)
In ovom blog postu, predložen je ranjiv obrazac koji zloupotrebljava native messages:
- Ekstenzija pregledača ima wildcard pattern za content script.
- Content script prosleđuje
postMessage
poruke background skriptu koristećisendMessage
. - Background skripta prosleđuje poruku native aplikaciji koristeći
sendNativeMessage
. - Native aplikacija nebezbedno obrađuje poruku, što može dovesti do izvršenja koda.
I u okviru toga objašnjen je primer kako se sa bilo koje stranice može ostvariti RCE zloupotrebom ekstenzije pregledača.
Sensitive Information in Memory/Code/Clipboard
Ako ekstenzija pregledača čuva osetljive informacije u svojoj memoriji, one mogu biti izvučene (posebno na Windows mašinama) i pretražene u potrazi za tim podacima.
Stoga memorija ekstenzije pregledača ne treba da se smatra sigurnom, i osetljive informacije kao što su kredencijali ili mnemoničke fraze ne bi trebalo da se čuvaju.
Naravno, nemojte staviti osetljive informacije u kod, jer će one biti javno dostupne.
Da biste dobili memory dump iz browsera možete dumpovati memoriju procesa ili otići u podešavanja ekstenzije pregledača, kliknuti na Inspect pop-up
-> u Memory
sekciji -> Take a snaphost
i pritisnuti CTRL+F
da pretražite snapshot za osetljive informacije.
Pored toga, izrazito osetljive informacije kao mnemonik ključevi ili lozinke ne bi trebalo dozvoliti da se kopiraju u clipboard (ili bar ukloniti iz clipboarda nakon nekoliko sekundi), jer će tada procesi koji nadgledaju clipboard moći da ih dobiju.
Loading an Extension in the Browser
- Preuzmite ekstenziju pregledača i raspakujte
- Idite na
chrome://extensions/
i omogućiteDeveloper Mode
- Kliknite na dugme
Load unpacked
U Firefox odete na about:debugging#/runtime/this-firefox
i kliknete na dugme Load Temporary Add-on
.
Getting the source code from the store
Izvorni kod Chrome ekstenzije može se dobiti na više načina. Ispod su detaljna objašnjenja i uputstva za svaku opciju.
Download Extension as ZIP via Command Line
Izvorni kod Chrome ekstenzije može se preuzeti kao ZIP fajl korišćenjem komandne linije. To podrazumeva korišćenje curl
da se preuzme ZIP fajl sa specifičnog URL-a i zatim izdvoje sadržaji ZIP fajla u direktorijum. Evo koraka:
- Zamenite
"extension_id"
stvarnim ID-jem ekstenzije. - Pokrenite sledeće komande:
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"
Koristite CRX Viewer veb-sajt
Koristite CRX Viewer ekstenziju
Još jedan zgodan metod je korišćenje Chrome Extension Source Viewer, koji je projekat otvorenog koda. Može se instalirati iz Chrome Web Store. Izvorni kod viewer-a je dostupan u njegovom GitHub repository.
Pregled izvora lokalno instalirane ekstenzije
Chrome ekstenzije instalirane lokalno takođe se mogu pregledati. Evo kako:
- Pristupite lokalnom Chrome profilu tako što ćete otići na
chrome://version/
i pronaći polje "Profile Path". - Idite u podfolder
Extensions/
unutar direktorijuma profila. - Ovaj folder sadrži sve instalirane ekstenzije, obično sa izvornim kodom u čitljivom formatu.
Da biste identifikovali ekstenzije, možete mapirati njihove ID-e na nazive:
- Omogućite Developer Mode na stranici
about:extensions
da biste videli ID-e svake ekstenzije. - U folderu svake ekstenzije, fajl
manifest.json
sadrži čitljivo poljename
, koje pomaže pri identifikaciji ekstenzije.
Koristite arhiver ili alat za raspakivanje
Idite na Chrome Web Store i preuzmite ekstenziju. Fajl će imati .crx
ekstenziju. Promenite ekstenziju fajla iz .crx
u .zip
. Koristite bilo koji arhiver (npr. WinRAR, 7-Zip, itd.) da izdvojite sadržaj ZIP fajla.
Koristite Developer Mode u Chrome-u
Otvorite Chrome i idite na chrome://extensions/
. Uključite "Developer mode" u gornjem desnom uglu. Kliknite na "Load unpacked extension...". Navigirajte do direktorijuma vaše ekstenzije. Ovo ne preuzima izvorni kod, ali je korisno za pregled i modifikaciju koda već preuzete ili razvijene ekstenzije.
Dataset manifesta Chrome ekstenzija
Da biste pokušali uočiti ranjive browser ekstenzije možete koristiti https://github.com/palant/chrome-extension-manifests-dataset i proveriti njihove manifest fajlove za potencijalne znake ranjivosti. Na primer, da biste proverili ekstenzije sa više od 25000 korisnika, content_scripts
i permisijom 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)
Prikrivena tehnika za ubacivanje backdoora u Chromium direktnim izmenama per-user Preferences i falsifikovanjem validnih HMACs, zbog čega pregledač prihvati i aktivira proizvoljan unpacked extension bez promptova ili flagova.
{{#ref}} forced-extension-load-preferences-mac-forgery-windows.md {{#endref}}
Kontrolna lista sigurnosnog audita
Iako Browser Extensions imaju limited attack surface, neke od njih mogu sadržati vulnerabilities ili potential hardening improvements. Sledeće su najčešće:
- Limit as much as possible requested
permissions
- Limit as much as possible
host_permissions
- Use a strong
content_security_policy
- Limit as much as possible the
externally_connectable
, if none is needed and possible, do not leave it by default, specify{}
- If URL vulnerable to XSS or to takeover is mentioned here, an attacker will be able to send messages to the background scripts directly. Very powerful bypass.
- Limit as much as possible the
web_accessible_resources
, even empty if possible. - If
web_accessible_resources
is not none, check for ClickJacking - If any communication occurs from the extension to the web page, check for XSS vulnerabilities caused in the communication.
- If Post Messages are used, check for Post Message vulnerabilities.
- If the Content Script access DOM details, check that they aren't introducing a XSS if they get modified by the web
- Make a special emphasis if this communication is also involved in the Content Script -> Background script communication
- If the background script is communicating via native messaging check the communication is secure and sanitized
- Sensitive information shouldn't be stored inside the Browser Extension code
- Sensitive information shouldn't be stored inside the Browser Extension memory
- Sensitive information shouldn't be stored inside the file system unprotected
Browser Extension Risks
- The app https://crxaminer.tech/ analyzes some data like the permissions browser extension requests to give a risk level of using the browser extension.
Alati
Tarnish
- Pulls any Chrome extension from a provided Chrome webstore link.
- manifest.json viewer: simply displays a JSON-prettified version of the extension’s manifest.
- Fingerprint Analysis: Detection of web_accessible_resources and automatic generation of Chrome extension fingerprinting JavaScript.
- Potential Clickjacking Analysis: Detection of extension HTML pages with the web_accessible_resources directive set. These are potentially vulnerable to clickjacking depending on the purpose of the pages.
- Permission Warning(s) viewer: which shows a list of all the Chrome permission prompt warnings which will be displayed upon a user attempting to install the extension.
- Dangerous Function(s): shows the location of dangerous functions which could potentially be exploited by an attacker (e.g. functions such as innerHTML, chrome.tabs.executeScript).
- Entry Point(s): shows where the extension takes in user/external input. This is useful for understanding an extension’s surface area and looking for potential points to send maliciously-crafted data to the extension.
- Both the Dangerous Function(s) and Entry Point(s) scanners have the following for their generated alerts:
- Relevant code snippet and line that caused the alert.
- Description of the issue.
- A “View File” button to view the full source file containing the code.
- The path of the alerted file.
- The full Chrome extension URI of the alerted file.
- The type of file it is, such as a Background Page script, Content Script, Browser Action, etc.
- If the vulnerable line is in a JavaScript file, the paths of all of the pages where it is included as well as these page’s type, and web_accessible_resource status.
- Content Security Policy (CSP) analyzer and bypass checker: This will point out weaknesses in your extension’s CSP and will also illuminate any potential ways to bypass your CSP due to whitelisted CDNs, etc.
- Known Vulnerable Libraries: This uses Retire.js to check for any usage of known-vulnerable JavaScript libraries.
- Download extension and formatted versions.
- Download the original extension.
- Download a beautified version of the extension (auto prettified HTML and JavaScript).
- Automatic caching of scan results, running an extension scan will take a good amount of time the first time you run it. However the second time, assuming the extension hasn’t been updated, will be almost instant due to the results being cached.
- Linkable Report URLs, easily link someone else to an extension report generated by tarnish.
Neto
Project Neto is a Python 3 package conceived to analyse and unravel hidden features of browser plugins and extensions for well-known browsers such as Firefox and Chrome. It automates the process of unzipping the packaged files to extract these features from relevant resources in a extension like manifest.json
, localization folders or Javascript and HTML source files.
Reference
- 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
{{#include ../../banners/hacktricks-training.md}}