mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-23 21:24:06 +00:00
612 lines
34 KiB
Markdown
612 lines
34 KiB
Markdown
|
# Méthodologie de Pentesting d'Extensions de Navigateur
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary><strong>Apprenez le hacking AWS de zéro à héros avec</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
|
||
|
Autres moyens de soutenir HackTricks :
|
||
|
|
||
|
* Si vous souhaitez voir votre **entreprise annoncée dans HackTricks** ou **télécharger HackTricks en PDF**, consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop)!
|
||
|
* Obtenez le [**merchandising officiel PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
|
* Découvrez [**La Famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection d'[**NFTs**](https://opensea.io/collection/the-peass-family) exclusifs
|
||
|
* **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||
|
* **Partagez vos astuces de hacking en soumettant des PR aux dépôts github** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
|
||
|
</details>
|
||
|
|
||
|
## Informations de Base
|
||
|
|
||
|
Les extensions de navigateur sont écrites en JavaScript et chargées par le navigateur en arrière-plan. Elles ont leur propre [DOM](https://www.w3schools.com/js/js_htmldom.asp) mais peuvent interagir avec les DOMs d'autres sites. Cela signifie qu'elles peuvent compromettre la confidentialité, l'intégrité et la disponibilité (CIA) d'autres sites.
|
||
|
|
||
|
## Composants Principaux
|
||
|
|
||
|
La structure d'une extension est mieux visualisée et se compose de trois composants. Examinons chaque composant en détail.
|
||
|
|
||
|
<figure><img src="../../.gitbook/assets/image.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>
|
||
|
|
||
|
### **Scripts de Contenu**
|
||
|
|
||
|
Chaque script de contenu a un accès direct au DOM d'une **page web unique** et est donc exposé à des entrées **potentiellement malveillantes**. Cependant, le script de contenu ne contient aucune permission autre que la capacité d'envoyer des messages au noyau de l'extension.
|
||
|
|
||
|
Pour voir et déboguer les scripts de contenu dans Chrome, vous pouvez ouvrir le menu des outils de développement de Chrome depuis Options > Plus d'outils > Outils de développement OU (Appuyez sur - Ctrl + Shift + I).
|
||
|
|
||
|
Avec les outils de développement affichés, cliquez sur l'onglet **Source**, puis sur l'onglet **Scripts de Contenu**. Ici, vous pouvez voir les scripts de contenu en cours d'exécution des différentes extensions et placer des points d'arrêt pour surveiller le flux d'exécution. Dans notre cas, nous avons montré via l'extension de navigateur Wappalyzer. 
|
||
|
|
||
|
<figure><img src="../../.gitbook/assets/image (1).png" alt=""><figcaption></figcaption></figure>
|
||
|
|
||
|
### **Noyau de l'Extension**
|
||
|
|
||
|
Le noyau de l'extension contient la plupart des privilèges/accès de l'extension, mais le noyau de l'extension ne peut interagir avec le contenu web que via [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) et les scripts de contenu. De plus, le noyau de l'extension n'a pas d'accès direct à la machine hôte.
|
||
|
|
||
|
### **Binaire Natif**
|
||
|
|
||
|
L'extension permet un binaire natif qui peut **accéder à la machine hôte avec les pleins privilèges de l'utilisateur.** Le binaire natif interagit avec le noyau de l'extension via l'interface de programmation d'applications de plugin Netscape standard ([NPAPI](https://en.wikipedia.org/wiki/NPAPI)) utilisée par Flash et d'autres plug-ins de navigateur.
|
||
|
|
||
|
### Limites
|
||
|
|
||
|
{% hint style="danger" %}
|
||
|
Pour obtenir les pleins privilèges de l'utilisateur, un attaquant doit convaincre l'extension de passer une entrée malveillante du script de contenu au noyau de l'extension et du noyau de l'extension au binaire natif.
|
||
|
{% endhint %}
|
||
|
|
||
|
Chaque composant de l'extension est séparé des autres par des **limites de protection solides**. Chaque composant s'exécute dans un **processus du système d'exploitation séparé**. Les scripts de contenu et les noyaux d'extension s'exécutent dans des **processus sandbox** inaccessibles à la plupart des services du système d'exploitation.  
|
||
|
|
||
|
De plus, les scripts de contenu sont séparés de leurs pages web associées en **s'exécutant dans un tas JavaScript séparé**. Le script de contenu et la page web ont **accès au même DOM sous-jacent**, mais les deux **n'échangent jamais de pointeurs JavaScript**, empêchant la fuite de fonctionnalités JavaScript.
|
||
|
|
||
|
## **`manifest.json`**
|
||
|
|
||
|
Une extension Chrome est simplement un dossier ZIP avec une extension de fichier [.crx](https://www.lifewire.com/crx-file-2620391). Le cœur de l'extension est le fichier **`manifest.json`** à la racine du dossier, qui spécifie la structure, les permissions et d'autres options de configuration.
|
||
|
|
||
|
Exemple :
|
||
|
```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`
|
||
|
|
||
|
Les scripts de contenu sont **chargés** chaque fois que l'utilisateur **navigue vers une page correspondante**, dans notre cas toute page correspondant à l'expression **`https://example.com/*`** et ne correspondant pas à la regex **`*://*/*/business*`**. Ils s'exécutent **comme les propres scripts de la page** et ont un accès arbitraire au [Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document\_Object\_Model) de la page.
|
||
|
```json
|
||
|
"content_scripts": [
|
||
|
{
|
||
|
"js": [
|
||
|
"script.js"
|
||
|
],
|
||
|
"matches": [
|
||
|
"https://example.com/*",
|
||
|
"https://www.example.com/*"
|
||
|
],
|
||
|
"exclude_matches": ["*://*/*business*"],
|
||
|
}
|
||
|
],
|
||
|
```
|
||
|
Afin d'inclure ou d'exclure davantage d'URLs, il est également possible d'utiliser **`include_globs`** et **`exclude_globs`**.
|
||
|
|
||
|
Voici un exemple de script de contenu qui ajoutera un bouton d'explication à la page lorsque [l'API de stockage](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage) pour récupérer la valeur `message` du stockage de l'extension.
|
||
|
```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);
|
||
|
});
|
||
|
```
|
||
|
```json
|
||
|
{
|
||
|
"name": "Exemple d'extension basée sur activeTab",
|
||
|
"version": "1.0",
|
||
|
"description": "Injecte des scripts de contenu dans l'onglet actif",
|
||
|
"permissions": ["activeTab"],
|
||
|
"background": {
|
||
|
"scripts": ["background.js"],
|
||
|
"persistent": false
|
||
|
},
|
||
|
"browser_action": {
|
||
|
"default_popup": "popup.html"
|
||
|
},
|
||
|
"manifest_version": 2
|
||
|
}
|
||
|
```
|
||
|
{% endcode %}
|
||
|
|
||
|
Lorsque ce bouton est cliqué, le script de contenu **utilise** [**runtime.sendMessage() API**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage) **pour envoyer un message aux pages de l'extension**. C'est parce qu'un script de contenu n'a accès directement qu'à un nombre limité d'APIs telles que `storage`. Tout le reste doit être effectué par les pages de l'extension auxquelles les scripts de contenu peuvent envoyer des messages.
|
||
|
|
||
|
{% hint style="warning" %}
|
||
|
Les **capacités des scripts de contenu** diffèrent légèrement selon le navigateur. Pour les navigateurs basés sur Chromium, vous pouvez trouver la liste dans la [documentation des développeurs Chrome](https://developer.chrome.com/docs/extensions/mv3/content_scripts/#capabilities), pour Firefox [MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis) est la source ultime.\
|
||
|
Rappelez-vous que le script de contenu peut également **communiquer avec les scripts d'arrière-plan** afin qu'ils effectuent des actions et renvoient la réponse.
|
||
|
{% endhint %}
|
||
|
|
||
|
### Scripts de contenu injectés
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Notez que les **scripts de contenu ne sont pas obligatoires** car il est également possible de **injecter** des scripts **dynamiquement** et de les **injecter de manière programmatique** dans des pages web via **`tabs.executeScript`**. Cela offre en fait plus de **contrôles granulaires**.
|
||
|
{% endhint %}
|
||
|
|
||
|
Pour injecter un script de contenu de manière programmatique, votre extension a besoin de [permissions d'hôte](https://developer.chrome.com/docs/extensions/reference/permissions) pour la page dans laquelle elle essaie d'injecter des scripts. Les permissions d'hôte peuvent être accordées soit en les **demandant** dans le manifeste de votre extension, soit temporairement via [**activeTab**](https://developer.chrome.com/docs/extensions/reference/manifest/activeTab)**.**
|
||
|
|
||
|
#### Exemple d'extension basée sur activeTab
|
||
|
|
||
|
{% code title="manifest.json" %}
|
||
|
```json
|
||
|
{
|
||
|
"name": "My extension",
|
||
|
...
|
||
|
"permissions": [
|
||
|
"activeTab",
|
||
|
"scripting"
|
||
|
],
|
||
|
"background": {
|
||
|
"service_worker": "background.js"
|
||
|
},
|
||
|
"action": {
|
||
|
"default_title": "Action Button"
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
* **Injecter un fichier JS au clic :**
|
||
|
```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"]
|
||
|
});
|
||
|
});
|
||
|
```
|
||
|
* **Injecter une fonction** au clic :
|
||
|
```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,
|
||
|
});
|
||
|
});
|
||
|
```
|
||
|
#### Exemple avec des permissions de script
|
||
|
```javascript
|
||
|
// service-workser.js
|
||
|
chrome.scripting.registerContentScripts([{
|
||
|
id : "test",
|
||
|
matches : [ "https://*.nytimes.com/*" ],
|
||
|
excludeMatches : [ "*://*/*business*" ],
|
||
|
js : [ "contentScript.js" ],
|
||
|
}]);
|
||
|
|
||
|
// ANother example
|
||
|
chrome.tabs.executeScript(tabId, { file: "content_script.js" });
|
||
|
```
|
||
|
Afin d'inclure ou d'exclure davantage d'URLs, il est également possible d'utiliser **`include_globs`** et **`exclude_globs`**.
|
||
|
|
||
|
### Scripts de contenu `run_at`
|
||
|
|
||
|
Le champ `run_at` contrôle **quand les fichiers JavaScript sont injectés dans la page web**. La valeur préférée et par défaut est `"document_idle"`.
|
||
|
|
||
|
Les valeurs possibles sont :
|
||
|
|
||
|
* **`document_idle`** : Dès que possible
|
||
|
* **`document_start`** : Après tous les fichiers de `css`, mais avant que toute autre construction du DOM ou exécution de script ait lieu.
|
||
|
* **`document_end`** : Immédiatement après que le DOM soit complet, mais avant que les sous-ressources telles que les images et les cadres soient chargées.
|
||
|
|
||
|
#### Via `manifest.json`
|
||
|
```json
|
||
|
{
|
||
|
"name": "My extension",
|
||
|
...
|
||
|
"content_scripts": [
|
||
|
{
|
||
|
"matches": ["https://*.nytimes.com/*"],
|
||
|
"run_at": "document_idle",
|
||
|
"js": ["contentScript.js"]
|
||
|
}
|
||
|
],
|
||
|
...
|
||
|
}
|
||
|
|
||
|
```
|
||
|
Via **`service-worker.js`**
|
||
|
```javascript
|
||
|
chrome.scripting.registerContentScripts([{
|
||
|
id : "test",
|
||
|
matches : [ "https://*.nytimes.com/*" ],
|
||
|
runAt : "document_idle",
|
||
|
js : [ "contentScript.js" ],
|
||
|
}]);
|
||
|
```
|
||
|
### `arrière-plan`
|
||
|
|
||
|
Lorsque les scripts de contenu envoient un message, leur destination est la **page d'arrière-plan**. La page d'arrière-plan est une page spéciale qui est **toujours présente** sauf indication contraire dans le manifeste de l'extension. Elle est invisible pour l'utilisateur, bien qu'elle soit une page normale avec son propre DOM et tout. Sa fonction est généralement de coordonner toutes les autres parties de l'extension.
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Si une page d'arrière-plan n'est pas déclarée explicitement, le navigateur va gentiment **en générer une** automatiquement et s'assurer que tous les **scripts d'arrière-plan déclarés sont chargés** dedans, comme dans l'exemple précédent de manifest.json.
|
||
|
{% endhint %}
|
||
|
|
||
|
Exemple de script d'arrière-plan :
|
||
|
```js
|
||
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
|
||
|
{
|
||
|
if (request == "explain")
|
||
|
{
|
||
|
chrome.tabs.create({ url: "https://example.net/explanation" });
|
||
|
}
|
||
|
})
|
||
|
```
|
||
|
Il utilise l'[API runtime.onMessage](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage) pour écouter les messages. Lorsqu'un message `"explain"` est reçu, il utilise l'[API tabs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs) pour ouvrir une page dans un nouvel onglet.
|
||
|
|
||
|
### Pages d'options et autres
|
||
|
|
||
|
Les extensions de navigateur peuvent contenir différents types de pages :
|
||
|
|
||
|
* Les **pages d'action** sont affichées dans un **menu déroulant lorsque l'icône de l'extension** est cliquée.
|
||
|
* Des pages que l'extension va **charger dans un nouvel onglet**.
|
||
|
* **Pages d'Options** : Cette page s'affiche au-dessus de l'extension lorsqu'on clique dessus. Dans le manifeste précédent, dans mon cas, j'ai pu accéder à cette page dans `chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca` ou en cliquant :
|
||
|
|
||
|
<figure><img src="../../.gitbook/assets/image (8).png" alt="" width="375"><figcaption></figcaption></figure>
|
||
|
|
||
|
Contrairement à la page d'arrière-plan, ces pages ne sont pas persistantes mais se chargent au besoin. Pourtant, toutes peuvent **recevoir des messages de scripts de contenu**. Et toutes ont **un accès complet aux API spécifiques à l'extension**, dans la mesure où les permissions de l'extension le permettent.
|
||
|
|
||
|
Ensemble, les contextes pertinents pour les extensions de navigateur ressemblent à ceci :
|
||
|
|
||
|
<figure><img src="../../.gitbook/assets/image (9).png" alt="" width="563"><figcaption></figcaption></figure>
|
||
|
|
||
|
### `permissions` & `host_permissions`
|
||
|
|
||
|
**`permissions`** et **`host_permissions`** sont des entrées du `manifest.json` qui indiqueront **quelles permissions** l'extension de navigateur a (stockage, localisation...) et sur **quelles pages web**.
|
||
|
|
||
|
Comme les extensions de navigateur peuvent être si **privilégiées**, une malveillante ou compromise pourrait permettre à l'attaquant **différents moyens de voler des informations sensibles et d'espionner l'utilisateur**.
|
||
|
|
||
|
Vérifiez comment ces paramètres fonctionnent et comment ils pourraient être abusés dans :
|
||
|
|
||
|
{% content-ref url="browext-permissions-and-host_permissions.md" %}
|
||
|
[browext-permissions-and-host\_permissions.md](browext-permissions-and-host\_permissions.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
### `content_security_policy`
|
||
|
|
||
|
Une **politique de sécurité de contenu** peut également être déclarée dans le `manifest.json`. Si une est définie, elle pourrait être **vulnérable**.
|
||
|
|
||
|
Le paramètre par défaut pour les pages d'extension de navigateur est plutôt restrictif :
|
||
|
```bash
|
||
|
script-src 'self'; object-src 'self';
|
||
|
```
|
||
|
Pour plus d'informations sur CSP et les contournements potentiels, consultez :
|
||
|
|
||
|
{% content-ref url="../content-security-policy-csp-bypass/" %}
|
||
|
[content-security-policy-csp-bypass](../content-security-policy-csp-bypass/)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
### `web_accessible_resources`
|
||
|
|
||
|
pour qu'une page web puisse accéder à une page d'une Extension de Navigateur, une page `.html` par exemple, cette page doit être mentionnée dans le champ **`web_accessible_resources`** du `manifest.json`.\
|
||
|
Par exemple :
|
||
|
```javascript
|
||
|
{
|
||
|
...
|
||
|
"web_accessible_resources": [
|
||
|
{
|
||
|
"resources": [ "images/*.png" ],
|
||
|
"matches": [ "https://example.com/*" ]
|
||
|
},
|
||
|
{
|
||
|
"resources": [ "fonts/*.woff" ],
|
||
|
"matches": [ "https://example.com/*" ]
|
||
|
}
|
||
|
],
|
||
|
...
|
||
|
}
|
||
|
```
|
||
|
Ces pages sont accessibles via des URL comme :
|
||
|
```
|
||
|
chrome-extension://<extension-id>/message.html
|
||
|
```
|
||
|
Dans les extensions publiques, **l'ID de l'extension est accessible** :
|
||
|
|
||
|
<figure><img src="../../.gitbook/assets/image (722).png" alt="" width="375"><figcaption></figcaption></figure>
|
||
|
|
||
|
Cependant, si le paramètre `manifest.json` **`use_dynamic_url`** est utilisé, cet **ID peut être dynamique**.
|
||
|
|
||
|
Le fait d'être autorisé à accéder à ces pages rend ces pages **potentiellement vulnérables au ClickJacking** :
|
||
|
|
||
|
{% content-ref url="browext-clickjacking.md" %}
|
||
|
[browext-clickjacking.md](browext-clickjacking.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
{% hint style="success" %}
|
||
|
Permettre à ces pages d'être chargées uniquement par l'extension et non par des URL aléatoires pourrait prévenir les attaques de ClickJacking.
|
||
|
{% endhint %}
|
||
|
|
||
|
### `externally_connectable`
|
||
|
|
||
|
Selon la [**documentation**](https://developer.chrome.com/docs/extensions/reference/manifest/externally_connectable), la propriété du manifeste `"externally_connectable"` déclare **quelles extensions et pages web peuvent se connecter** à votre extension via [runtime.connect](https://developer.chrome.com/docs/extensions/reference/runtime#method-connect) et [runtime.sendMessage](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage).
|
||
|
|
||
|
* Si la clé **`externally_connectable`** n'est **pas** déclarée dans le manifeste de votre extension ou si elle est déclarée comme **`"ids": ["*"]`**, **toutes les extensions peuvent se connecter, mais aucune page web ne peut se connecter**.
|
||
|
* Si **des ID spécifiques sont spécifiés**, comme dans `"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]`, **seules ces applications** peuvent se connecter.
|
||
|
* Si des **correspondances** sont spécifiées, ces applications web pourront se connecter :
|
||
|
```json
|
||
|
"matches": [
|
||
|
"https://*.google.com/*",
|
||
|
"*://*.chromium.org/*",
|
||
|
```
|
||
|
* Si c'est spécifié comme vide : **`"externally_connectable": {}`**, aucune application ou page web ne pourra se connecter.
|
||
|
|
||
|
Le **moins d'extensions et d'URLs** indiquées ici, la **surface d'attaque sera plus petite**.
|
||
|
|
||
|
{% hint style="danger" %}
|
||
|
Si une page web **vulnérable aux XSS ou à la prise de contrôle** est indiquée dans **`externally_connectable`**, un attaquant pourra **envoyer des messages directement au script de fond**, contournant complètement le script de contenu et sa CSP.
|
||
|
|
||
|
Par conséquent, c'est un **contournement très puissant**.
|
||
|
{% endhint %}
|
||
|
|
||
|
## Communication Web **↔︎** Script de Contenu
|
||
|
|
||
|
Bien que les environnements d'exécution des **scripts de contenu et des pages** qui les hébergent soient **isolés** l'un de l'autre, ils **partagent l'accès au DOM de la page**. Si la page souhaite communiquer avec le script de contenu, ou avec l'extension via le script de contenu, elle doit le faire à travers le **DOM partagé**.
|
||
|
|
||
|
### Post Messages
|
||
|
|
||
|
{% code title="content-script.js" %}
|
||
|
```javascript
|
||
|
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);
|
||
|
port.postMessage(event.data.text);
|
||
|
}
|
||
|
}, false);
|
||
|
```
|
||
|
```
|
||
|
{% endcode %}
|
||
|
|
||
|
{% code title="example.js" %}
|
||
|
```
|
||
|
```javascript
|
||
|
document.getElementById("theButton").addEventListener("click", () => {
|
||
|
window.postMessage(
|
||
|
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
|
||
|
}, false);
|
||
|
```
|
||
|
```markdown
|
||
|
{% endcode %}
|
||
|
|
||
|
Une communication Post Message sécurisée devrait vérifier l'authenticité du message reçu, cela peut être fait en vérifiant :
|
||
|
|
||
|
* **`event.isTrusted`** : Cela est vrai uniquement si l'événement a été déclenché par une action de l'utilisateur
|
||
|
* Le script de contenu pourrait attendre un message uniquement si l'utilisateur effectue une action
|
||
|
* **domaine d'origine** : Il peut être vérifié contre une liste blanche de domaines.
|
||
|
* Si une regex est utilisée, soyez très prudent
|
||
|
* **Source** : `received_message.source !== window` peut être utilisé pour vérifier si le message provient **de la même fenêtre** où le Script de Contenu écoute.
|
||
|
|
||
|
Les vérifications précédentes, même si effectuées, pourraient être vulnérables, donc vérifiez dans la page suivante **les contournements potentiels de Post Message** :
|
||
|
|
||
|
{% content-ref url="../postmessage-vulnerabilities/" %}
|
||
|
[postmessage-vulnerabilities](../postmessage-vulnerabilities/)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
### Iframe
|
||
|
|
||
|
Une autre manière possible de communication pourrait être à travers **les URL d'Iframe**, vous pouvez trouver un exemple dans :
|
||
|
|
||
|
{% content-ref url="browext-xss-example.md" %}
|
||
|
[browext-xss-example.md](browext-xss-example.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
### DOM
|
||
|
|
||
|
Ce n'est pas "exactement" une manière de communiquer, mais **le web et le script de contenu auront accès au DOM web**. Donc, si le **script de contenu** lit des informations à partir de celui-ci, **faisant confiance au DOM web**, le web pourrait **modifier ces données** (parce que le web ne devrait pas être considéré comme fiable, ou parce que le web est vulnérable aux XSS) et **compromettre le Script de Contenu**.
|
||
|
|
||
|
Vous pouvez également trouver un exemple de **XSS basé sur le DOM pour compromettre une extension de navigateur** dans :
|
||
|
|
||
|
{% content-ref url="browext-xss-example.md" %}
|
||
|
[browext-xss-example.md](browext-xss-example.md)
|
||
|
{% endcontent-ref %}
|
||
|
|
||
|
## Informations Sensibles en Mémoire/Code
|
||
|
|
||
|
Si une Extension de Navigateur stocke **des informations sensibles dans sa mémoire**, celles-ci pourraient être **extraites** (surtout sur les machines Windows) et **recherchées** pour ces informations.
|
||
|
|
||
|
Par conséquent, la mémoire de l'Extension de Navigateur **ne devrait pas être considérée comme sécurisée** et **les informations sensibles** telles que les identifiants ou les phrases mnémoniques **ne devraient pas être stockées**.
|
||
|
|
||
|
Bien sûr, **ne mettez pas d'informations sensibles dans le code**, car elles seront **publiques**.
|
||
|
|
||
|
## Communication Script de Contenu **↔︎** Script d'Arrière-plan
|
||
|
|
||
|
Un Script de Contenu peut utiliser les fonctions [**runtime.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage) **ou** [**tabs.sendMessage()**](https://developer.chrome.com/docs/extensions/reference/tabs#method-sendMessage) pour envoyer un message **sérialisable en JSON à usage unique**.
|
||
|
|
||
|
Pour gérer la **réponse**, utilisez la **Promise** retournée. Cependant, pour la compatibilité ascendante, vous pouvez toujours passer un **callback** comme dernier argument.
|
||
|
|
||
|
L'envoi d'une requête à partir d'un **script de contenu** ressemble à ceci :
|
||
|
```
|
||
|
```javascript
|
||
|
(async () => {
|
||
|
const response = await chrome.runtime.sendMessage({greeting: "hello"});
|
||
|
// do something with response here, not outside the function
|
||
|
console.log(response);
|
||
|
})();
|
||
|
```
|
||
|
L'envoi d'une requête depuis l'**extension** (généralement un **script d'arrière-plan**) vers un script de contenu est similaire, sauf que vous devez spécifier à quel onglet l'envoyer. Cet exemple montre comment envoyer un message au script de contenu dans l'onglet sélectionné.
|
||
|
```javascript
|
||
|
(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);
|
||
|
})();
|
||
|
```
|
||
|
À **l'extrémité réceptrice**, vous devez configurer un [**runtime.onMessage**](https://developer.chrome.com/docs/extensions/reference/runtime#event-onMessage) **écouteur d'événement** pour gérer le message. Cela ressemble à la même chose depuis un script de contenu ou une page d'extension.
|
||
|
```javascript
|
||
|
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"});
|
||
|
}
|
||
|
);
|
||
|
```
|
||
|
Dans l'exemple ci-dessus, **`sendResponse()`** a été appelé de manière synchrone. Si vous souhaitez utiliser `sendResponse()` de manière **asynchrone**, ajoutez `return true;` au gestionnaire d'événement `onMessage`.
|
||
|
|
||
|
> Si plusieurs pages écoutent les événements `onMessage`, **seule la première à appeler `sendResponse()`** pour un événement particulier réussira à envoyer la réponse. Toutes les autres réponses à cet événement seront ignorées.
|
||
|
|
||
|
Pour les nouvelles extensions, vous devriez préférer les promesses aux rappels (callbacks). Si vous utilisez des rappels, le rappel `sendResponse()` n'est valide que s'il est utilisé de manière synchrone, ou si le gestionnaire d'événement retourne `true` pour indiquer qu'il répondra de manière asynchrone. Le rappel de la fonction `sendMessage()` sera invoqué automatiquement si aucun gestionnaire ne retourne true ou si le rappel `sendResponse()` est collecté par le garbage collector.
|
||
|
|
||
|
## Charger une Extension dans le Navigateur
|
||
|
|
||
|
1. **Téléchargez** l'Extension pour Navigateur et décompressez-la
|
||
|
2. Allez sur **`chrome://extensions/`** et **activez** le `Mode Développeur`
|
||
|
3. Cliquez sur le bouton **`Charger l'extension non empaquetée`**
|
||
|
|
||
|
Dans **Firefox**, vous allez sur **`about:debugging#/runtime/this-firefox`** et cliquez sur le bouton **`Charger un module temporaire`**.
|
||
|
|
||
|
## Obtenir le code source depuis le magasin
|
||
|
|
||
|
Depuis [**ici**](https://gist.github.com/paulirish/78d6c1406c901be02c2d):
|
||
|
|
||
|
### Option 1 : Téléchargement de l'extension en ligne de commande sous forme de zip et extraction
|
||
|
|
||
|
{% code overflow="wrap" %}
|
||
|
```bash
|
||
|
extension_id=jifpbeccnghkjeaalbbjmodiffmgedin # change this 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"
|
||
|
```
|
||
|
```markdown
|
||
|
{% endcode %}
|
||
|
|
||
|
Merci à crxviewer pour l'[URL de téléchargement magique](https://github.com/Rob--W/crxviewer/blob/6113c25e3569e1ec59365ad9a177aa97e2bcda61/src/cws_pattern.js#L27-L74).
|
||
|
|
||
|
### Option 2 : Utiliser le site web CRX Viewer
|
||
|
|
||
|
[https://robwu.nl/crxviewer/](https://robwu.nl/crxviewer/)
|
||
|
|
||
|
### Option 3 : Utiliser l'extension CRX Viewer
|
||
|
|
||
|
L'[extension Chrome pour visualiser le code source](https://chrome.google.com/webstore/detail/chrome-extension-source-v/jifpbeccnghkjeaalbbjmodiffmgedin?hl=en) est open source ([dépôt github](https://github.com/Rob--W/crxviewer)) et rend cela très facile.
|
||
|
|
||
|
### Option 3 : Voir le code source d'une extension installée localement
|
||
|
|
||
|
1. Trouvez le répertoire de profil local de Chrome. Ouvrez `chrome://version/` et trouvez le champ "Chemin du profil:". Ouvrez ce dossier.
|
||
|
2. Ouvrez le sous-dossier `Extensions/`
|
||
|
3. Toutes vos extensions sont ici, avec généralement une source lisible.
|
||
|
|
||
|
#### Correspondance entre les IDs des extensions installées localement et les noms
|
||
|
|
||
|
* Sur `about:extensions`, activez le Mode Développeur et vous verrez les IDs sous chaque entrée
|
||
|
* Dans les dossiers `Extensions/`, le fichier manifest.json contient un champ `name` lisible
|
||
|
|
||
|
## Liste de vérification pour l'audit de sécurité
|
||
|
|
||
|
Bien que les Extensions de Navigateur aient une **surface d'attaque limitée**, certaines peuvent contenir des **vulnérabilités** ou des **améliorations de durcissement potentielles**. Voici les plus courantes :
|
||
|
|
||
|
* [ ] **Limiter** autant que possible les **`permissions`** demandées
|
||
|
* [ ] **Limiter** autant que possible les **`host_permissions`**
|
||
|
* [ ] Utiliser une **politique de sécurité de contenu (`content_security_policy`)** **forte**
|
||
|
* [ ] **Limiter** autant que possible l'attribut **`externally_connectable`**, si aucun n'est nécessaire et possible, ne pas le laisser par défaut, spécifier **`{}`**
|
||
|
* [ ] Si une **URL vulnérable aux XSS ou à la prise de contrôle** est mentionnée ici, un attaquant pourra **envoyer des messages aux scripts en arrière-plan directement**. Contournement très puissant.
|
||
|
* [ ] **Limiter** autant que possible les **`web_accessible_resources`**, même vide si possible.
|
||
|
* [ ] Si **`web_accessible_resources`** n'est pas nul, vérifier la présence de [**ClickJacking**](browext-clickjacking.md)
|
||
|
* [ ] Si une **communication** a lieu de l'**extension** vers la **page web**, [**vérifier les vulnérabilités XSS**](browext-xss-example.md) **causées dans la communication**.
|
||
|
* [ ] Si les Post Messages sont utilisés, vérifier les [**vulnérabilités des Post Messages**](../postmessage-vulnerabilities/)**.**
|
||
|
* [ ] Si le **Content Script accède aux détails du DOM**, vérifier qu'ils **n'introduisent pas de XSS** s'ils sont **modifiés** par le web
|
||
|
* [ ] Mettre un accent particulier si cette communication est également impliquée dans la **communication Content Script -> Script en arrière-plan**
|
||
|
* [ ] **Les informations sensibles ne doivent pas être stockées** dans le code de l'Extension de Navigateur
|
||
|
* [ ] **Les informations sensibles ne doivent pas être stockées** dans la mémoire de l'Extension de Navigateur
|
||
|
|
||
|
## Outils
|
||
|
|
||
|
### [**Tarnish**](https://thehackerblog.com/tarnish/)
|
||
|
|
||
|
* Télécharge n'importe quelle extension Chrome à partir d'un lien fourni du Chrome webstore.
|
||
|
* **Visualiseur de `manifest.json`** : affiche simplement une version JSON joliment formatée du manifeste de l'extension.
|
||
|
* **Analyse d'empreinte digitale** : Détection des [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) et génération automatique de JavaScript pour l'empreinte digitale des extensions Chrome.
|
||
|
* **Analyse Potentielle de Clickjacking** : Détection des pages HTML d'extension avec la directive [web_accessible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) définie. Celles-ci sont potentiellement vulnérables au clickjacking en fonction de l'objectif des pages.
|
||
|
* **Visualiseur d'avertissements de permissions** : qui montre une liste de tous les avertissements de demande de permission de Chrome qui seront affichés lorsqu'un utilisateur tente d'installer l'extension.
|
||
|
* **Fonctions Dangereuses** : montre l'emplacement des fonctions dangereuses qui pourraient potentiellement être exploitées par un attaquant (par exemple, des fonctions telles que innerHTML, chrome.tabs.executeScript).
|
||
|
* **Points d'Entrée** : montre où l'extension prend des entrées utilisateur/externes. Cela est utile pour comprendre la surface d'attaque d'une extension et chercher des points potentiels pour envoyer des données malicieusement conçues à l'extension.
|
||
|
* Les scanners de Fonctions Dangereuses et de Points d'Entrée ont les éléments suivants pour leurs alertes générées :
|
||
|
* Extrait de code pertinent et ligne qui a causé l'alerte.
|
||
|
* Description du problème.
|
||
|
* Un bouton "Voir le fichier" pour visualiser le fichier source complet contenant le code.
|
||
|
* Le chemin du fichier alerté.
|
||
|
* L'URI complet de l'extension Chrome du fichier alerté.
|
||
|
* Le type de fichier, tel qu'un script de Page d'Arrière-plan, Script de Contenu, Action de Navigateur, etc.
|
||
|
* Si la ligne vulnérable se trouve dans un fichier JavaScript, les chemins de toutes les pages où il est inclus ainsi que le type de ces pages, et le statut de [web_accessible_resource](https://developer.chrome.com/extensions/manifest/web_accessible_resources).
|
||
|
* **Analyseur de Politique de Sécurité de Contenu (CSP) et vérificateur de contournement** : Cela mettra en évidence les faiblesses dans le CSP de votre extension et éclairera également les moyens potentiels de contourner votre CSP en raison de CDNs autorisés, etc.
|
||
|
* **Bibliothèques Vulnérables Connues** : Utilise [Retire.js](https://retirejs.github.io/retire.js/) pour vérifier toute utilisation de bibliothèques JavaScript connues pour être vulnérables.
|
||
|
* Télécharger l'extension et les versions formatées.
|
||
|
* Télécharger l'extension originale.
|
||
|
* Télécharger une version embelli de l'extension (HTML et JavaScript automatiquement jolis).
|
||
|
* Mise en cache automatique des résultats d'analyse, l'exécution d'une analyse d'extension prendra un bon moment la première fois que vous l'exécutez. Cependant, la deuxième fois, en supposant que l'extension n'ait pas été mise à jour, sera presque instantanée grâce à la mise en cache des résultats.
|
||
|
* URLs de Rapport Partageables, liez facilement quelqu'un d'autre à un rapport d'extension généré par tarnish.
|
||
|
|
||
|
### [Neto](https://github.com/elevenpaths/neto)
|
||
|
|
||
|
Le projet Neto est un package Python 3 conçu pour analyser et révéler les fonctionnalités cachées des plugins et extensions de navigateur pour des navigateurs bien connus tels que Firefox et Chrome. Il automatise le processus de décompression des fichiers empaquetés pour extraire ces fonctionnalités de ressources pertinentes dans une extension comme `manifest.json`, les dossiers de localisation ou les fichiers sources Javascript et HTML.
|
||
|
|
||
|
## Références
|
||
|
|
||
|
* **Merci à** [**@naivenom**](https://twitter.com/naivenom) **pour l'aide avec cette méthodologie**
|
||
|
* [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/)
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary><strong>Apprenez le hacking AWS de zéro à héros avec</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
||
|
|
||
|
Autres moyens de soutenir HackTricks :
|
||
|
|
||
|
* Si vous souhaitez voir votre **entreprise annoncée dans HackTricks** ou **télécharger HackTricks en PDF**, consultez les [**PLANS D'ABONNEMENT**](https://github.com/sponsors/carlospolop)!
|
||
|
* Obtenez le [**merchandising officiel PEASS & HackTricks**](https://peass.creator-spring.com)
|
||
|
* Découvrez [**La Famille PEASS**](https://opensea.io/collection/the-peass-family), notre collection d'[**NFTs**](https://opensea.io/collection/the-peass-family) exclusifs
|
||
|
* **Rejoignez le** 💬 [**groupe Discord**](https://discord.gg/hRep4RUj7f) ou le [**groupe telegram**](https://t.me/peass) ou **suivez** moi sur **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
|
||
|
* **Partagez vos astuces de hacking en soumettant des PR aux dépôts github** [**HackTricks**](https://github.com/carlospolop/hacktricks) et [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud).
|
||
|
|
||
|
</details>
|
||
|
```
|