mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-29 22:43:11 +00:00
749 lines
44 KiB
Markdown
749 lines
44 KiB
Markdown
# Metodologia de Pentesting de Extensões de Navegador
|
|
|
|
{% hint style="success" %}
|
|
Aprenda e pratique Hacking AWS:<img src="../../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/arte.png" alt="" data-size="line">\
|
|
Aprenda e pratique Hacking GCP: <img src="../../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
|
|
|
<details>
|
|
|
|
<summary>Suporte ao HackTricks</summary>
|
|
|
|
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
|
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
|
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|
|
{% endhint %}
|
|
|
|
## Informações Básicas
|
|
|
|
Extensões de navegador são escritas em JavaScript e carregadas pelo navegador em segundo plano. Elas têm seu [DOM](https://www.w3schools.com/js/js_htmldom.asp) mas podem interagir com os DOMs de outros sites. Isso significa que pode comprometer a confidencialidade, integridade e disponibilidade (CIA) de outros sites.
|
|
|
|
## Principais Componentes
|
|
|
|
Os layouts de extensão são melhor visualizados e consistem em três componentes. Vamos analisar cada componente em profundidade.
|
|
|
|
<figure><img src="../../.gitbook/assets/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>
|
|
|
|
### **Scripts de Conteúdo**
|
|
|
|
Cada script de conteúdo tem acesso direto ao DOM de uma **única página da web** e está, portanto, exposto a **entrada potencialmente maliciosa**. No entanto, o script de conteúdo não contém permissões além da capacidade de enviar mensagens ao núcleo da extensão.
|
|
|
|
### **Núcleo da Extensão**
|
|
|
|
O núcleo da extensão contém a maioria dos privilégios/acessos da extensão, mas o núcleo da extensão só pode interagir com o conteúdo da web via [XMLHttpRequest](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) e scripts de conteúdo. Além disso, o núcleo da extensão não tem acesso direto à máquina host.
|
|
|
|
### **Binário Nativo**
|
|
|
|
A extensão permite um binário nativo que pode **acessar a máquina host com os privilégios totais do usuário.** O binário nativo interage com o núcleo da extensão através da interface de programação de aplicativos padrão do Netscape Plugin ([NPAPI](https://en.wikipedia.org/wiki/NPAPI)) usada pelo Flash e outros plug-ins de navegador.
|
|
|
|
### Limites
|
|
|
|
{% hint style="danger" %}
|
|
Para obter os privilégios totais do usuário, um atacante deve convencer a extensão a passar entrada maliciosa do script de conteúdo para o núcleo da extensão e do núcleo da extensão para o binário nativo.
|
|
{% endhint %}
|
|
|
|
Cada componente da extensão é separado dos outros por **fortes limites de proteção**. Cada componente é executado em um **processo de sistema operacional separado**. Scripts de conteúdo e núcleos de extensão são executados em **processos de sandbox** indisponíveis para a maioria dos serviços do sistema operacional.
|
|
|
|
Além disso, os scripts de conteúdo são separados de suas páginas da web associadas por **executarem em um heap JavaScript separado**. O script de conteúdo e a página da web têm **acesso ao mesmo DOM subjacente**, mas os dois **nunca trocam ponteiros JavaScript**, prevenindo o vazamento de funcionalidade JavaScript.
|
|
|
|
## **`manifest.json`**
|
|
|
|
Uma extensão do Chrome é apenas uma pasta ZIP com uma [.crx file extension](https://www.lifewire.com/crx-file-2620391). O núcleo da extensão é o **`manifest.json`** arquivo na raiz da pasta, que especifica layout, permissões e outras opções de configuração.
|
|
|
|
Exemplo:
|
|
```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`
|
|
|
|
Os scripts de conteúdo são **carregados** sempre que o usuário **navega para uma página correspondente**, neste caso, qualquer página que corresponda à expressão **`https://example.com/*`** e não corresponda à regex **`*://*/*/business*`**. Eles são executados **como os próprios scripts da página** e têm acesso arbitrário ao [Modelo de Objeto de Documento (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) da página.
|
|
```json
|
|
"content_scripts": [
|
|
{
|
|
"js": [
|
|
"script.js"
|
|
],
|
|
"matches": [
|
|
"https://example.com/*",
|
|
"https://www.example.com/*"
|
|
],
|
|
"exclude_matches": ["*://*/*business*"],
|
|
}
|
|
],
|
|
```
|
|
Para incluir ou excluir mais URLs, também é possível usar **`include_globs`** e **`exclude_globs`**.
|
|
|
|
Este é um exemplo de script de conteúdo que adicionará um botão de explicação à página quando [a API de armazenamento](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage) for usada para recuperar o valor `message` do armazenamento da extensão.
|
|
```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="../../.gitbook/assets/image (23).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
Uma mensagem é enviada para as páginas da extensão pelo script de conteúdo quando este botão é clicado, através da utilização da [**runtime.sendMessage() API**](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/sendMessage). Isso se deve à limitação do script de conteúdo em acessar APIs diretamente, sendo `storage` uma das poucas exceções. Para funcionalidades além dessas exceções, mensagens são enviadas para as páginas da extensão com as quais os scripts de conteúdo podem se comunicar.
|
|
|
|
{% hint style="warning" %}
|
|
Dependendo do navegador, as capacidades do script de conteúdo podem variar ligeiramente. Para navegadores baseados em Chromium, a lista de capacidades está disponível na [documentação dos desenvolvedores do Chrome](https://developer.chrome.com/docs/extensions/mv3/content_scripts/#capabilities), e para o Firefox, o [MDN](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#webextension_apis) serve como a fonte principal.\
|
|
É também notável que os scripts de conteúdo têm a capacidade de se comunicar com scripts de fundo, permitindo que realizem ações e retransmitam respostas.
|
|
{% endhint %}
|
|
|
|
Para visualizar e depurar scripts de conteúdo no Chrome, o menu de ferramentas de desenvolvedor do Chrome pode ser acessado em Opções > Mais ferramentas > Ferramentas do desenvolvedor OU pressionando Ctrl + Shift + I.
|
|
|
|
Após as ferramentas de desenvolvedor serem exibidas, a aba **Fonte** deve ser clicada, seguida pela aba **Scripts de Conteúdo**. Isso permite a observação de scripts de conteúdo em execução de várias extensões e a definição de pontos de interrupção para rastrear o fluxo de execução.
|
|
|
|
### Scripts de conteúdo injetados
|
|
|
|
{% hint style="success" %}
|
|
Observe que **Scripts de Conteúdo não são obrigatórios** pois também é possível **injetar** scripts **dinamicamente** e **injetá-los programaticamente** em páginas da web via **`tabs.executeScript`**. Isso na verdade fornece mais **controles granulares**.
|
|
{% endhint %}
|
|
|
|
Para a injeção programática de um script de conteúdo, a extensão deve ter [permissões de host](https://developer.chrome.com/docs/extensions/reference/permissions) para a página na qual os scripts devem ser injetados. Essas permissões podem ser obtidas solicitando-as dentro do manifesto da extensão ou de forma temporária através de [**activeTab**](https://developer.chrome.com/docs/extensions/reference/manifest/activeTab).
|
|
|
|
#### Exemplo de extensão baseada em activeTab
|
|
|
|
{% code title="manifest.json" %}
|
|
```json
|
|
{
|
|
"name": "My extension",
|
|
...
|
|
"permissions": [
|
|
"activeTab",
|
|
"scripting"
|
|
],
|
|
"background": {
|
|
"service_worker": "background.js"
|
|
},
|
|
"action": {
|
|
"default_title": "Action Button"
|
|
}
|
|
}
|
|
```
|
|
{% endcode %}
|
|
|
|
* **Injetar um arquivo JS ao clicar:**
|
|
```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"]
|
|
});
|
|
});
|
|
```
|
|
* **Injetar uma função** ao clicar:
|
|
```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,
|
|
});
|
|
});
|
|
```
|
|
#### Exemplo com permissões de script
|
|
```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" });
|
|
```
|
|
Para incluir ou excluir mais URLs, também é possível usar **`include_globs`** e **`exclude_globs`**.
|
|
|
|
### Content Scripts `run_at`
|
|
|
|
O campo `run_at` controla **quando os arquivos JavaScript são injetados na página da web**. O valor preferido e padrão é `"document_idle"`.
|
|
|
|
Os valores possíveis são:
|
|
|
|
* **`document_idle`**: Sempre que possível
|
|
* **`document_start`**: Após quaisquer arquivos de `css`, mas antes que qualquer outro DOM seja construído ou qualquer outro script seja executado.
|
|
* **`document_end`**: Imediatamente após o DOM estar completo, mas antes que subrecursos como imagens e frames tenham sido carregados.
|
|
|
|
#### Via `manifest.json`
|
|
```json
|
|
{
|
|
"name": "My extension",
|
|
...
|
|
"content_scripts": [
|
|
{
|
|
"matches": ["https://*.example.com/*"],
|
|
"run_at": "document_idle",
|
|
"js": ["contentScript.js"]
|
|
}
|
|
],
|
|
...
|
|
}
|
|
|
|
```
|
|
Via **`service-worker.js`**
|
|
```javascript
|
|
chrome.scripting.registerContentScripts([{
|
|
id : "test",
|
|
matches : [ "https://*.example.com/*" ],
|
|
runAt : "document_idle",
|
|
js : [ "contentScript.js" ],
|
|
}]);
|
|
```
|
|
### `background`
|
|
|
|
As mensagens enviadas por scripts de conteúdo são recebidas pela **página de fundo**, que desempenha um papel central na coordenação dos componentes da extensão. Notavelmente, a página de fundo persiste ao longo da vida útil da extensão, operando discretamente sem interação direta do usuário. Ela possui seu próprio Modelo de Objeto de Documento (DOM), permitindo interações complexas e gerenciamento de estado.
|
|
|
|
**Pontos Chave**:
|
|
|
|
* **Papel da Página de Fundo:** Atua como o centro nervoso da extensão, garantindo comunicação e coordenação entre várias partes da extensão.
|
|
* **Persistência:** É uma entidade sempre presente, invisível ao usuário, mas integral à funcionalidade da extensão.
|
|
* **Geração Automática:** Se não for explicitamente definida, o navegador criará automaticamente uma página de fundo. Esta página gerada automaticamente incluirá todos os scripts de fundo especificados no manifesto da extensão, garantindo a operação contínua das tarefas de fundo da extensão.
|
|
|
|
{% hint style="success" %}
|
|
A conveniência proporcionada pelo navegador ao gerar automaticamente uma página de fundo (quando não declarada explicitamente) garante que todos os scripts de fundo necessários estejam integrados e operacionais, simplificando o processo de configuração da extensão.
|
|
{% endhint %}
|
|
|
|
Exemplo de script de fundo:
|
|
```js
|
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>
|
|
{
|
|
if (request == "explain")
|
|
{
|
|
chrome.tabs.create({ url: "https://example.net/explanation" });
|
|
}
|
|
})
|
|
```
|
|
Ele usa a [runtime.onMessage API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage) para escutar mensagens. Quando uma mensagem `"explain"` é recebida, ele usa a [tabs API](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs) para abrir uma página em uma nova aba.
|
|
|
|
Para depurar o script de fundo, você pode ir aos **detalhes da extensão e inspecionar o service worker,** isso abrirá as ferramentas de desenvolvedor com o script de fundo:
|
|
|
|
<figure><img src="https://github.com/carlospolop/hacktricks/blob/master/pentesting-web/browser-extension-pentesting-methodology/broken-reference" alt=""><figcaption></figcaption></figure>
|
|
|
|
### Páginas de opções e outras
|
|
|
|
As extensões do navegador podem conter vários tipos de páginas:
|
|
|
|
* **Páginas de ação** são exibidas em um **menu suspenso quando o ícone da extensão** é clicado.
|
|
* Páginas que a extensão irá **carregar em uma nova aba**.
|
|
* **Páginas de Opção**: Esta página é exibida no topo da extensão quando clicada. No manifesto anterior, no meu caso, consegui acessar esta página em `chrome://extensions/?options=fadlhnelkbeojnebcbkacjilhnbjfjca` ou clicando:
|
|
|
|
<figure><img src="../../.gitbook/assets/image (24).png" alt="" width="375"><figcaption></figcaption></figure>
|
|
|
|
Note que essas páginas não são persistentes como as páginas de fundo, pois carregam conteúdo dinamicamente conforme necessário. Apesar disso, elas compartilham certas capacidades com a página de fundo:
|
|
|
|
* **Comunicação com Scripts de Conteúdo:** Semelhante à página de fundo, essas páginas podem receber mensagens de scripts de conteúdo, facilitando a interação dentro da extensão.
|
|
* **Acesso a APIs Específicas da Extensão:** Essas páginas têm acesso abrangente a APIs específicas da extensão, sujeito às permissões definidas para a extensão.
|
|
|
|
### `permissions` & `host_permissions`
|
|
|
|
**`permissions`** e **`host_permissions`** são entradas do `manifest.json` que indicarão **quais permissões** a extensão do navegador possui (armazenamento, localização...) e em **quais páginas da web**.
|
|
|
|
Como as extensões do navegador podem ser tão **privilegiadas**, uma maliciosa ou uma que esteja comprometida poderia permitir ao atacante **diferentes meios de roubar informações sensíveis e espionar o usuário**.
|
|
|
|
Verifique como essas configurações funcionam e como podem ser abusadas em:
|
|
|
|
{% 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`
|
|
|
|
Uma **política de segurança de conteúdo** pode ser declarada também dentro do `manifest.json`. Se houver uma definida, ela pode ser **vulnerável**.
|
|
|
|
A configuração padrão para páginas de extensão do navegador é bastante restritiva:
|
|
```bash
|
|
script-src 'self'; object-src 'self';
|
|
```
|
|
Para mais informações sobre CSP e possíveis contornos, consulte:
|
|
|
|
{% content-ref url="../content-security-policy-csp-bypass/" %}
|
|
[content-security-policy-csp-bypass](../content-security-policy-csp-bypass/)
|
|
{% endcontent-ref %}
|
|
|
|
### `web_accessible_resources`
|
|
|
|
Para que uma página da web acesse uma página de uma extensão do navegador, uma página `.html`, por exemplo, essa página precisa ser mencionada no campo **`web_accessible_resources`** do `manifest.json`.\
|
|
Por exemplo:
|
|
```javascript
|
|
{
|
|
...
|
|
"web_accessible_resources": [
|
|
{
|
|
"resources": [ "images/*.png" ],
|
|
"matches": [ "https://example.com/*" ]
|
|
},
|
|
{
|
|
"resources": [ "fonts/*.woff" ],
|
|
"matches": [ "https://example.com/*" ]
|
|
}
|
|
],
|
|
...
|
|
}
|
|
```
|
|
Estas páginas são acessíveis em URL como:
|
|
```
|
|
chrome-extension://<extension-id>/message.html
|
|
```
|
|
Em extensões públicas, o **extension-id é acessível**:
|
|
|
|
<figure><img src="../../.gitbook/assets/image (1194).png" alt="" width="375"><figcaption></figcaption></figure>
|
|
|
|
No entanto, se o parâmetro `manifest.json` **`use_dynamic_url`** for utilizado, este **id pode ser dinâmico**.
|
|
|
|
{% hint style="success" %}
|
|
Observe que, mesmo que uma página seja mencionada aqui, ela pode estar **protegida contra ClickJacking** graças à **Content Security Policy**. Portanto, você também precisa verificá-la (seção frame-ancestors) antes de confirmar que um ataque de ClickJacking é possível.
|
|
{% endhint %}
|
|
|
|
Ter acesso a essas páginas torna essas páginas **potencialmente vulneráveis a ClickJacking**:
|
|
|
|
{% content-ref url="browext-clickjacking.md" %}
|
|
[browext-clickjacking.md](browext-clickjacking.md)
|
|
{% endcontent-ref %}
|
|
|
|
{% hint style="success" %}
|
|
Permitir que essas páginas sejam carregadas apenas pela extensão e não por URLs aleatórias poderia prevenir ataques de ClickJacking.
|
|
{% endhint %}
|
|
|
|
{% hint style="danger" %}
|
|
Observe que as páginas de **`web_accessible_resources`** e outras páginas da extensão também são capazes de **contatar scripts em segundo plano**. Portanto, se uma dessas páginas for vulnerável a **XSS**, isso poderia abrir uma vulnerabilidade maior.
|
|
|
|
Além disso, note que você só pode abrir páginas indicadas em **`web_accessible_resources`** dentro de iframes, mas de uma nova aba é possível acessar qualquer página na extensão conhecendo o ID da extensão. Portanto, se um XSS for encontrado abusando dos mesmos parâmetros, ele poderia ser explorado mesmo que a página não esteja configurada em **`web_accessible_resources`**.
|
|
{% endhint %}
|
|
|
|
### `externally_connectable`
|
|
|
|
De acordo com a [**docs**](https://developer.chrome.com/docs/extensions/reference/manifest/externally-connectable), a propriedade de manifesto `"externally_connectable"` declara **quais extensões e páginas da web podem se conectar** à sua extensão via [runtime.connect](https://developer.chrome.com/docs/extensions/reference/runtime#method-connect) e [runtime.sendMessage](https://developer.chrome.com/docs/extensions/reference/runtime#method-sendMessage).
|
|
|
|
* Se a chave **`externally_connectable`** **não** for declarada no manifesto da sua extensão ou for declarada como **`"ids": ["*"]`**, **todas as extensões podem se conectar, mas nenhuma página da web pode se conectar**.
|
|
* Se **IDs específicos forem especificados**, como em `"ids": ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]`, **apenas esses aplicativos** podem se conectar.
|
|
* Se **matches** forem especificados, esses aplicativos da web poderão se conectar:
|
|
```json
|
|
"matches": [
|
|
"https://*.google.com/*",
|
|
"*://*.chromium.org/*",
|
|
```
|
|
* Se estiver especificado como vazio: **`"externally_connectable": {}`**, nenhum aplicativo ou site poderá se conectar.
|
|
|
|
Quanto **menos extensões e URLs** indicadas aqui, **menor será a superfície de ataque**.
|
|
|
|
{% hint style="danger" %}
|
|
Se uma página da web **vulnerável a XSS ou takeover** estiver indicada em **`externally_connectable`**, um atacante poderá **enviar mensagens diretamente para o script de fundo**, contornando completamente o Content Script e seu CSP.
|
|
|
|
Portanto, este é um **bypass muito poderoso**.
|
|
|
|
Além disso, se o cliente instalar uma extensão maliciosa, mesmo que não seja permitido comunicar-se com a extensão vulnerável, ela poderá injetar **dados XSS em uma página da web permitida** ou abusar das APIs **`WebRequest`** ou **`DeclarativeNetRequest`** para manipular solicitações em um domínio alvo alterando a solicitação de uma **arquivo JavaScript**. (Observe que o CSP na página alvo pode impedir esses ataques). Esta ideia vem [**deste writeup**](https://www.darkrelay.com/post/opera-zero-day-rce-vulnerability).
|
|
{% endhint %}
|
|
|
|
## Resumo da comunicação
|
|
|
|
### Extensão <--> WebApp
|
|
|
|
Para se comunicar entre o script de conteúdo e a página da web, mensagens postadas são geralmente usadas. Portanto, na aplicação web você geralmente encontrará chamadas para a função **`window.postMessage`** e, no script de conteúdo, ouvintes como **`window.addEventListener`**. Note, no entanto, que a extensão também pode **se comunicar com a aplicação web enviando uma Post Message** (e, portanto, a web deve esperar por isso) ou apenas fazer a web carregar um novo script.
|
|
|
|
### Dentro da extensão
|
|
|
|
Geralmente, a função **`chrome.runtime.sendMessage`** é usada para enviar uma mensagem dentro da extensão (geralmente tratada pelo script `background`) e, para recebê-la e manipulá-la, um ouvinte é declarado chamando **`chrome.runtime.onMessage.addListener`**.
|
|
|
|
Também é possível usar **`chrome.runtime.connect()`** para ter uma conexão persistente em vez de enviar mensagens únicas, é possível usá-la para **enviar** e **receber** **mensagens** como no seguinte exemplo:
|
|
|
|
<details>
|
|
|
|
<summary><code>chrome.runtime.connect()</code> exemplo</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>
|
|
|
|
Também é possível enviar mensagens de um script de fundo para um script de conteúdo localizado em uma aba específica chamando **`chrome.tabs.sendMessage`**, onde você precisará indicar o **ID da aba** para a qual enviar a mensagem.
|
|
|
|
### De `externally_connectable` permitido para a extensão
|
|
|
|
**Aplicativos da web e extensões de navegador externas permitidas** na configuração `externally_connectable` podem enviar solicitações usando:
|
|
```javascript
|
|
chrome.runtime.sendMessage(extensionId, ...
|
|
```
|
|
Onde é necessário mencionar o **extension ID**.
|
|
|
|
### Native Messaging
|
|
|
|
É possível que os scripts de fundo se comuniquem com binários dentro do sistema, que podem ser **susceptíveis a vulnerabilidades críticas, como RCEs**, se essa comunicação não for devidamente protegida. [Mais sobre isso mais tarde](./#native-messaging).
|
|
```javascript
|
|
chrome.runtime.sendNativeMessage(
|
|
'com.my_company.my_application',
|
|
{text: 'Hello'},
|
|
function (response) {
|
|
console.log('Received ' + response);
|
|
}
|
|
);
|
|
```
|
|
## Web **↔︎** Comunicação de Script de Conteúdo
|
|
|
|
Os ambientes onde os **scripts de conteúdo** operam e onde as páginas host existem são **separados** um do outro, garantindo **isolamento**. Apesar desse isolamento, ambos têm a capacidade de interagir com o **Modelo de Objeto de Documento (DOM)** da página, um recurso compartilhado. Para que a página host se envolva em comunicação com o **script de conteúdo**, ou indiretamente com a extensão através do script de conteúdo, é necessário utilizar o **DOM** que é acessível por ambas as partes como o canal de comunicação.
|
|
|
|
### Mensagens Post
|
|
|
|
{% code title="content-script.js" %}
|
|
```javascript
|
|
// 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);
|
|
```
|
|
{% endcode %}
|
|
|
|
{% code title="example.js" %}
|
|
```javascript
|
|
document.getElementById("theButton").addEventListener("click", () => {
|
|
window.postMessage(
|
|
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
|
|
}, false);
|
|
```
|
|
{% endcode %}
|
|
|
|
Uma comunicação segura de Post Message deve verificar a autenticidade da mensagem recebida, isso pode ser feito verificando:
|
|
|
|
* **`event.isTrusted`**: Isso é Verdadeiro apenas se o evento foi acionado por uma ação do usuário
|
|
* O script de conteúdo pode esperar uma mensagem apenas se o usuário realizar alguma ação
|
|
* **domínio de origem**: pode esperar uma mensagem apenas de uma lista de domínios permitidos.
|
|
* Se uma regex for usada, tenha muito cuidado
|
|
* **Fonte**: `received_message.source !== window` pode ser usado para verificar se a mensagem foi **da mesma janela** onde o Script de Conteúdo está ouvindo.
|
|
|
|
As verificações anteriores, mesmo que realizadas, podem ser vulneráveis, então verifique na página seguinte **potenciais bypasses de Post Message**:
|
|
|
|
{% content-ref url="../postmessage-vulnerabilities/" %}
|
|
[postmessage-vulnerabilities](../postmessage-vulnerabilities/)
|
|
{% endcontent-ref %}
|
|
|
|
### Iframe
|
|
|
|
Outra possível forma de comunicação pode ser através de **URLs de Iframe**, você pode encontrar um exemplo em:
|
|
|
|
{% content-ref url="browext-xss-example.md" %}
|
|
[browext-xss-example.md](browext-xss-example.md)
|
|
{% endcontent-ref %}
|
|
|
|
### DOM
|
|
|
|
Isso não é "exatamente" uma forma de comunicação, mas o **web e o script de conteúdo terão acesso ao DOM da web**. Portanto, se o **script de conteúdo** estiver lendo alguma informação dele, **confiando no DOM da web**, a web poderia **modificar esses dados** (porque a web não deve ser confiável, ou porque a web é vulnerável a XSS) e **comprometer o Script de Conteúdo**.
|
|
|
|
Você também pode encontrar um exemplo de um **XSS baseado em DOM para comprometer uma extensão de navegador** em:
|
|
|
|
{% content-ref url="browext-xss-example.md" %}
|
|
[browext-xss-example.md](browext-xss-example.md)
|
|
{% endcontent-ref %}
|
|
|
|
## Comunicação entre Script de Conteúdo **↔︎** Script de Fundo
|
|
|
|
Um Script de Conteúdo pode usar as funções [**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) para enviar uma mensagem **JSON-serializável de uma única vez**.
|
|
|
|
Para lidar com a **resposta**, use a **Promise** retornada. Embora, para compatibilidade retroativa, você ainda possa passar um **callback** como o último argumento.
|
|
|
|
Enviar uma solicitação de um **script de conteúdo** se parece com isso:
|
|
```javascript
|
|
(async () => {
|
|
const response = await chrome.runtime.sendMessage({greeting: "hello"});
|
|
// do something with response here, not outside the function
|
|
console.log(response);
|
|
})();
|
|
```
|
|
Enviando uma solicitação do **extension** (geralmente um **background script**). Exemplo de como enviar uma mensagem para o script de conteúdo na aba selecionada:
|
|
```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);
|
|
})();
|
|
```
|
|
No **lado receptor**, você precisa configurar um [**runtime.onMessage**](https://developer.chrome.com/docs/extensions/reference/runtime#event-onMessage) **ouvinte de eventos** para lidar com a mensagem. Isso parece o mesmo de um script de conteúdo ou página de extensão.
|
|
```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"});
|
|
}
|
|
);
|
|
```
|
|
No exemplo destacado, **`sendResponse()`** foi executado de forma síncrona. Para modificar o manipulador de eventos `onMessage` para a execução assíncrona de `sendResponse()`, é imperativo incorporar `return true;`.
|
|
|
|
Uma consideração importante é que, em cenários onde várias páginas estão configuradas para receber eventos `onMessage`, **a primeira página a executar `sendResponse()`** para um evento específico será a única capaz de entregar a resposta efetivamente. Quaisquer respostas subsequentes para o mesmo evento não serão levadas em conta.
|
|
|
|
Ao criar novas extensões, a preferência deve ser por promessas em vez de callbacks. Em relação ao uso de callbacks, a função `sendResponse()` é considerada válida apenas se for executada diretamente dentro do contexto síncrono, ou se o manipulador de eventos indicar uma operação assíncrona retornando `true`. Se nenhum dos manipuladores retornar `true` ou se a função `sendResponse()` for removida da memória (coletada pelo garbage collector), o callback associado à função `sendMessage()` será acionado por padrão.
|
|
|
|
## Native Messaging
|
|
|
|
As extensões do navegador também permitem comunicar-se com **binários no sistema via stdin**. O aplicativo deve instalar um json indicando isso em um json como:
|
|
```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/"]
|
|
}
|
|
```
|
|
Onde o `name` é a string passada para [`runtime.connectNative()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-connectNative) ou [`runtime.sendNativeMessage()`](https://developer.chrome.com/docs/extensions/reference/api/runtime#method-sendNativeMessage) para se comunicar com o aplicativo a partir dos scripts de fundo da extensão do navegador. O `path` é o caminho para o binário, há apenas 1 `type` válido que é stdio (use stdin e stdout) e os `allowed_origins` indicam as extensões que podem acessá-lo (e não podem ter wildcard).
|
|
|
|
O Chrome/Chromium irá procurar por este json em alguns registros do Windows e alguns caminhos no macOS e Linux (mais informações na [**docs**](https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging)).
|
|
|
|
{% hint style="success" %}
|
|
A extensão do navegador também precisa da permissão `nativeMessaing` declarada para poder usar essa comunicação.
|
|
{% endhint %}
|
|
|
|
Assim é como parece um código de script de fundo enviando mensagens para um aplicativo nativo:
|
|
```javascript
|
|
chrome.runtime.sendNativeMessage(
|
|
'com.my_company.my_application',
|
|
{text: 'Hello'},
|
|
function (response) {
|
|
console.log('Received ' + response);
|
|
}
|
|
);
|
|
```
|
|
Em [**este post do blog**](https://spaceraccoon.dev/universal-code-execution-browser-extensions/), um padrão vulnerável que abusa de mensagens nativas é proposto:
|
|
|
|
1. A extensão do navegador tem um padrão curinga para o script de conteúdo.
|
|
2. O script de conteúdo passa mensagens `postMessage` para o script de fundo usando `sendMessage`.
|
|
3. O script de fundo passa a mensagem para o aplicativo nativo usando `sendNativeMessage`.
|
|
4. O aplicativo nativo manipula a mensagem de forma perigosa, levando à execução de código.
|
|
|
|
E dentro dele, um exemplo de **como ir de qualquer página para RCE abusando de uma extensão do navegador é explicado**.
|
|
|
|
## Informações Sensíveis na Memória/Código/Área de Transferência
|
|
|
|
Se uma Extensão do Navegador armazena **informações sensíveis dentro de sua memória**, isso pode ser **extraído** (especialmente em máquinas Windows) e **procurado** por essas informações.
|
|
|
|
Portanto, a memória da Extensão do Navegador **não deve ser considerada segura** e **informações sensíveis** como credenciais ou frases mnemônicas **não devem ser armazenadas**.
|
|
|
|
Claro, **não coloque informações sensíveis no código**, pois isso será **público**.
|
|
|
|
Para extrair a memória do navegador, você pode **extrair a memória do processo** ou ir para as **configurações** da extensão do navegador clicando em **`Inspecionar pop-up`** -> Na seção **`Memória`** -> **`Tirar um instantâneo`** e **`CTRL+F`** para procurar dentro do instantâneo por informações sensíveis.
|
|
|
|
Além disso, informações altamente sensíveis como chaves mnemônicas ou senhas **não devem ser permitidas para serem copiadas na área de transferência** (ou pelo menos removê-las da área de transferência em poucos segundos) porque então processos que monitoram a área de transferência poderão obtê-las.
|
|
|
|
## Carregando uma Extensão no Navegador
|
|
|
|
1. **Baixe** a Extensão do Navegador & descompacte
|
|
2. Vá para **`chrome://extensions/`** e **ative** o `Modo de Desenvolvedor`
|
|
3. Clique no botão **`Carregar sem compactação`**
|
|
|
|
No **Firefox**, você vai para **`about:debugging#/runtime/this-firefox`** e clica no botão **`Carregar complemento temporário`**.
|
|
|
|
## Obtendo o código-fonte da loja
|
|
|
|
O código-fonte de uma extensão do Chrome pode ser obtido através de vários métodos. Abaixo estão explicações detalhadas e instruções para cada opção.
|
|
|
|
### Baixar Extensão como ZIP via Linha de Comando
|
|
|
|
O código-fonte de uma extensão do Chrome pode ser baixado como um arquivo ZIP usando a linha de comando. Isso envolve usar `curl` para buscar o arquivo ZIP de uma URL específica e, em seguida, extrair o conteúdo do arquivo ZIP para um diretório. Aqui estão os passos:
|
|
|
|
1. Substitua `"extension_id"` pelo ID real da extensão.
|
|
2. Execute os seguintes comandos:
|
|
```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"
|
|
```
|
|
### Use o site CRX Viewer
|
|
|
|
[https://robwu.nl/crxviewer/](https://robwu.nl/crxviewer/)
|
|
|
|
### Use a extensão CRX Viewer
|
|
|
|
Outro método conveniente é usar o Chrome Extension Source Viewer, que é um projeto de código aberto. Ele pode ser instalado na [Chrome Web Store](https://chrome.google.com/webstore/detail/chrome-extension-source-v/jifpbeccnghkjeaalbbjmodiffmgedin?hl=pt). O código-fonte do visualizador está disponível em seu [repositório GitHub](https://github.com/Rob--W/crxviewer).
|
|
|
|
### Ver o código-fonte da extensão instalada localmente
|
|
|
|
As extensões do Chrome instaladas localmente também podem ser inspecionadas. Veja como:
|
|
|
|
1. Acesse o diretório do seu perfil local do Chrome visitando `chrome://version/` e localizando o campo "Profile Path".
|
|
2. Navegue até a subpasta `Extensions/` dentro do diretório do perfil.
|
|
3. Esta pasta contém todas as extensões instaladas, tipicamente com seu código-fonte em um formato legível.
|
|
|
|
Para identificar extensões, você pode mapear seus IDs para nomes:
|
|
|
|
* Ative o Modo Desenvolvedor na página `about:extensions` para ver os IDs de cada extensão.
|
|
* Dentro da pasta de cada extensão, o arquivo `manifest.json` contém um campo `name` legível, ajudando você a identificar a extensão.
|
|
|
|
### Use um Arquivador de Arquivos ou Descompactador
|
|
|
|
Vá para a Chrome Web Store e baixe a extensão. O arquivo terá a extensão `.crx`. Altere a extensão do arquivo de `.crx` para `.zip`. Use qualquer arquivador de arquivos (como WinRAR, 7-Zip, etc.) para extrair o conteúdo do arquivo ZIP.
|
|
|
|
### Use o Modo Desenvolvedor no Chrome
|
|
|
|
Abra o Chrome e vá para `chrome://extensions/`. Ative "Modo desenvolvedor" no canto superior direito. Clique em "Carregar extensão descompactada...". Navegue até o diretório da sua extensão. Isso não baixa o código-fonte, mas é útil para visualizar e modificar o código de uma extensão já baixada ou desenvolvida.
|
|
|
|
## Conjunto de dados do manifesto da extensão do Chrome
|
|
|
|
Para tentar identificar extensões de navegador vulneráveis, você pode usar o [https://github.com/palant/chrome-extension-manifests-dataset](https://github.com/palant/chrome-extension-manifests-dataset) e verificar seus arquivos de manifesto em busca de sinais potencialmente vulneráveis. Por exemplo, para verificar extensões com mais de 25000 usuários, `content_scripts` e a permissão `nativeMessaing`:
|
|
|
|
{% code overflow="wrap" %}
|
|
```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')"
|
|
```
|
|
{% endcode %}
|
|
|
|
## Lista de Verificação de Auditoria de Segurança
|
|
|
|
Embora as Extensões de Navegador tenham uma **superfície de ataque limitada**, algumas delas podem conter **vulnerabilidades** ou **melhorias potenciais de endurecimento**. As seguintes são as mais comuns:
|
|
|
|
* [ ] **Limitar** o máximo possível as **`permissões`** solicitadas
|
|
* [ ] **Limitar** o máximo possível as **`host_permissions`**
|
|
* [ ] Usar uma **política de segurança de conteúdo** **`strong`**
|
|
* [ ] **Limitar** o máximo possível o **`externally_connectable`**, se nenhum for necessário e possível, não deixá-lo por padrão, especificar **`{}`**
|
|
* [ ] Se **URL vulnerável a XSS ou a takeover** for mencionada aqui, um atacante poderá **enviar mensagens para os scripts de fundo diretamente**. Um bypass muito poderoso.
|
|
* [ ] **Limitar** o máximo possível os **`web_accessible_resources`**, mesmo vazios, se possível.
|
|
* [ ] Se **`web_accessible_resources`** não for nenhum, verifique [**ClickJacking**](browext-clickjacking.md)
|
|
* [ ] Se qualquer **comunicação** ocorrer da **extensão** para a **página da web**, [**verifique por XSS**](browext-xss-example.md) **vulnerabilidades** causadas na comunicação.
|
|
* [ ] Se Post Messages forem usados, verifique por [**vulnerabilidades de Post Message**](../postmessage-vulnerabilities/)**.**
|
|
* [ ] Se o **Content Script acessar detalhes do DOM**, verifique se eles **não estão introduzindo um XSS** se forem **modificados** pela web
|
|
* [ ] Faça uma ênfase especial se essa comunicação também estiver envolvida na **comunicação do Content Script -> script de fundo**
|
|
* [ ] Se o script de fundo estiver se comunicando via **native messaging**, verifique se a comunicação é segura e sanitizada
|
|
* [ ] **Informações sensíveis não devem ser armazenadas** dentro do código da Extensão do Navegador
|
|
* [ ] **Informações sensíveis não devem ser armazenadas** dentro da memória da Extensão do Navegador
|
|
* [ ] **Informações sensíveis não devem ser armazenadas** dentro do **sistema de arquivos sem proteção**
|
|
|
|
## Riscos da Extensão do Navegador
|
|
|
|
* O aplicativo [https://crxaminer.tech/](https://crxaminer.tech/) analisa alguns dados, como as permissões que a extensão do navegador solicita, para dar um nível de risco ao uso da extensão do navegador.
|
|
|
|
## Ferramentas
|
|
|
|
### [**Tarnish**](https://thehackerblog.com/tarnish/)
|
|
|
|
* Extrai qualquer extensão do Chrome a partir de um link fornecido da Chrome webstore.
|
|
* Visualizador de [**manifest.json**](https://developer.chrome.com/extensions/manifest): simplesmente exibe uma versão JSON formatada do manifesto da extensão.
|
|
* Análise de Impressão Digital: Detecção de [web\_accessible\_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) e geração automática de JavaScript de impressão digital da extensão do Chrome.
|
|
* Análise Potencial de Clickjacking: Detecção de páginas HTML da extensão com a diretiva [web\_accessible\_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources) definida. Estas são potencialmente vulneráveis a clickjacking, dependendo do propósito das páginas.
|
|
* Visualizador de Aviso(s) de Permissão: que mostra uma lista de todos os avisos de prompt de permissão do Chrome que serão exibidos quando um usuário tentar instalar a extensão.
|
|
* Função(ões) Perigosa(s): mostra a localização de funções perigosas que poderiam ser potencialmente exploradas por um atacante (por exemplo, funções como innerHTML, chrome.tabs.executeScript).
|
|
* Ponto(s) de Entrada: mostra onde a extensão recebe entrada de usuário/externa. Isso é útil para entender a área de superfície de uma extensão e procurar pontos potenciais para enviar dados maliciosamente elaborados para a extensão.
|
|
* Tanto os scanners de Função(ões) Perigosa(s) quanto de Ponto(s) de Entrada têm o seguinte para seus alertas gerados:
|
|
* Trecho de código relevante e linha que causou o alerta.
|
|
* Descrição do problema.
|
|
* Um botão “Ver Arquivo” para visualizar o arquivo fonte completo contendo o código.
|
|
* O caminho do arquivo alertado.
|
|
* O URI completo da extensão do Chrome do arquivo alertado.
|
|
* O tipo de arquivo que é, como um script de Página de Fundo, Script de Conteúdo, Ação do Navegador, etc.
|
|
* Se a linha vulnerável estiver em um arquivo JavaScript, os caminhos de todas as páginas onde está incluída, bem como o tipo dessas páginas e o status de [web\_accessible\_resource](https://developer.chrome.com/extensions/manifest/web_accessible_resources).
|
|
* Analisador de Política de Segurança de Conteúdo (CSP) e verificador de bypass: Isso apontará fraquezas na CSP da sua extensão e também iluminará quaisquer maneiras potenciais de contornar sua CSP devido a CDNs na lista branca, etc.
|
|
* Bibliotecas Conhecidas Vulneráveis: Isso usa [Retire.js](https://retirejs.github.io/retire.js/) para verificar qualquer uso de bibliotecas JavaScript conhecidas como vulneráveis.
|
|
* Baixar extensão e versões formatadas.
|
|
* Baixar a extensão original.
|
|
* Baixar uma versão embelezada da extensão (HTML e JavaScript automaticamente formatados).
|
|
* Cache automático dos resultados da varredura, executar uma varredura de extensão levará um bom tempo na primeira vez que você a executar. No entanto, na segunda vez, assumindo que a extensão não foi atualizada, será quase instantâneo devido aos resultados estarem em cache.
|
|
* URLs de Relatório Linkáveis, facilmente vincule alguém a um relatório de extensão gerado pelo tarnish.
|
|
|
|
### [Neto](https://github.com/elevenpaths/neto)
|
|
|
|
O Projeto Neto é um pacote Python 3 concebido para analisar e desvendar recursos ocultos de plugins e extensões de navegador para navegadores bem conhecidos, como Firefox e Chrome. Ele automatiza o processo de descompactar os arquivos empacotados para extrair esses recursos de recursos relevantes em uma extensão, como `manifest.json`, pastas de localização ou arquivos fonte JavaScript e HTML.
|
|
|
|
## Referências
|
|
|
|
* **Agradecimentos a** [**@naivenom**](https://twitter.com/naivenom) **pela ajuda com esta metodologia**
|
|
* [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)
|
|
|
|
{% hint style="success" %}
|
|
Aprenda e pratique Hacking AWS:<img src="../../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../.gitbook/assets/arte.png" alt="" data-size="line">\
|
|
Aprenda e pratique Hacking GCP: <img src="../../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
|
|
|
<details>
|
|
|
|
<summary>Support HackTricks</summary>
|
|
|
|
* Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
|
|
* **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-nos no** **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.**
|
|
* **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|
|
{% endhint %}
|