Cross-Site Scripting (XSS)
Neste artigo, veremos sobre Cross-site Scripting (XSS). Essa vulnerabilidade ocorre em diversas aplicações modernas e atuais. Em alguns cenários, pode ser extremamente crítica, podendo levar até mesmo a um Account Takeover.
O que é Cross-site Scripting (XSS)?
O XSS é uma vulnerabilidade que permite que atacantes possam executar scripts maliciosos em uma página confiável e legítima. O fator que leva a aplicação ficar vulnerável a esse tipo de ataque é: Falta de sanitização dos dados inseridos pelo usuário.
Quando a aplicação não faz a devida sanitização dos dados inseridos pelo usuário e reflete esses dados de maneira "insegura" na página, um usuário pode injetar tanto tags HTML quanto códigos JavaScript, assim sendo possível alterar o comportamento da página.
Tipos conhecidos de XSS
- XSS Reflected: Ocorre quando a resposta da requisição HTTP retorna uma página HTML com o input malicioso inserido pelo atacante no conteúdo dela.
- XSS DOM-Based: Ocorre quando um código JavaScript obtém dados controlados pelo usuário e os reflete na página utilizando uma função insegura, como "document.write()".
- XSS Stored: Ocorre quando a aplicação está vulnerável a XSS (seja Reflected ou DOM-Based) e armazena o input do usuário na página, tornando possível armazenar uma payload de XSS em uma página legítima.
- XSS Blind: Ocorre quando a aplicação está vulnerável a XSS Stored e a payload inserida pelo atacante é armazenada em uma página à qual ele não tem acesso, tornando o ataque do tipo "blind".
Explorando XSS na prática
Aqui vamos explorar todos os tipos de XSS mencionados na seção acima, exceto o XSS Blind, pois segue o mesmo conceito do XSS Stored.
XSS Reflected
Como vimos anteriormente, esse tipo de XSS ocorre quando a aplicação retorna uma página HTML com o input malicioso contido no conteúdo dela.
Veja um exemplo de um código PHP vulnerável a XSS Reflected:
Vemos que a aplicação recebe o parâmetro "name" na URL, e o reflete na página HTML sem fazer nenhuma sanitização. Isso possibilita com que um atacante injete novas tags e scripts na página através do parâmetro.
Enviando um nome no parâmetro "name", vemos que o mesmo é refletido:
Enviando uma tag HTML, vemos que ela é interpretada pelo browser:
Além da possibilidade de injetarmos tags HTML na página, conseguimos executar códigos JavaScript:
Vemos que a exploração da vulnerabilidade é extremamente simples. Em alguns casos, os parâmetros da aplicação são filtrados, dificultando a exploração. Porém, muitas vezes, ainda é possível executar códigos JavaScript por meio de técnicas para burlar esses filtros.
Abaixo, vemos um código PHP que filtra o conteúdo do parâmetro "name", assim dificultando (porém não impossibilitando, pois o mesmo é inseguro) a execução de código JavaScript na página:
Se enviarmos um código JavaScript no parâmetro "name", vemos que a aplicação identifica o ataque:
Porém, podemos utilizar outras tags para chegar a execução de código JavaScript. Veja alguns exemplos de payloads abaixo:
<img src=x onerror="console.log('pwned')">
Essa payload consiste em: carregar uma imagem inexistente, e utilizar a propriedade "onerror" para fazer a execução de um código JavaScript
<svg onload="console.log('pwned')">
Essa payload consiste em: utilizar a propriedade "onload" da tag "svg" para fazer a execução de um código JavaScript
<video src=x onerror="console.log('pwned')">
Essa payload consiste em: carregar um vídeo inexistente, e utilizar a propriedade "onerror" para fazer a execução de um código JavaScript
Existem centenas de payloads que podem ser utilizadas para burlar filtros mal implementados. Algumas delas são encontradas em repositórios do github, como este:
Em alguns casos, precisamos fazer uma análise do filtro implementado na aplicação, e criarmos uma payload customizada para fazer o bypass dela.
Veja o exemplo abaixo:
O código está fazendo replace da string "<script>" por uma string nula, ou seja, está removendo a tag do input do usuário.
Vemos que enviando uma payload de XSS comum, a aplicação faz a devida sanitização:
Porém, o filtro implementado não é seguro, pois podemos confundir a lógica da função de replace para burlarmos o filtro.
Enviando a seguinte payload, conseguimos executar um código JavaScript na página:
<scr<script>ipt>console.log('pwned')</script>
Veja que quando a função de replace for executada, ela vai removar a tag "<script>", e quando isso ocorrer, a string resultante será: <script>console.log('pwned')</script>
.
Agora que conhecemos o básico, podemos estudar os outros tipos, como DOM-Based, Stored e Blind XSS.
XSS DOM-Based
Como dito anteriormente, o XSS DOM-Based ocorre quando um código JavaScript da página reflete um conteúdo controlado por um usuário de maneira insegura, e sem fazer sanitização.
Veja um exemplo de código vulnerável abaixo:
O código obtém o conteúdo do input "name", e o reflete na página utilizando a função "document.write()". Isso nos possibilita injetar tags e códigos JavaScript.
Enviando um input comum:
Enviando uma payload de XSS utilizando a tag "<script>":
Além da função "document.write()", existem diversas funções que também são inseguras para refletir dados inseridos por usuários. Algumas são:
- document.write()
- document.writeln()
- document.domain
- element.innerHTML
- element.outerHTML
- element.insertAdjacentHTML
- element.onevent
Veja um exemplo de código vulnerável que utiliza "innerHTML":
Enviando payload de XSS:
Observação: Em alguns casos de uso, como "innerHTML", "outerHTML" e outras funções, a tag "<script>" não é interpretada, porém ainda podemos fazer a utilização de outras tags em conjunto com as propriedades "onerror", "onhover", entre outras.
XSS Stored
Casos em que o input do usuário fica armazenado na aplicação, e a mesma reflete-os de maneira insegura e sem fazer a devida sanitização, podemos classificar o XSS como Stored. Existem dois tipos de "XSS Stored":
- XSS Stored - Reflected: Ocorre quando a aplicação está vulnerável a XSS Reflected, porém, faz a persistência dos dados.
- XSS Stored - DOM-Based: Ocorre quando a aplicação está vulnerável a XSS DOM-Based, porém, faz a persistência dos dados.
Vemos que a aplicação da imagem abaixo, faz a persistência dos comentários na página, o que a torna vulnerável a XSS Stored:
Analisando o código JavaScript da página, vemos que o mesmo utiliza a função "innerHTML" para inserir os comentários na página, e além disso, não faz nenhuma sanitização nos dados:
Enviando um comentário com a payload abaixo, conseguimos executar código JavaScript na página:
<img src=x onerror="console.log('pwned')">
Nesse cenários, nos encontramos um XSS Stored - DOM-Based, pois utiliza funções "inseguras" do DOM para refletir os dados.
Causando impactos significativos com XSS
Até nesse momento, vimos exemplos de explorações simples de XSS, porém, com a execução de códigos JavaScript na página, podemos fazer centenas de coisas maliciosas. Algumas delas são:
- Criar novos campos na página para campanhas de phishing
- Roubar sessões do navegador da vítima
- Controlar o console do navegador da vítima
- Redirecionar a vítima para um site malicioso
Veja o código da imagem abaixo:
Vemos que o código cria dois prompts para obter as credenciais do usuário, e depois faz uma requisição para o servidor do atacante (nesse caso, foi para localhost:8000), enviando as mesmas no parâmetro "data".
Utilizamos o cyberchef para fazer o base64 encoding desse código, assim não teremos problema de sintaxe ao enviar o código em uma payload de XSS.
Para executarmos o código, podemos fazer a seguinte payload:
<img src=x onerror="eval(atob('BASE64 HERE'))">
Recarregando a página, vemos os seguintes prompts em nossa tela:
Ao enviar as informações, recebemos as mesmas em nosso servidor que está sendo executado na porta 8000:
Corrigindo o XSS
Para corrigir o XSS, podemos utilizar bibliotecas de sanitização, como DomPurify, ou podemos fazer o HTML Encoding dos dados, assim, impossibilitando com que o browser interprete as tags maliciosas inseridas pelo atacante.
Veja abaixo um exemplo de código utilizando a função de HTML Encoding (utilizada na linha 8):
Enviando uma payload de XSS no parâmetro "name", vemos que a mesma não é interpretada pelo navegador:
Referências
Onde praticar Cross-site Scripting ?
Atualmente o hackingclub possuí diversos labs em que podem ser explorados Cross-site Scripting (XSS), em diversos contextos e linguagens diferentes.
O Hacking Club é uma plataforma de treinamento em cybersecurity, que permite você aprender hacking de forma totalmente prática.
Temos mais de 200 ambientes com vulnerabilidades reais com write-ups para você treinar e aprender hacking.
Semanalmente lançamos máquinas gratuitas para você praticar e se desafiar no hacking!
Se registre gratuitamente!