mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
722 lines
40 KiB
Markdown
722 lines
40 KiB
Markdown
# Blaaieruitbreiding Pentesting Metodologie
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|
||
|
||
## Basiese Inligting
|
||
|
||
Blaaieruitbreidings is in JavaScript geskryf en word deur die blaaier in die agtergrond gelaai. Dit het sy eie [DOM](https://www.w3schools.com/js/js_htmldom.asp) maar kan met ander sites se DOMs interaksie hê. Dit beteken dat dit die vertroulikheid, integriteit en beskikbaarheid (CIA) van ander sites kan kompromitteer.
|
||
|
||
## Hoofkomponente
|
||
|
||
Extension layouts lyk die beste wanneer dit gevisualiseer word en bestaan uit drie komponente. Kom ons kyk na elke komponent in diepte.
|
||
|
||
<figure><img src="../../images/image (16) (1) (1).png" alt=""><figcaption><p><a href="http://webblaze.cs.berkeley.edu/papers/Extensions.pdf">http://webblaze.cs.berkeley.edu/papers/Extensions.pdf</a></p></figcaption></figure>
|
||
|
||
### **Content Scripts**
|
||
|
||
Each content script het direkte toegang tot die DOM van 'n **single web page** en is daarmee blootgestel aan **potentially malicious input**. Die content script bevat egter geen permissies behalwe die vermoë om boodskappe na die extension core te stuur nie.
|
||
|
||
### **Extension Core**
|
||
|
||
Die extension core bevat die meeste van die uitbreiding se voorregte/toegang, maar die extension core kan slegs met webinhoud kommunikeer via [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) en content scripts. Ook het die extension core nie direkte toegang tot die gasheermasjien nie.
|
||
|
||
### **Native Binary**
|
||
|
||
Die uitbreiding laat 'n native binary toe wat toegang tot die gasheermasjien met die gebruiker se volle voorregte kan hê. Die native binary kommunikeer met die extension core deur die standaard Netscape Plugin Application Programming Interface ([NPAPI](https://en.wikipedia.org/wiki/NPAPI)) wat deur Flash en ander browser plug-ins gebruik word.
|
||
|
||
### Grense
|
||
|
||
> [!CAUTION]
|
||
> Om die gebruiker se volle voorregte te verkry, moet 'n aanvaller die uitbreiding oortuig om malicious input van die content script na die extension core en van die extension core na die native binary deur te gee.
|
||
|
||
Elke komponent van die uitbreiding is van mekaar geskei deur **sterk beskermende grense**. Elke komponent loop in 'n **afsonderlike operating system process**. Content scripts en extension cores loop in **sandbox processes** wat nie beskikbaar is vir die meeste operating system-dienste nie.
|
||
|
||
Verder is content scripts van hul geassosieerde webbladsye geskei deur **in 'n aparte JavaScript heap te loop**. Die content script en webblad het **access to the same underlying DOM**, maar die twee **never exchange JavaScript pointers**, wat die leaking van JavaScript-funksionaliteit voorkom.
|
||
|
||
## **`manifest.json`**
|
||
|
||
'n Chrome extension is net 'n ZIP-lêergids met 'n [.crx file extension](https://www.lifewire.com/crx-file-2620391). Die kern van die uitbreiding is die **`manifest.json`** lêer in die wortel van die gids, wat layout, permissies en ander konfigurasie-opsies spesifiseer.
|
||
|
||
Voorbeeld:
|
||
```json
|
||
{
|
||
"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-skripte word **gelaai** wanneer die gebruiker **na 'n ooreenstemmende bladsy navigeer**, in ons geval enige bladsy wat ooreenstem met die **`https://example.com/*`** uitdrukking en nie ooreenstem met die **`*://*/*/business*`** regex nie. Hulle word uitgevoer **soos die bladsy se eie skripte** en het arbitrêre toegang tot die bladsy se [Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model).
|
||
```json
|
||
"content_scripts": [
|
||
{
|
||
"js": [
|
||
"script.js"
|
||
],
|
||
"matches": [
|
||
"https://example.com/*",
|
||
"https://www.example.com/*"
|
||
],
|
||
"exclude_matches": ["*://*/*business*"],
|
||
}
|
||
],
|
||
```
|
||
Om meer URLs in te sluit of uit te sluit is dit ook moontlik om **`include_globs`** en **`exclude_globs`** te gebruik.
|
||
|
||
Dit is 'n voorbeeld content script wat 'n explain-knoppie aan die bladsy sal voeg wanneer [the storage API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage) gebruik word om die `message`-waarde uit die extension’s storage te haal.
|
||
```js
|
||
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)
|
||
})
|
||
```
|
||
<figure><img src="../../images/image (23).png" alt=""><figcaption></figcaption></figure>
|
||
|
||
Wanneer hierdie knoppie geklik word, stuur die content script 'n boodskap na die extension pages deur gebruik te maak van die [**runtime.sendMessage() API**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage). Dit is omdat die content script beperkte direkte toegang tot APIs het, met `storage` as een van die paar uitsonderings. Vir funksionaliteit buite hierdie uitsonderings word boodskappe na extension pages gestuur waarmee content scripts kan kommunikeer.
|
||
|
||
> [!WARNING]
|
||
> Afhangend van die blaaier kan die vermoëns van die content script effens verskil. Vir Chromium-gebaseerde browsers is die lys van vermoëns beskikbaar in die [Chrome Developers documentation](https://developer.chrome.com/docs/extensions/mv3/content_scripts/#capabilities), en vir Firefox dien die [MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis) as die primêre bron.\
|
||
> Dit is ook vermeldenswaardig dat content scripts met background scripts kan kommunikeer, wat dit toelaat om aksies uit te voer en antwoorde terug te stuur.
|
||
|
||
Om content scripts in Chrome te sien en te debug, kan jy die Chrome developer tools-menu oopmaak via Options > More tools > Developer tools OF deur Ctrl + Shift + I te druk.
|
||
|
||
Sodra die developer tools gewys word, klik op die **Source tab**, gevolg deur die **Content Scripts** tab. Dit maak dit moontlik om lopende content scripts van verskeie extensions te besigtig en breakpoints te stel om die uitvoeringsvloei te volg.
|
||
|
||
### Ingespuitte content scripts
|
||
|
||
> [!TIP]
|
||
> Let wel dat **Content Scripts nie verpligtend is nie**, aangesien dit ook moontlik is om skripte **dinamies** te inspuit en om hulle **programmaties** in webbladsye in te spuit via **`tabs.executeScript`**. Dit bied eintlik meer **fyn beheer**.
|
||
|
||
Vir die programmatiese inspuiting van 'n content script, moet die extension host permissions hê vir die bladsy waarin die skripte ingespuit gaan word. Hierdie permissies kan verkry word deur hulle binne die manifest van die extension **aan te vra** of tydelik via [**activeTab**](https://developer.chrome.com/docs/extensions/reference/manifest/activeTab).
|
||
|
||
#### Voorbeeld van activeTab-gebaseerde extension
|
||
```json:manifest.json
|
||
{
|
||
"name": "My extension",
|
||
...
|
||
"permissions": [
|
||
"activeTab",
|
||
"scripting"
|
||
],
|
||
"background": {
|
||
"service_worker": "background.js"
|
||
},
|
||
"action": {
|
||
"default_title": "Action Button"
|
||
}
|
||
}
|
||
```
|
||
- **Inject 'n JS-lêer wanneer daar op geklik word:**
|
||
```javascript
|
||
// 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"],
|
||
})
|
||
})
|
||
```
|
||
- **Injekteer 'n function** met 'n klik:
|
||
```javascript
|
||
//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,
|
||
})
|
||
})
|
||
```
|
||
#### Voorbeeld met scripting-toestemmings
|
||
```javascript
|
||
// 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" })
|
||
```
|
||
Om meer URL's in te sluit of uit te sluit, is dit ook moontlik om **`include_globs`** en **`exclude_globs`** te gebruik.
|
||
|
||
### Content-skripte `run_at`
|
||
|
||
Die `run_at` veld beheer **wanneer JavaScript-lêers in die webblad ingesit word**. Die voorkeur- en standaardwaarde is `"document_idle"`.
|
||
|
||
Die moontlike waardes is:
|
||
|
||
- **`document_idle`**: Wanneer moontlik
|
||
- **`document_start`**: Na enige lêers van `css`, maar voordat enige ander DOM opgebou is of enige ander script uitgevoer word.
|
||
- **`document_end`**: Onmiddellik nadat die DOM voltooi is, maar voordat subbronne soos beelde en rame gelaai is.
|
||
|
||
#### Deur `manifest.json`
|
||
```json
|
||
{
|
||
"name": "My extension",
|
||
...
|
||
"content_scripts": [
|
||
{
|
||
"matches": ["https://*.example.com/*"],
|
||
"run_at": "document_idle",
|
||
"js": ["contentScript.js"]
|
||
}
|
||
],
|
||
...
|
||
}
|
||
|
||
```
|
||
Deur **`service-worker.js`**
|
||
```javascript
|
||
chrome.scripting.registerContentScripts([
|
||
{
|
||
id: "test",
|
||
matches: ["https://*.example.com/*"],
|
||
runAt: "document_idle",
|
||
js: ["contentScript.js"],
|
||
},
|
||
])
|
||
```
|
||
### `background`
|
||
|
||
Boodskappe wat deur content scripts gestuur word, word ontvang deur die **agtergrondblad**, wat 'n sentrale rol speel in die koördinering van die uitbreiding se komponente. Belangrik is dat die agtergrondblad oor die lewensduur van die uitbreiding voortbestaan en stilweg werk sonder direkte gebruikersinteraksie. Dit het sy eie Document Object Model (DOM), wat ingewikkelde interaksies en toestandbestuur moontlik maak.
|
||
|
||
**Belangrike Punte**:
|
||
|
||
- **Rol van die Agtergrondblad:** Dien as die senuweesentrum van die uitbreiding en verseker kommunikasie en koördinering tussen verskeie dele van die uitbreiding.
|
||
- **Persistensie:** Dit is 'n steeds-aanwesige entiteit, onsigbaar vir die gebruiker maar integraal tot die uitbreiding se funksionaliteit.
|
||
- **Outomatiese Generering:** As dit nie eksplisiet gedefinieer is nie, sal die browser outomaties 'n agtergrondblad skep. Hierdie outo-gegenereerde blad sal al die agtergrondskripte insluit wat in die uitbreiding se manifest gespesifiseer is, wat die naatlose werking van die uitbreiding se agtergrondtake verseker.
|
||
|
||
> [!TIP]
|
||
> Die gerief wat die browser bied deur outomaties 'n agtergrondblad te genereer (wanneer dit nie eksplisiet verklaar is nie) verseker dat alle nodige agtergrondskripte geïntegreer en operasioneel is, wat die opstelproses van die uitbreiding vereenvoudig.
|
||
|
||
Example background script:
|
||
```js
|
||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||
if (request == "explain") {
|
||
chrome.tabs.create({ url: "https://example.net/explanation" })
|
||
}
|
||
})
|
||
```
|
||
Dit gebruik [runtime.onMessage API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage) om na boodskappe te luister. Wanneer die `"explain"` boodskap ontvang word, gebruik dit [tabs API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs) om 'n bladsy in 'n nuwe tabblad oop te maak.
|
||
|
||
To debug die background script kan jy na die **extension details and inspect the service worker,** gaan; dit sal die developer tools met die background script oopmaak:
|
||
|
||
<figure><img src="https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/browser-extension-pentesting-methodology/broken-reference" alt=""><figcaption></figcaption></figure>
|
||
|
||
### Options pages and other
|
||
|
||
Browser extensions kan verskeie tipes bladsye bevat:
|
||
|
||
- **Action pages** word vertoon in 'n **drop-down wanneer die extension ico**n geklik word.
|
||
- Bladsye wat die extension sal **load in a new tab**.
|
||
- **Option Pages**: Hierdie bladsy verskyn bo-op die extension wanneer dit geklik word. In die vorige manifest kon ek hierdie bladsy in my geval toegang kry by `chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca` of deur te klik:
|
||
|
||
<figure><img src="../../images/image (24).png" alt="" width="375"><figcaption></figcaption></figure>
|
||
|
||
Let wel dat hierdie bladsye nie persistent is soos background pages nie, aangesien hulle dinamies content laai wanneer nodig. Ten spyte hiervan deel hulle sekere vermoëns met die background page:
|
||
|
||
- **Communication with Content Scripts:** Soortgelyk aan die background page, kan hierdie bladsye boodskappe van content scripts ontvang, wat interaksie binne die extension vergemaklik.
|
||
- **Access to Extension-Specific APIs:** Hierdie bladsye het uitgebreide toegang tot extension-specific APIs, onderhewig aan die permissions wat vir die extension gedefinieer is.
|
||
|
||
### `permissions` & `host_permissions`
|
||
|
||
**`permissions`** en **`host_permissions`** is inskrywings in die `manifest.json` wat aandui **watter permissions** die browser extension het (storage, location...) en in **watter webbladsye**.
|
||
|
||
Aangesien browser extensions so **privileged** kan wees, kan 'n kwaadwillige een of een wat gekompromitteer is die aanvaller toelaat **verskeie maniere om sensitiewe inligting te steel en die gebruiker te bespioneer**.
|
||
|
||
Kyk hoe hierdie instellings werk en hoe hulle misbruik kan word in:
|
||
|
||
|
||
{{#ref}}
|
||
browext-permissions-and-host_permissions.md
|
||
{{#endref}}
|
||
|
||
### `content_security_policy`
|
||
|
||
'n **content security policy** kan ook binne die `manifest.json` gedefinieer word. Indien een gedefinieer is, kan dit **kwesbaar** wees.
|
||
|
||
Die standaardinstelling vir browser extension-bladsye is redelik beperkend:
|
||
```bash
|
||
script-src 'self'; object-src 'self';
|
||
```
|
||
Vir meer inligting oor CSP en potensiële bypasses, sien:
|
||
|
||
|
||
{{#ref}}
|
||
../content-security-policy-csp-bypass/
|
||
{{#endref}}
|
||
|
||
### `web_accessible_resources`
|
||
|
||
Sodat 'n webblad toegang tot 'n bladsy van 'n Browser Extension (byvoorbeeld 'n `.html` bladsy) kan kry, moet hierdie bladsy in die **`web_accessible_resources`** veld van die `manifest.json` genoem word.\
|
||
Byvoorbeeld:
|
||
```javascript
|
||
{
|
||
...
|
||
"web_accessible_resources": [
|
||
{
|
||
"resources": [ "images/*.png" ],
|
||
"matches": [ "https://example.com/*" ]
|
||
},
|
||
{
|
||
"resources": [ "fonts/*.woff" ],
|
||
"matches": [ "https://example.com/*" ]
|
||
}
|
||
],
|
||
...
|
||
}
|
||
```
|
||
Hierdie bladsye is beskikbaar via URL's soos:
|
||
```
|
||
chrome-extension://<extension-id>/message.html
|
||
```
|
||
In openbare uitbreidings is die **extension-id** toeganklik:
|
||
|
||
<figure><img src="../../images/image (1194).png" alt="" width="375"><figcaption></figcaption></figure>
|
||
|
||
As die `manifest.json`-parameter **`use_dynamic_url`** gebruik word, kan hierdie **id dinamies wees**.
|
||
|
||
> [!TIP]
|
||
> Let wel dat selfs al word 'n bladsy hier genoem, dit dalk **teen ClickJacking beskerm** is danksy die **Content Security Policy**. Jy moet dit dus ook nagaan (frame-ancestors section) voordat jy bevestig dat 'n ClickJacking-aanval moontlik is.
|
||
|
||
Dat toegang tot hierdie bladsye toegestaan is, maak hulle **potensieel kwesbaar vir ClickJacking**:
|
||
|
||
|
||
{{#ref}}
|
||
browext-clickjacking.md
|
||
{{#endref}}
|
||
|
||
> [!TIP]
|
||
> Deur toe te laat dat hierdie bladsye slegs deur die uitbreiding gelaai word en nie deur ewekansige URLs nie, kan ClickJacking-aanvalle voorkom word.
|
||
|
||
> [!CAUTION]
|
||
> Let wel dat die bladsye uit **`web_accessible_resources`** en ander bladsye van die uitbreiding ook in staat is om **contact te maak met background scripts**. Dus, as een van hierdie bladsye kwesbaar is vir **XSS** kan dit 'n groter kwesbaarheid oopmaak.
|
||
>
|
||
> Verder, let op dat jy slegs bladsye wat in **`web_accessible_resources`** aangedui is binne iframes kan open, maar vanaf 'n nuwe tab is dit moontlik om enige bladsy in die uitbreiding te toegang te kry as jy die extension ID ken. Daarom, as 'n XSS gevind word wat dieselfde parameters misbruik, kan dit misbruik word selfs al is die bladsy nie in **`web_accessible_resources`** gekonfigureer nie.
|
||
|
||
### `externally_connectable`
|
||
|
||
Volgens die [**docs**](https://developer.chrome.com/docs/extensions/reference/manifest/externally_connectable) verklaar die `"externally_connectable"` manifest-eienskap **watter extensions en webbladsye kan koppel** aan jou uitbreiding via [runtime.connect](https://developer.chrome.com/docs/extensions/reference/runtime#method-connect) en [runtime.sendMessage](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage).
|
||
|
||
- As die **`externally_connectable`** sleutel **nie** in jou uitbreiding se manifest verklaar is nie, of dit verklaar is as **`"ids": ["*"]`**, kan **alle extensions koppel, maar geen webbladsye kan koppel nie**.
|
||
- As **spesifieke IDs aangedui** is, soos in `"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]`, kan **slegs daardie toepassings** koppel.
|
||
- As **matches** gespesifiseer is, sal daardie web-apps in staat wees om te koppel:
|
||
```json
|
||
"matches": [
|
||
"https://*.google.com/*",
|
||
"*://*.chromium.org/*",
|
||
```
|
||
- As dit as leeg gespesifiseer is: **`"externally_connectable": {}`**, sal geen app of webwerf in staat wees om te koppel nie.
|
||
|
||
Hoe minder extensies en URL's hier aangedui word, hoe kleiner sal die aanvalsvlak wees.
|
||
|
||
> [!CAUTION]
|
||
> Indien 'n webbladsy **kwetsbaar vir XSS of takeover** in **`externally_connectable`** aangedui word, sal 'n aanvaller in staat wees om **boodskappe direk na die background script te stuur**, en die Content Script en sy CSP heeltemal te omseil.
|
||
>
|
||
> Daarom is dit 'n **baie kragtige bypass**.
|
||
>
|
||
> Verder, as die kliënt 'n rogue extension installeer, selfs al is dit nie toegelaat om met die kwesbare extension te kommunikeer nie, kan dit **XSS data in 'n toegelate web page injekteer** of **`WebRequest`** of **`DeclarativeNetRequest`** APIs misbruik om versoeke op 'n geteikende domein te manipuleer deur 'n blad se versoek na 'n **JavaScript file** te verander. (Let daarop dat CSP op die geteikende blad hierdie aanvalle kan voorkom). This idea comes [**from this writeup**](https://www.darkrelay.com/post/opera-zero-day-rce-vulnerability).
|
||
|
||
## Kommunikasie opsomming
|
||
|
||
### Extension <--> WebApp
|
||
|
||
Om te kommunikeer tussen die content script en die webblad gebruik mens gewoonlik post messages. Daarom sal jy in die web application gewoonlik oproepe na die funksie **`window.postMessage`** vind en in die content script luisteraars soos **`window.addEventListener`**. Neem egter kennis dat die extension ook kan **kommunikeer met die web application deur 'n Post Message te stuur** (en dus behoort die web dit te verwag) of eenvoudig die web laat 'n nuwe script laai.
|
||
|
||
### Binne die extension
|
||
|
||
Gewoonlik word die funksie **`chrome.runtime.sendMessage`** gebruik om 'n boodskap binne die extension te stuur (gewoonlik hanteer deur die `background` script) en om dit te ontvang en te hanteer word 'n listener gedeclareer wat **`chrome.runtime.onMessage.addListener`** aanroep.
|
||
|
||
Dit is ook moontlik om **`chrome.runtime.connect()`** te gebruik om 'n volgehoue verbinding te hê in plaas van enkel boodskappe te stuur; dit kan gebruik word om **send** en **receive** **messages** soos in die volgende voorbeeld:
|
||
|
||
<details>
|
||
|
||
<summary><code>chrome.runtime.connect()</code> voorbeeld</summary>
|
||
```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>
|
||
|
||
Dit is ook moontlik om boodskappe van 'n background script na 'n content script wat in 'n spesifieke tab geleë is, te stuur deur **`chrome.tabs.sendMessage`** aan te roep, waar jy die **ID of the tab** moet aandui om die boodskap na te stuur.
|
||
|
||
### Van toegelate `externally_connectable` na die extension
|
||
|
||
**Web apps en eksterne browser extensions wat toegelaat is** in die `externally_connectable` konfigurasie kan versoeke stuur met behulp van :
|
||
```javascript
|
||
chrome.runtime.sendMessage(extensionId, ...
|
||
```
|
||
Waar dit nodig is om die **extension ID**.
|
||
|
||
### Native Messaging
|
||
|
||
Dit is moontlik vir die background scripts om met binaries binne die stelsel te kommunikeer, wat **gevoelig kan wees vir kritieke kwesbaarhede soos RCEs** as hierdie kommunikasie nie behoorlik beveilig is nie. [More on this later](#native-messaging).
|
||
```javascript
|
||
chrome.runtime.sendNativeMessage(
|
||
"com.my_company.my_application",
|
||
{ text: "Hello" },
|
||
function (response) {
|
||
console.log("Received " + response)
|
||
}
|
||
)
|
||
```
|
||
## Web **↔︎** Content Script Kommunikasie
|
||
|
||
Die omgewings waar **content scripts** opereer en waar die gasheerbladsye bestaan, is van mekaar **geskei**, wat **isolasie** verseker. Ten spyt van hierdie isolasie het beide die vermoë om met die bladsy se **Document Object Model (DOM)**, 'n gedeelde hulpbron, te kommunikeer. Vir die gasheerbladsy om met die **content script** te kommunikeer, of indirek met die extension deur die content script, moet dit die **DOM** wat deur albei partye toeganklik is, as die kommunikasiekanaal gebruik.
|
||
|
||
### Post Messages
|
||
```javascript:content-script.js
|
||
// 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
|
||
)
|
||
```
|
||
|
||
```javascript:example.js
|
||
document.getElementById("theButton").addEventListener(
|
||
"click",
|
||
() => {
|
||
window.postMessage(
|
||
{ type: "FROM_PAGE", text: "Hello from the webpage!" },
|
||
"*"
|
||
)
|
||
},
|
||
false
|
||
)
|
||
```
|
||
'n veilige Post Message kommunikasie moet die egtheid van die ontvangde boodskap nagaan; dit kan gedoen word deur te kontroleer:
|
||
|
||
- **`event.isTrusted`**: Dit is True slegs as die gebeurtenis deur 'n gebruiker se aksie getrigger is
|
||
- Die content script mag net 'n boodskap verwag as die gebruiker 'n aksie uitvoer
|
||
- **origin domain**: kan 'n boodskap slegs van 'n allowlist van domeine verwag
|
||
- If a regex is used, be very careful
|
||
- **Source**: `received_message.source !== window` kan gebruik word om te kontroleer of die boodskap **van dieselfde venster** was waarin die Content Script luister.
|
||
|
||
Die vorige kontroles, selfs as dit gedoen is, kan kwesbaar wees, so kyk op die volgende bladsy na **potensiële Post Message bypasses**:
|
||
|
||
|
||
{{#ref}}
|
||
../postmessage-vulnerabilities/
|
||
{{#endref}}
|
||
|
||
### Iframe
|
||
|
||
Nog 'n moontlike kommunikasieweg kan deur **Iframe URLs** wees, jy kan 'n voorbeeld vind in:
|
||
|
||
|
||
{{#ref}}
|
||
browext-xss-example.md
|
||
{{#endref}}
|
||
|
||
### DOM
|
||
|
||
Dit is nie presies 'n kommunikasieweg nie, maar die **web en die content script sal toegang tot die web DOM hê**. Dus, as die **content script** sommige inligting daaruit lees en die **web DOM vertrou**, kan die web hierdie data wysig (omdat die web nie vertrou behoort te word nie, of omdat die web aan XSS kwesbaar is) en die **Content Script** kompromitteer.
|
||
|
||
Jy kan ook 'n voorbeeld vind van 'n **DOM gebaseerde XSS om 'n browser extension te kompromitteer** in:
|
||
|
||
|
||
{{#ref}}
|
||
browext-xss-example.md
|
||
{{#endref}}
|
||
|
||
## Content Script **↔︎** Background Script Communication
|
||
|
||
'n Content Script kan die funksies [**runtime.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage) **or** [**tabs.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/tabs#method-sendMessage) gebruik om 'n **eenmalige JSON-serializable** boodskap te stuur.
|
||
|
||
Om die **response** te hanteer, gebruik die teruggegewe **Promise**. Alhoewel, vir agterwaartse versoenbaarheid, kan jy steeds 'n **callback** as die laaste argument deurgee.
|
||
|
||
Die stuur van 'n versoek vanaf 'n **content script** lyk soos volg:
|
||
```javascript
|
||
;(async () => {
|
||
const response = await chrome.runtime.sendMessage({ greeting: "hello" })
|
||
// do something with response here, not outside the function
|
||
console.log(response)
|
||
})()
|
||
```
|
||
Stuur 'n versoek vanaf die **extension** (gewoonlik 'n **background script**). Voorbeeld van hoe om 'n boodskap na die content script in die selected tab te stuur:
|
||
```javascript
|
||
// 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)
|
||
})()
|
||
```
|
||
Aan die **ontvangende kant** moet jy 'n [**runtime.onMessage**](https://developer.chrome.com/docs/extensions/reference/runtime#event-onMessage) **event listener** opstel om die boodskap te hanteer. Dit lyk dieselfde vanuit 'n content script of extension page.
|
||
```javascript
|
||
// 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" })
|
||
})
|
||
```
|
||
In die uitgeligde voorbeeld is **`sendResponse()`** sinchronies uitgevoer. Om die `onMessage` event handler vir asynchrone uitvoering van `sendResponse()` te wysig, is dit noodsaaklik om `return true;` in te voeg.
|
||
|
||
'n Belangrike oorweging is dat in scenario's waar meerdere bladsye ingestel is om `onMessage` events te ontvang, **die eerste bladsy wat `sendResponse()` vir 'n spesifieke event uitvoer** die enigste een sal wees wat die response effektief kan lewer. Enige daaropvolgende responses op dieselfde event sal nie in ag geneem word nie.
|
||
|
||
Wanneer nuwe extensions geskep word, behoort die voorkeur aan promises bo callbacks te wees. Met betrekking tot die gebruik van callbacks word die `sendResponse()` funksie slegs as geldig beskou indien dit direk binne die sinchroniese konteks uitgevoer word, of indien die event handler 'n asynchrone operasie aandui deur `return true;` terug te gee. Indien geen van die handlers `return true;` teruggee nie, of indien die `sendResponse()` funksie uit geheue verwyder word (garbage-collected), sal die callback geassosieer met die `sendMessage()` funksie standaard getrigger word.
|
||
|
||
## Native Messaging
|
||
|
||
Browser extensions laat ook toe om met **binaries in die stelsel via stdin** te kommunikeer. Die toepassing moet 'n json installeer wat dit aandui, in 'n json soos:
|
||
```json
|
||
{
|
||
"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/"]
|
||
}
|
||
```
|
||
Waar die `name` die string is wat aan [`runtime.connectNative()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-connectNative) of [`runtime.sendNativeMessage()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-sendNativeMessage) deurgegee word om met die toepassing vanuit die agtergrondskripte van die blaaieruitbreiding te kommunikeer. Die `path` is die pad na die binêre, daar is net 1 geldige `type` wat stdio is (gebruik stdin en stdout) en die `allowed_origins` dui die extensies aan wat toegang daartoe het (en kan nie 'n wildcard hê nie).
|
||
|
||
Chrome/Chromium sal na hierdie json soek in sekere Windows-register en in sekere paaie op macOS en Linux (meer inligting in die [**docs**](https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging)).
|
||
|
||
> [!TIP]
|
||
> Die blaaieruitbreiding het ook die `nativeMessaing` permission nodig wat verklaar moet word om hierdie kommunikasie te kan gebruik.
|
||
|
||
So lyk dit wanneer 'n agtergrondskrip kode boodskappe na 'n native toepassing stuur:
|
||
```javascript
|
||
chrome.runtime.sendNativeMessage(
|
||
"com.my_company.my_application",
|
||
{ text: "Hello" },
|
||
function (response) {
|
||
console.log("Received " + response)
|
||
}
|
||
)
|
||
```
|
||
In [**this blog post**](https://spaceraccoon.dev/universal-code-execution-browser-extensions/), 'n kwesbare patroon wat native messages misbruik, word voorgestel:
|
||
|
||
1. Browser-uitbreiding het 'n wildcard-patroon vir content script.
|
||
2. Content script stuur `postMessage`-boodskappe na die background script met `sendMessage`.
|
||
3. Background script stuur die boodskap aan die native application met `sendNativeMessage`.
|
||
4. Die native application hanteer die boodskap op 'n gevaarlike wyse, wat lei tot code execution.
|
||
|
||
En daarin word 'n voorbeeld verduidelik van **hoe om van enige bladsy na RCE te gaan deur 'n browser-uitbreiding te misbruik**.
|
||
|
||
## Sensitiewe Inligting in Geheue/Kode/Kleefbord
|
||
|
||
As 'n blaaier-uitbreiding **sensitiewe inligting in sy geheue** stoor, kan dit **uitgelaai** (veral op Windows-masjiene) en daarna vir daardie inligting **deurgesoek** word.
|
||
|
||
Daarom moet die geheue van die blaaier-uitbreiding **nie as veilig beskou word nie** en **sensitiewe inligting** soos aanmeldbewyse of mnemoniese frases **moet nie gestoor word nie**.
|
||
|
||
Plaas natuurlik **nie sensitiewe inligting in die kode nie**, aangesien dit **publiek** sal wees.
|
||
|
||
Om geheue van die blaaier te onttrek kan jy byvoorbeeld die prosesgeheue uitgelaai, of na die instellings van die blaaier-uitbreiding gaan en op **`Inspect pop-up`** klik -> In die **`Memory`** afdeling -> **`Take a snaphost`** en **`CTRL+F`** gebruik om binne die snapshot na sensitiewe inligting te soek.
|
||
|
||
Verder moet uiters sensitiewe inligting soos mnemoniese sleutels of wagwoorde **nie in die kleefbord toegelaat word om gekopieer te word nie** (of veral dit binne 'n paar sekondes uit die kleefbord verwyder), omdat prosesse wat die kleefbord monitor dit kan kry.
|
||
|
||
## Loading an Extension in the Browser
|
||
|
||
1. **Laai** die blaaier-uitbreiding af en pak dit uit
|
||
2. Gaan na **`chrome://extensions/`** en **aktiveer** die `Developer Mode`
|
||
3. Klik die **`Load unpacked`** knoppie
|
||
|
||
In **Firefox** gaan jy na **`about:debugging#/runtime/this-firefox`** en klik op die **`Load Temporary Add-on`** knoppie.
|
||
|
||
## Getting the source code from the store
|
||
|
||
Die bronkode van 'n Chrome extension kan deur verskeie metodes verkry word. Hieronder is gedetaileerde verduidelikings en instruksies vir elke opsie.
|
||
|
||
### Download Extension as ZIP via Command Line
|
||
|
||
Die bronkode van 'n Chrome extension kan as 'n ZIP-lêer via die opdraglyn afgelaai word. Dit behels die gebruik van `curl` om die ZIP-lêer van 'n spesifieke URL te kry en daarna die inhoud daarvan na 'n gids te onttrek. Hier is die stappe:
|
||
|
||
1. Vervang `"extension_id"` met die werklike ID van die extension.
|
||
2. Voer die volgende opdragte uit:
|
||
```bash
|
||
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"
|
||
```
|
||
### Gebruik die CRX Viewer webwerf
|
||
|
||
[https://robwu.nl/crxviewer/](https://robwu.nl/crxviewer/)
|
||
|
||
### Gebruik die CRX Viewer extension
|
||
|
||
Nog 'n handige metode is om die Chrome Extension Source Viewer te gebruik, wat 'n open-source projek is. Dit kan vanaf die [Chrome Web Store](https://chrome.google.com/webstore/detail/chrome-extension-source-v/jifpbeccnghkjeaalbbjmodiffmgedin?hl=en) geïnstalleer word. Die source code van die viewer is beskikbaar in sy [GitHub repository](https://github.com/Rob--W/crxviewer).
|
||
|
||
### Bekyk die bron van lokaal geïnstalleerde extension
|
||
|
||
Chrome extensions wat lokaal geïnstalleer is, kan ook ondersoek word. So doen jy dit:
|
||
|
||
1. Gaan na jou Chrome lokale profielgids deur `chrome://version/` te besoek en die "Profile Path" veld te soek.
|
||
2. Gaan na die `Extensions/` subgids binne die profielgids.
|
||
3. Hierdie vouer bevat alle geïnstalleerde extensions, tipies met hul source code in 'n leesbare formaat.
|
||
|
||
Om extensions te identifiseer, kan jy hul IDs aan name koppel:
|
||
|
||
- Skakel Developer Mode aan op die `about:extensions` blad om die IDs van elke extension te sien.
|
||
- Binne elke extension se gids bevat die `manifest.json` lêer 'n leesbare `name` veld wat help om die extension te identifiseer.
|
||
|
||
### Gebruik 'n File Archiver of Unpacker
|
||
|
||
Gaan na die Chrome Web Store en laai die extension af. Die lêer sal 'n `.crx` uitbreiding hê. Verander die lêeruitbreiding van `.crx` na `.zip`. Gebruik enige file archiver (soos WinRAR, 7-Zip, ens.) om die inhoud van die ZIP-lêer uit te pak.
|
||
|
||
### Gebruik Developer Mode in Chrome
|
||
|
||
Maak Chrome oop en gaan na `chrome://extensions/`. Skakel "Developer mode" bo-aan regs aan. Klik op "Load unpacked extension...". Navigeer na die gids van jou extension. Dit laai nie die source code af nie, maar dit is nuttig om die kode van 'n reeds afgelaaide of ontwikkelde extension te sien en te wysig.
|
||
|
||
## Chrome extension manifest dataset
|
||
|
||
Om kwesbare browser extensions te probeer opspoor, kan jy die [https://github.com/palant/chrome-extension-manifests-dataset](https://github.com/palant/chrome-extension-manifests-dataset) gebruik en hul manifest-lêers vir moontlike kwetsbare tekens nagaan. Byvoorbeeld, om te kyk vir extensions met meer as 25000 gebruikers, `content_scripts` en die permission `nativeMessaing`:
|
||
```bash
|
||
# 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)
|
||
|
||
Stealthy technique to backdoor Chromium by directly editing per-user Preferences and forging valid HMACs, causing the browser to accept and activate an arbitrary unpacked extension without prompts or flags.
|
||
|
||
{{#ref}}
|
||
forced-extension-load-preferences-mac-forgery-windows.md
|
||
{{#endref}}
|
||
|
||
## Sekuriteitsoudit Kontrolelys
|
||
|
||
Alhoewel Browser Extensions 'n **beperkte aanvalsoorvlak** het, kan sommige van hulle **s kwesbaarhede** of **potensiële verhardingsverbeterings** bevat. Die volgende is die mees algemene:
|
||
|
||
- [ ] **Beperk** so veel as moontlik die aangevraagde **`permissions`**
|
||
- [ ] **Beperk** so veel as moontlik **`host_permissions`**
|
||
- [ ] Gebruik 'n **sterk** **`content_security_policy`**
|
||
- [ ] **Beperk** so veel as moontlik die **`externally_connectable`**; as geen nodig is en moontlik, laat dit nie verstek staan nie — spesifiseer **`{}`**
|
||
- [ ] As 'n URL wat vatbaar is vir **XSS** of vir takeover hier genoem word, sal 'n aanvaller in staat wees om **boodskappe direk na die background scripts te stuur**. Baie kragtige omseiling.
|
||
- [ ] **Beperk** so veel as moontlik die **`web_accessible_resources`**, selfs leë as moontlik.
|
||
- [ ] As **`web_accessible_resources`** nie leeg is nie, kyk vir [**ClickJacking**](browext-clickjacking.md)
|
||
- [ ] As enige **kommunikasie** van die **extension** na die **webblad** plaasvind, [**kontroleer vir XSS**](browext-xss-example.md) **kwesbaarhede** wat in die kommunikasie veroorsaak kan word.
|
||
- [ ] As Post Messages gebruik word, kontroleer vir [**Post Message vulnerabilities**](../postmessage-vulnerabilities/index.html)**.**
|
||
- [ ] As die **Content Script** toegang tot DOM-besonderhede het, kyk dat dit **nie 'n XSS inbring** as dit deur die web gewysig word nie
|
||
- [ ] Maak 'n spesiale klem as hierdie kommunikasie ook betrokke is by die **Content Script -> Background script communication**
|
||
- [ ] As die background script kommunikeer via **native messaging**, vergewis jouself dat die kommunikasie veilig en gesanitiseer is
|
||
- [ ] **Gevoelige inligting moet nie gestoor word** binne die Browser Extension **kode** nie
|
||
- [ ] **Gevoelige inligting moet nie gestoor word** binne die Browser Extension **geheue** nie
|
||
- [ ] **Gevoelige inligting moet nie onbeskermd gestoor word** op die **lêerstelsel** nie
|
||
|
||
## Risiko's van Browser Extensions
|
||
|
||
- Die app [https://crxaminer.tech/](https://crxaminer.tech/) analiseer sekere data soos die permissies wat 'n browser extension versoek om 'n risikovlak vir die gebruik van die extension te gee.
|
||
|
||
## Gereedskap
|
||
|
||
### [**Tarnish**](https://thehackerblog.com/tarnish/)
|
||
|
||
- Trek enige Chrome extension vanaf 'n gegewe Chrome webstore skakel.
|
||
- [**manifest.json**](https://developer.chrome.com/extensions/manifest) **kijker**: vertoon eenvoudig 'n JSON-pragvrye weergawe van die extension se manifest.
|
||
- **Fingerprint Analysis**: Opsporing van [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) en outomatiese generering van Chrome extension fingerprinting JavaScript.
|
||
- **Potential Clickjacking Analysis**: Opsporing van extension HTML-bladsye met die [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) direktef fest. Hierdie kan potensieel kwesbaar wees vir clickjacking afhangende van die doel van die bladsye.
|
||
- **Permission Warning(s) viewer**: wys 'n lys van al die Chrome permission prompt waarskuwings wat vertoon sal word wanneer 'n gebruiker probeer om die extension te installeer.
|
||
- **Dangerous Function(s)**: wys die plek van gevaarlike funksies wat moontlik deur 'n aanvaller uitgebuit kan word (bv. funksies soos innerHTML, chrome.tabs.executeScript).
|
||
- **Entry Point(s)**: wys waar die extension gebruikers-/eksterne insette aanvaar. Dit is nuttig om die oppervlakte van 'n extension te verstaan en potensiële punte te soek om kwaadwillig-opgemaakte data na die extension te stuur.
|
||
- Beide die Dangerous Function(s) en Entry Point(s) skanners lewer die volgende vir hul gegenereerde waarskuwings:
|
||
- Relevante kodefragment en lyn wat die waarskuwing veroorsaak het.
|
||
- Beskrywing van die kwessie.
|
||
- 'n “View File” knoppie om die volle bronlêer wat die kode bevat te sien.
|
||
- Die pad van die gewaarsku lde lêer.
|
||
- Die volle Chrome extension URI van die gewaarsku lde lêer.
|
||
- Die tipe lêer wat dit is, soos 'n Background Page script, Content Script, Browser Action, ens.
|
||
- As die kwesbare lyn in 'n JavaScript-lêer is, die paaie van al die bladsye waar dit ingesluit word sowel as die tipe van daardie bladsye, en [web_accessible_resource](https://developer.chrome.com/extensions/manifest/web_accessible_resources) status.
|
||
- **Content Security Policy (CSP) analyzer and bypass checker**: Sal swakhede in jou extension se CSP uitwys en ook enige potensiële maniere om jou CSP te omseil verklaar weens witgeplakte CDNs, ens.
|
||
- **Known Vulnerable Libraries**: Gebruik [Retire.js](https://retirejs.github.io/retire.js/) om te kyk vir enige gebruik van bekende-kwesbare JavaScript-biblioteke.
|
||
- Laai extension en geformateerde weergawes af.
|
||
- Laai die oorspronklike extension af.
|
||
- Laai 'n verfraaide weergawe van die extension af (outomaties gepretified HTML en JavaScript).
|
||
- Outomatiese kas van skanresultate; die eerste keer wat 'n extension geskan word sal dit 'n geruime tyd neem. Die tweede keer, mits die extension nie opgedateer is nie, sal dit byna onmiddellik wees as gevolg van kasresultate.
|
||
- Deelbare verslag-URL's, maklik om iemand anders na 'n Extension verslag wat deur tarnish gegenereer is te skakel.
|
||
|
||
### [Neto](https://github.com/elevenpaths/neto)
|
||
|
||
Project Neto is 'n Python 3 pakket wat ontwerp is om verborge funksies van browser plugins en extensions vir bekende blaaiers soos Firefox en Chrome te ontleed en te ontrafel. Dit outomatiseer die proses om gepakte lêers uit te pak om hierdie funksies uit relevante bronne in 'n extension soos `manifest.json`, lokalisasie-gidse of JavaScript- en HTML-bronkode-lêers te onttrek.
|
||
|
||
## Verwante bronne
|
||
|
||
- **Dank aan** [**@naivenom**](https://twitter.com/naivenom) **vir die hulp met hierdie metodologie**
|
||
- [https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing](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/10/anatomy-of-a-basic-extension/)
|
||
- [https://palant.info/2022/08/24/attack-surface-of-extension-pages/](https://palant.info/2022/08/24/attack-surface-of-extension-pages/)
|
||
- [https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/](https://palant.info/2022/08/31/when-extension-pages-are-web-accessible/)
|
||
- [https://help.passbolt.com/assets/files/PBL-02-report.pdf](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/develop/concepts/content-scripts)
|
||
- [https://developer.chrome.com/docs/extensions/mv2/background-pages](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://thehackerblog.com/kicking-the-rims-a-guide-for-securely-writing-and-auditing-chrome-extensions/)
|
||
- [https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0](https://gist.github.com/LongJohnCoder/9ddf5735df3a4f2e9559665fb864eac0)
|
||
|
||
{{#include ../../banners/hacktricks-training.md}}
|