Browser Extension Pentesting Methodology
Informações Básicas
As extensões de navegador são escritas em JavaScript e carregadas pelo navegador em segundo plano. Elas têm seu DOM, mas podem interagir com os DOMs de outros sites. Isso significa que podem comprometer a confidencialidade, integridade e disponibilidade (CIA) de outros sites.
Componentes Principais
Os layouts de extensão são mais bem visualizados e consistem em três componentes. Vamos analisar cada componente em profundidade.
Scripts de Conteúdo
Cada script de conteúdo tem acesso direto ao DOM de uma única página da web e, portanto, está 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 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) usada pelo Flash e outros plug-ins de navegador.
Limites
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.
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
manifest.json
Uma extensão do Chrome é apenas uma pasta ZIP com uma .crx file extension. 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:
content_scripts
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) da página.
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 for usada para recuperar o valor message
do armazenamento da extensão.
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. Isso se deve à limitação do script de conteúdo em acessar diretamente as APIs, 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.
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, e para o Firefox, o MDN 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.
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 a exibição das ferramentas de desenvolvedor, 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
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 controles mais granulares.
Para a injeção programática de um script de conteúdo, a extensão deve ter permissões de host 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.
Exemplo de extensão baseada em activeTab
Injetar um arquivo JS ao clicar:
Injetar uma função ao clicar:
Exemplo com permissões de script
Para incluir ou excluir mais URLs, também é possível usar include_globs
e exclude_globs
.
Content Scripts run_at
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íveldocument_start
: Após quaisquer arquivos decss
, 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
manifest.json
Via service-worker.js
background
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.
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.
Exemplo de script de fundo:
Utiliza a runtime.onMessage API para escutar mensagens. Quando uma mensagem "explain"
é recebida, utiliza a tabs API 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:
Páginas de opções e outras
As extensões de 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:
Note que essas páginas não são persistentes como as páginas de fundo, pois carregam conteúdo dinamicamente conforme a necessidade. 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
& 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 de 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:
BrowExt - permissions & host_permissionscontent_security_policy
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 de navegador é bastante restritiva:
Para mais informações sobre CSP e possíveis contornos, consulte:
Content Security Policy (CSP) Bypassweb_accessible_resources
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:
Estas páginas são acessíveis em URL como:
Em extensões públicas, o extension-id é acessível:
No entanto, se o parâmetro manifest.json
use_dynamic_url
for utilizado, este id pode ser dinâmico.
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.
Ter acesso a essas páginas torna essas páginas potencialmente vulneráveis a ClickJacking:
BrowExt - ClickJackingPermitir que essas páginas sejam carregadas apenas pela extensão e não por URLs aleatórias poderia prevenir ataques de ClickJacking.
Observe que as páginas de web_accessible_resources
e outras páginas da extensão também são capazes de contatar scripts de fundo. 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 a partir 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
.
externally_connectable
externally_connectable
De acordo com a docs, a propriedade de manifesto "externally_connectable"
declara quais extensões e páginas da web podem se conectar à sua extensão via runtime.connect e runtime.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:
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.
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 página para um arquivo JavaScript. (Observe que o CSP na página alvo pode prevenir esses ataques). Esta ideia vem deste writeup.
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: