Cross-Site Scripting (XSS)

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:

GitHub - payloadbox/xss-payload-list: 🎯 Cross Site Scripting ( XSS ) Vulnerability Payload List
🎯 Cross Site Scripting ( XSS ) Vulnerability Payload List - payloadbox/xss-payload-list

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

Cross Site Scripting (XSS) | OWASP Foundation
Cross Site Scripting (XSS) on the main website for The OWASP Foundation. OWASP is a nonprofit foundation that works to improve the security of software.
Cross-site scripting (XSS)
Cross-site scripting (XSS) is a web security vulnerability that enables an attacker to manipulate a vulnerable web site so that it returns malicious…
blog/chall-xss-basic at main · crowsec-edtech/blog
Repository for labs of the crowsec blog. Contribute to crowsec-edtech/blog development by creating an account on GitHub.

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!