# CORS - Configurações Incorretas e Bypass
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥 * Você trabalha em uma **empresa de segurança cibernética**? Você quer ver sua **empresa anunciada no HackTricks**? ou você quer ter acesso à **última versão do PEASS ou baixar o HackTricks em PDF**? Verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)! * Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family) * Adquira o [**swag oficial do PEASS & HackTricks**](https://peass.creator-spring.com) * **Junte-se ao** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga-me** no **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks\_live)**.** * **Compartilhe suas técnicas de hacking enviando PRs para o** [**repositório hacktricks**](https://github.com/carlospolop/hacktricks) **e para o** [**repositório hacktricks-cloud**](https://github.com/carlospolop/hacktricks-cloud).
## O que é CORS? O padrão CORS (Compartilhamento de Recursos de Origem Cruzada) é necessário porque ele **permite que servidores especifiquem quem pode acessar seus ativos** e quais **métodos de solicitação HTTP são permitidos** a partir de recursos externos. Uma política de **mesma origem** requer que tanto o **servidor solicitante** de um recurso quanto o servidor onde o **recurso** está localizado usem o mesmo protocolo ([http://), nome de domínio](http://\), nome de domínio) e a mesma **porta** (80). Então, se o servidor força a política de mesma origem, apenas páginas da web do mesmo domínio e porta poderão acessar os recursos. A tabela a seguir mostra como a política de mesma origem será aplicada em `http://normal-website.com/example/example.html` : | URL acessada | Acesso permitido? | | ----------------------------------------- | ---------------------------------- | | `http://normal-website.com/example/` | Sim: mesmo esquema, domínio e porta | | `http://normal-website.com/example2/` | Sim: mesmo esquema, domínio e porta | | `https://normal-website.com/example/` | Não: esquema e porta diferentes | | `http://en.normal-website.com/example/` | Não: domínio diferente | | `http://www.normal-website.com/example/` | Não: domínio diferente | | `http://normal-website.com:8080/example/` | Não: porta diferente\* | \*_O Internet Explorer permitirá esse acesso porque o IE não leva em conta o número da porta ao aplicar a política de mesma origem._ ### Cabeçalho `Access-Control-Allow-Origin` A especificação de `Access-Control-Allow-Origin` permite **múltiplas origens**, ou o valor **`null`**, ou o caractere coringa **`*`**. No entanto, **nenhum navegador suporta múltiplas origens** e há **restrições** no uso do **coringa** `*`. (_O caractere coringa só pode ser usado sozinho, isso falhará `Access-Control-Allow-Origin: https://*.normal-website.com` e não pode ser usado com_ _Access-Control-Allow-Credentials: true_) Este cabeçalho é **retornado por um servidor** quando um site solicita um recurso de outro domínio, com um cabeçalho `Origin` adicionado pelo navegador. ### Cabeçalho `Access-Control-Allow-Credentials` O comportamento **padrão** das solicitações de recursos de origem cruzada é que as **solicitações** sejam **passadas sem credenciais** como cookies e o cabeçalho de autorização. No entanto, o servidor de origem cruzada pode **permitir a leitura** da **resposta** quando as **credenciais** são **passadas** para ele definindo o cabeçalho CORS **`Access-Control-Allow-Credentials`** como **`true`**. Se o valor for definido como `true`, o navegador enviará credenciais (cookies, cabeçalhos de autorização ou certificados de cliente TLS). ```javascript var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { console.log(xhr.responseText); } } xhr.open('GET', 'http://example.com/', true); xhr.withCredentials = true; xhr.send(null); ``` ```javascript fetch(url, { credentials: 'include' }) ``` ```javascript const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://bar.other/resources/post-here/'); xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); xhr.setRequestHeader('Content-Type', 'application/xml'); xhr.onreadystatechange = handler; xhr.send('Arun'); ``` ### Pedido de pré-voo Em certas circunstâncias, quando um pedido de domínio cruzado: * inclui um **método HTTP não padrão (HEAD, GET, POST)** * inclui novos **cabeçalhos** * inclui um valor de cabeçalho **Content-Type especial** {% hint style="info" %} **Verifique** [**neste link**](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple\_requests) **as condições de um pedido para evitar o envio de um pedido de pré-voo** {% endhint %} o pedido de origem cruzada é precedido por um **pedido** usando o método **`OPTIONS`**, e o protocolo CORS exige uma verificação inicial sobre quais **métodos e cabeçalhos são permitidos antes de permitir o pedido de origem cruzada**. Isso é chamado de **verificação de pré-voo**. O servidor **retorna uma lista de métodos permitidos** além da **origem confiável** e o navegador verifica se o método do site solicitante é permitido. {% hint style="danger" %} Observe que, **mesmo que um pedido de pré-voo não seja enviado** porque as condições do "pedido regular" são respeitadas, a **resposta precisa ter os cabeçalhos de autorização** ou o **navegador não poderá ler a resposta** do pedido. {% endhint %} Por **exemplo**, este é um pedido de pré-voo que está buscando **usar o método `PUT`** juntamente com um **cabeçalho de pedido personalizado** chamado `Special-Request-Header`: ``` OPTIONS /data HTTP/1.1 Host: ... Origin: https://normal-website.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: Special-Request-Header ``` O servidor pode retornar uma resposta como a seguinte: ``` HTTP/1.1 204 No Content ... Access-Control-Allow-Origin: https://normal-website.com Access-Control-Allow-Methods: PUT, POST, OPTIONS Access-Control-Allow-Headers: Special-Request-Header Access-Control-Allow-Credentials: true Access-Control-Max-Age: 240 ``` * `Access-Control-Allow-Headers` Cabeçalhos permitidos * `Access-Control-Expose-Headers` Cabeçalhos expostos * `Access-Control-Max-Age` Define um período máximo para armazenar em cache a resposta pré-voo para reutilização * `Access-Control-Request-Headers` O cabeçalho que a solicitação de origem cruzada deseja enviar * `Access-Control-Request-Method` O método que a solicitação de origem cruzada deseja usar * `Origin` Origem da solicitação de origem cruzada (definido automaticamente pelo navegador) ![](../.gitbook/assets/preflight.svg) Observe que geralmente (dependendo do tipo de conteúdo e cabeçalhos definidos) em uma solicitação **GET/POST, nenhuma solicitação pré-voo é enviada** (a solicitação é enviada **diretamente**), mas se você quiser acessar os **cabeçalhos/corpo da resposta**, ela deve conter um cabeçalho _Access-Control-Allow-Origin_ permitindo isso.\ **Portanto, o CORS não protege contra CSRF (mas pode ser útil).** ### **Solicitação pré-voo de rede local** Quando uma solicitação é enviada para um endereço IP de rede local, 2 cabeçalhos CORS adicionais são enviados: * O cabeçalho de solicitação do cliente `Access-Control-Request-Local-Network` indica que a solicitação é uma solicitação de rede local * O cabeçalho de resposta do servidor `Access-Control-Allow-Local-Network` indica que um recurso pode ser compartilhado com segurança com redes externas Uma **resposta válida permitindo a solicitação de rede local** também precisa ter na resposta o cabeçalho `Access-Controls-Allow-Local_network: true`: ``` HTTP/1.1 200 OK ... Access-Control-Allow-Origin: https://public.example.com Access-Control-Allow-Methods: GET Access-Control-Allow-Credentials: true Access-Control-Allow-Local-Network: true Content-Length: 0 ... ``` {% hint style="warning" %} Observe que o IP linux **0.0.0.0** funciona para **burlar** esses requisitos para acessar o localhost, pois esse endereço IP não é considerado "local". Também é possível **burlar os requisitos da Rede Local** se você usar o **endereço IP público de um endpoint local** (como o IP público do roteador). Porque em várias ocasiões, mesmo que o **IP público** seja acessado, se for **da rede local**, o acesso será concedido. {% endhint %} ## Configurações incorretas exploráveis Observe que a maioria dos **ataques reais requer que `Access-Control-Allow-Credentials`** seja definido como **`true`** porque isso permitirá que o navegador envie as credenciais e leia a resposta. Sem credenciais, muitos ataques se tornam irrelevantes; isso significa que você não pode usar os cookies do usuário, então muitas vezes não há nada a ser ganho fazendo com que o navegador deles emita a solicitação em vez de emitir você mesmo. Uma exceção notável é quando a **localização da rede da vítima funciona como uma espécie de autenticação**. Você pode usar o navegador da vítima como um proxy para ignorar a autenticação baseada em IP e acessar aplicativos de intranet. Em termos de impacto, isso é semelhante ao DNS rebinding, mas muito menos complicado de explorar. ### Reflected `Origin` in `Access-Control-Allow-Origin` No mundo real, isso não pode acontecer, pois **esses 2 valores dos cabeçalhos são proibidos juntos**.\ Também é verdade que muitos desenvolvedores desejam **permitir vários URLs no CORS**, mas curingas de subdomínio ou listas de URLs não são permitidos. Então, vários desenvolvedores **geram** o cabeçalho \*\*`Access-Control-Allow-Origin`\*\* **dinamicamente**, e em mais de uma ocasião eles apenas **copiam o valor do cabeçalho Origin**. Nesse caso, a **mesma vulnerabilidade pode ser explorada.** Em outros casos, o desenvolvedor poderia verificar se o **domínio** (_victimdomain.com_) **aparece** no cabeçalho Origin, então, um atacante pode usar um domínio chamado **`attackervictimdomain.com`** para roubar informações confidenciais. ```html ``` ### A Origem `null` `null` é um valor especial para o cabeçalho **Origin**. A especificação menciona que ele é acionado por redirecionamentos e arquivos HTML locais. Algumas aplicações podem permitir a origem `null` na lista branca para suportar o desenvolvimento local da aplicação.\ Isso é interessante porque **várias aplicações permitirão esse valor** dentro do CORS e qualquer **site pode facilmente obter a origem nula usando um iframe isolado**: ```html ``` ```html ``` ### **Burlas de Regexp** Se você descobriu que o domínio _victim.com_ está na **lista branca**, você deve verificar se _victim.com.**attacker.com**_ também está na **lista branca**, ou, caso você possa **assumir algum subdomínio**, verifique se _**somesubdomain**.victim.com_ está na lista branca. ### **Burlas de Regexp Avançadas** A maioria das expressões regulares usadas para identificar o domínio dentro da string se concentrará em caracteres alfanuméricos ASCII e `.-`. Então, algo como `victimdomain.com{.attacker.com` dentro do cabeçalho de Origem será interpretado pela expressão regular como se o domínio fosse `victimdomain.com`, mas o navegador (neste caso, o Safari suporta esse caractere no domínio) acessará o domínio `attacker.com`. O caractere `_` (em subdomínios) não é apenas suportado no Safari, mas também no Chrome e no Firefox! **Então, usando um desses subdomínios, você pode burlar algumas expressões regulares "comuns" para encontrar o domínio principal de uma URL.** **Para obter mais informações e configurações dessa burla, consulte:** [**https://www.corben.io/advanced-cors-techniques/**](https://www.corben.io/advanced-cors-techniques/) **e** [**https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397**](https://medium.com/bugbountywriteup/think-outside-the-scope-advanced-cors-exploitation-techniques-dad019c68397) ![](<../.gitbook/assets/image (153).png>) ### A partir de XSS dentro de um subdomínio Um mecanismo de defesa que os desenvolvedores usam contra a exploração do CORS é listar em branco os domínios que frequentemente solicitam acesso a informações. No entanto, isso não é totalmente seguro, porque se **um** dos subdomínios do domínio **listado em branco** for **vulnerável** a outros exploits, como **XSS**, ele pode permitir a exploração do CORS. Vamos considerar um exemplo, o código a seguir mostra a configuração que permite que subdomínios de _requester.com_ acessem recursos de _provider.com_. ```javascript if ($_SERVER['HTTP_HOST'] == '*.requester.com') { //Access data else{ // unauthorized access} } ``` Supondo que um usuário tenha acesso a sub.requester.com, mas não a requester.com, e supondo que `sub.requester.com` seja vulnerável a XSS. O usuário pode explorar `provider.com` usando o método de ataque de script entre sites. ### **Envenenamento de cache do lado do servidor** Se as estrelas estiverem alinhadas, podemos usar o envenenamento de cache do lado do servidor via injeção de cabeçalho HTTP para criar uma vulnerabilidade [XSS armazenada](https://portswigger.net/web-security/cross-site-scripting/stored). Se um aplicativo **reflete** o **cabeçalho de origem** sem nem mesmo verificá-lo quanto a caracteres ilegais como `,` efetivamente temos uma vulnerabilidade de injeção de cabeçalho HTTP contra usuários do IE/Edge, já que o Internet Explorer e o Edge veem \r (0x0d) como um terminador de cabeçalho HTTP válido: `GET / HTTP/1.1`\ `Origin: z[0x0d]Content-Type: text/html; charset=UTF-7` O Internet Explorer vê a resposta como: `HTTP/1.1 200 OK`\ `Access-Control-Allow-Origin: z`\ `Content-Type: text/html; charset=UTF-7` Isso não é diretamente explorável porque não há como um invasor fazer o navegador web de alguém enviar um cabeçalho malformado como esse, mas eu posso **criar manualmente essa solicitação no Burp Suite e um cache do lado do servidor pode salvar a resposta e servi-la para outras pessoas**. O payload que usei mudará o conjunto de caracteres da página para **UTF-7**, que é notoriamente útil para criar vulnerabilidades XSS. ### **Envenenamento de cache do lado do cliente** Você pode ter encontrado ocasionalmente uma página com [XSS refletido](https://portswigger.net/web-security/cross-site-scripting/reflected) em um cabeçalho HTTP personalizado. Digamos que uma página da web reflita o conteúdo de um cabeçalho personalizado sem codificação: ```http GET / HTTP/1.1 Host: example.com X-User-id: <svg/onload=alert\(1\)> HTTP/1.1 200 OK Access-Control-Allow-Origin: \* Access-Control-Allow-Headers: X-User-id Content-Type: text/html ... Invalid user: <svg/onload=alert\(1\)>\ ``` Com o CORS, podemos enviar qualquer valor no Header. Por si só, isso é inútil, já que a resposta contendo nosso JavaScript injetado não será renderizada. No entanto, se Vary: Origin não tiver sido especificado, a resposta pode ser armazenada no cache do navegador e exibida diretamente quando o navegador navegar para a URL associada. Eu criei um fiddle para tentar esse ataque em uma URL de sua escolha. Como esse ataque usa o cache do lado do cliente, ele é bastante confiável. ```markup ``` ## Bypass ### XSSI (Inclusão de Script entre Sites) / JSONP XSSI designa um tipo de vulnerabilidade que explora o fato de que, quando um recurso é incluído usando a tag `script`, a SOP não se aplica, porque os scripts devem ser capazes de serem incluídos entre domínios. Um atacante pode, assim, ler tudo o que foi incluído usando a tag `script`. Isso é especialmente interessante quando se trata de JavaScript dinâmico ou JSONP, quando informações de autoridade ambiental, como cookies, são usadas para autenticação. Os cookies são incluídos ao solicitar um recurso de um host diferente. Plugin do BurpSuite: [https://github.com/kapytein/jsonp](https://github.com/kapytein/jsonp) [**Leia mais sobre os diferentes tipos de XSSI e como explorá-los aqui.**](xssi-cross-site-script-inclusion.md) Tente adicionar um **parâmetro de retorno de chamada** (**`callback`**) na solicitação. Talvez a página tenha sido preparada para enviar os dados como JSONP. Nesse caso, a página enviará de volta os dados com `Content-Type: application/javascript`, o que contornará a política CORS. ![](<../.gitbook/assets/image (229).png>) ### Bypass fácil (inútil?) Você pode pedir a um aplicativo da web para fazer uma solicitação para você e enviar de volta a resposta. Isso contornará o **`Access-Control-Allow-Origin`**, mas observe que as **credenciais para a vítima final não serão enviadas** porque você estará **entrando em contato com um domínio diferente** (aquele que fará a solicitação para você). [**CORS-escape**](https://github.com/shalvah/cors-escape) CORS-escape fornece um **proxy** que **encaminha** nossa **solicitação** juntamente com seus **cabeçalhos**, e também **finge** o cabeçalho **Origin** (Origin = **domínio solicitado**). Assim, a **política CORS é contornada**.\ O código-fonte está [no Github](https://github.com/shalvah/cors-escape), para que você possa **hospedar o seu próprio**. ```javascript xhr.open("GET", "https://cors-escape.herokuapp.com/https://maximum.blog/@shalvah/posts"); ``` [**simple-cors-escape**](https://github.com/shalvah/simple-cors-escape) Proxying é como "passar" sua solicitação, exatamente como você a enviou. Poderíamos resolver isso de uma maneira alternativa que ainda envolve outra pessoa fazendo a solicitação para você, mas desta vez, **em vez de passar sua solicitação, o servidor faz sua própria solicitação, mas com os parâmetros que você especificou.** ### Bypass de Iframe + Popup Você pode **burlar verificações CORS** como `e.origin === window.origin` **criando um iframe** e **a partir dele abrindo uma nova janela**. Mais informações na seguinte página: {% content-ref url="xss-cross-site-scripting/iframes-in-xss-and-csp.md" %} [iframes-in-xss-and-csp.md](xss-cross-site-scripting/iframes-in-xss-and-csp.md) {% endcontent-ref %} ### DNS Rebinding via TTL ![](<../.gitbook/assets/image (108).png>) Basicamente, você faz a **vítima acessar sua página**, então você muda o **DNS do seu domínio (o IP)** e faz com que ele **aponte** para a **página da web da vítima**. Você faz sua **vítima executar** (**JS**) algo quando o **TTL acabar** para que uma nova solicitação DNS seja feita e, em seguida, você poderá coletar as informações (como você sempre mantém o usuário em seu domínio, ele não enviará nenhum cookie para o servidor da vítima, então essa opção **abusa dos privilégios especiais do IP da vítima**). Mesmo que você defina o **TTL muito baixo** (0 ou 1), os **navegadores têm um cache** que **impedirá** que você **abusar** disso por vários segundos / minutos. Portanto, essa técnica é útil para **burlar verificações explícitas** (a vítima está **realizando explicitamente uma solicitação DNS** para verificar o IP do domínio e quando o bot é chamado, ele fará o seu próprio). Ou quando você pode ter um **usuário / bot na mesma página por um longo tempo** (para que você possa **esperar** até que o **cache expire**). Se você precisar de algo rápido para abusar disso, pode usar um serviço como [https://lock.cmpxchg8b.com/rebinder.html](https://lock.cmpxchg8b.com/rebinder.html). Se você quiser executar seu próprio servidor de DNS rebinding, pode usar algo como [**DNSrebinder**](https://github.com/mogwailabs/DNSrebinder)**,** em seguida, **expor** a **porta local 53/udp**, criar um **registro A apontando para ele** (ns.example.com) e criar um **registro NS** apontando para o **subdomínio A criado anteriormente** (ns.example.com).\ Então, qualquer subdomínio desse subdomínio (ns.example.com) será resolvido pelo seu host. Confira também o **servidor em execução publicamente em** [**http://rebind.it/singularity.html**](http://rebind.it/singularity.html) ### DNS Rebinding via **DNS Cache Flooding** Como foi explicado na seção anterior, os **navegadores** têm os IPs dos domínios **armazenados em cache por mais tempo** do que o especificado no TTL. No entanto, há uma maneira de burlar essa defesa. Você pode ter um trabalhador de serviço que **inunda o cache DNS para forçar uma segunda solicitação DNS**. Então, o fluxo será como: 1. Solicitação DNS respondida com o endereço do atacante 2. O trabalhador de serviço inunda o cache DNS (o nome do servidor atacante em cache é excluído) 3. Segunda solicitação DNS, desta vez respondida com 127.0.0.1 ![](<../.gitbook/assets/image (375) (1).png>) _Azul é a primeira solicitação DNS e laranja é a inundação._ ### DNS Rebinding via **Cache** Como foi explicado na seção anterior, os **navegadores** têm os IPs dos domínios **armazenados em cache por mais tempo** do que o especificado no TTL. No entanto, há outra maneira de burlar essa defesa. Você pode **criar 2 registros A** (ou **1 com 2 IPs**, dependendo do provedor) para o **mesmo subdomínio** no **provedor DNS** e quando um navegador os verifica, ele receberá ambos. Agora, se o **navegador** decidir **usar o endereço IP do atacante primeiro**, o **atacante** poderá **servir** a **carga útil** que **realizará solicitações HTTP** para o mesmo **domínio**. No entanto, agora que o atacante conhece o IP da vítima, **ele deixará de responder ao navegador da vítima**. Quando o navegador descobrir que o **domínio não está respondendo** a ele, ele **usará o segundo IP fornecido**, então ele **acessará um lugar diferente, burlando o SOP**. O atacante pode abusar disso para **obter as informações e exfiltrá-las**. {% hint style="warning" %} Observe que, para acessar o localhost, você deve tentar restringir **127.0.0.1** no Windows e **0.0.0.0** no Linux.\ Provedores como godaddy ou cloudflare não me permitiram usar o IP 0.0.0.0, mas a AWS route53 me permitiu criar um registro A com 2 IPs, sendo um deles "0.0.0.0" {% endhint %} ![](<../.gitbook/assets/image (620) (4).png>) Para mais informações, você pode verificar [https://unit42.paloaltonetworks.com/dns-rebinding/](https://unit42.paloaltonetworks.com/dns-rebinding/) ### Outros Bypasses Comuns * Se **endereços IP internos não são permitidos**, eles podem **ter esquecido de proibir 0.0.0.0** (funciona no Linux e no Mac) * Se **endereços IP internos não são permitidos**, responda com um **CNAME** para **localhost