WAF através dos olhos de hackers

Hoje vamos falar sobre um dos modernos mecanismos de segurança para aplicativos da Web, o Web Application Firewall (WAF). Discutiremos as WAFs modernas e em que elas se baseiam, além de técnicas de desvio, como usá-las e por que você nunca deve confiar inteiramente na WAF. Estamos falando da perspectiva dos pentesters; nunca desenvolvemos WAFs e apenas coletamos dados de fontes abertas. Assim, podemos apenas nos referir à nossa própria experiência e podemos desconhecer algumas peculiaridades das WAFs.




Isenção de responsabilidade: esta é uma tradução do artigo de russo para inglês, o artigo foi lançado no final de 2017, respectivamente, algumas informações podem ficar desatualizadas.

Conteúdo


  1. 1. Introdução
  2. O WAF moderno
  3. Identificando WAF
  4. Folha de dicas de desvio do WAF
  5. Desvio WAF na prática
  6. Conclusão

Se você souber por que as WAFs são usadas e como elas funcionam, você pode pular diretamente para a seção de desvio.

1. Introdução


WAFs se tornaram bastante populares recentemente. Os fornecedores oferecem várias soluções em diferentes faixas de preço, kits de distribuição e opções, visando diferentes clientes, desde pequenas empresas a grandes empresas. Os WAFs são populares porque são uma solução complexa para proteger aplicativos da Web, que abrange todo um espectro de tarefas. É por isso que os desenvolvedores de aplicativos da Web podem confiar no WAF em alguns aspectos de segurança. Embora os WAFs não possam conceder segurança total.



Então, do que uma WAF deve ser capaz de justificar sua implementação em um projeto? Sua principal função é detectar e bloquear qualquer solicitação que, de acordo com a análise da WAF, possua anomalias ou vetor de ataque. A análise não deve impedir a interação entre usuários legítimos e o aplicativo Web e, ao mesmo tempo, deve detectar com precisão e pontualidade quaisquer tentativas de ataque. Para implementar essa funcionalidade, os desenvolvedores do WAF usam expressões regulares, tokenizers, análise de comportamento, análise de reputação e, é claro, aprendizado de máquina. Muitas vezes, todas essas tecnologias são usadas juntas. O WAF também pode implementar outras funções: proteção contra DDoS, proibição de IPs de invasores, monitoramento de IPs suspeitos, adição de cabeçalhos de segurança (proteção X-XSS, opções de quadro X etc.), adição de sinalizadores http apenas ao cookie, implementação de o mecanismo HSTS e tokens CSRF. Além disso, alguns WAFs possuem módulos JavaScript do lado do cliente para sites.

Obviamente, as WAFs criam alguns obstáculos para hackers e criminosos. O WAF torna a descoberta e a exploração de vulnerabilidades mais intensivas em recursos (exceto se o invasor conhecer métodos eficazes de desvio de 0 dia para um WAF específico). Os scanners automáticos são praticamente inúteis ao analisar aplicativos da Web protegidos por WAF. WAF é uma proteção confiável contra "scriptkiddies". No entanto, um hacker experiente ou um pesquisador sem motivação suficiente provavelmente não gostaria de perder tempo tentando encontrar maneiras de contorná-lo. Deve-se observar que quanto mais complexo o aplicativo da Web, maior a sua superfície de ataque e mais fácil é encontrar um método de desvio.

Em nossas auditorias recentes, frequentemente encontramos diferentes WAFs. Falaremos sobre alguns deles mais tarde. Já testamos dois WAFs proprietários em dois cenários principais:

  • Sabemos que há uma certa vulnerabilidade em um aplicativo Web e tentamos contornar o WAF para explorá-lo;
  • Como não conhecemos nenhuma vulnerabilidade, precisamos encontrar uma, apesar da WAF, e explorá-la ignorando a WAF.

Mas primeiro, vamos dar uma olhada mais de perto nos mecanismos básicos por trás do WAF e ver quais problemas eles têm.

O WAF moderno


Para poder encontrar efetivamente várias maneiras de contornar o WAF, primeiro, precisamos descobrir mecanismos modernos de classificação de solicitações. Cada WAF é específica e construída exclusivamente, mas existem alguns métodos gerais de análise. Vamos dar uma olhada neles.



Regras baseadas em expressões regulares


A maioria dos WAFs existentes usa regras baseadas em expressões regulares. O desenvolvedor pesquisa um certo conjunto de ataques conhecidos para identificar as principais estruturas sintáticas que podem apontar para um ataque. Com base nesses dados, o desenvolvedor cria expressões regulares que encontram essas estruturas sintáticas. Parece simples, mas esse método tem algumas desvantagens. Primeiro, uma expressão regular pode ser aplicada a apenas uma única solicitação, ou mesmo a um único parâmetro de solicitação, o que obviamente reduz a eficiência de tais regras e deixa alguns pontos cegos. Segundo, a sintaxe das expressões regulares e a lógica complexa dos protocolos de texto, que permitem a substituição por estruturas equivalentes e o uso de diferentes representações de símbolos, levam a erros ao criar essas regras.

Scorebuilding


Quem sabe como funcionam os firewalls e antivírus da rede deve estar familiarizado com esse mecanismo. Ele não detecta ataques, mas complementa outros mecanismos, tornando-os mais precisos e flexíveis. O fato é que uma estrutura "suspeita" em uma solicitação não é uma condição suficiente para detectar um ataque e pode levar a muitos falsos positivos. Esse problema é resolvido com a implementação de um sistema de classificação. Cada regra baseada em expressões regulares é complementada pelas informações sobre sua criticidade; depois que todas as regras acionadas são identificadas, sua criticidade é resumida. Se a criticidade total atingir o valor limite, o ataque é detectado e a solicitação é bloqueada. Não obstante sua simplicidade, esse mecanismo se mostrou eficiente e é amplamente utilizado para tais tarefas.

Tokenizers


Este método de detecção foi apresentado no Black Hat 2012 como uma libinjeção de biblioteca C / C +, que permite identificar injeções de SQL com rapidez e precisão. Neste momento, existem muitas portas de libinjeção para diferentes linguagens de programação, como PHP, Lua, Python, etc. Esse mecanismo procura assinaturas apresentadas como um conjunto de tokens. Um certo número de assinaturas está na lista negra e elas são consideradas indesejadas e maliciosas. Em outras palavras, antes de analisar uma solicitação, ela é traduzida em um conjunto de tokens. Os tokens são divididos em certos tipos, como variável, string, operador regular, desconhecido, número, comentário, operador semelhante a união, função, vírgula etc. Uma das principais desvantagens do método é que é possível construir uma estrutura que levaria à formação incorreta de tokens; portanto, a assinatura da solicitação será diferente da esperada. Essas estruturas são geralmente chamadas de disjuntores, e as discutiremos mais tarde

Análise comportamental


Detectar e bloquear tentativas de exploração em solicitações não é a única tarefa para WAFs. Também é importante identificar o processo de pesquisa de vulnerabilidades e o WAF deve reagir de acordo. Pode se manifestar como tentativas de varredura, força bruta de diretório, distorção de parâmetros e outros métodos automáticos. WAFs avançados podem criar cadeias de solicitação típicas do comportamento normal normal e bloquear tentativas de enviar solicitações incomuns. Esse método não detecta tanto ataques, como dificulta o processo de busca de vulnerabilidades. Limitar o número de solicitações por minuto não afetaria um usuário comum, mas seria um sério obstáculo para os scanners, que funcionam em vários threads.

Análise de reputação


Esse é outro mecanismo herdado diretamente de firewalls e antivírus. Hoje, quase todo WAF inclui listas de endereços de VPNs, anonimizadores, nós Tor e redes de bots para bloquear solicitações desses. WAFs avançados podem atualizar automaticamente suas bases e complementá-las com entradas adicionais baseadas no tráfego analisado.

Aprendizado de máquina


Este é um dos aspectos mais questionáveis ​​do WAF. Vamos observar que o termo "aprendizado de máquina" é bastante amplo e inclui muitas tecnologias e métodos. Além disso, é apenas uma das classes da IA. "Implementação" de aprendizado de máquina ou "uso de IA" são frases de marketing muito populares. Nem sempre é claro quais algoritmos são usados ​​exatamente e, às vezes, parece mero absurdo. Os fornecedores que realmente usam o aprendizado de máquina e o fazem efetivamente não estão dispostos a compartilhar sua experiência. Isso torna difícil para alguém de fora tentar entender a situação. No entanto, vamos tentar fazer alguns pontos com base nas informações disponíveis.

Primeiro, o aprendizado de máquina depende totalmente dos dados em que foi treinado, o que apresenta um certo problema. Um desenvolvedor deve ter uma base de ataques atualizada e completa, o que é difícil de alcançar. É por isso que muitos desenvolvedores registram minuciosamente os resultados de seus WAFs e cooperam com os fornecedores que fornecem sistemas IDS e SIEM para obter exemplos de ataques no mundo real. Segundo, um modelo treinado em um aplicativo da web abstrato pode se mostrar totalmente ineficaz em um aplicativo da web real. Para uma melhor qualidade, é recomendável treinar adicionalmente um modelo no estágio de implementação, que consome muitos recursos e consome tempo e ainda não garante os melhores resultados.

Identificando WAF


Os desenvolvedores do WAF usam maneiras diferentes de notificar o usuário que a solicitação foi bloqueada. Assim, podemos identificar o WAF analisando a resposta à nossa solicitação de ataque. Isso geralmente é chamado de impressão digital WAF. As impressões digitais podem ajudar se um WAF não for atualizado por algum motivo (principalmente se aplica a projetos de código aberto). Os desenvolvedores de WAFs proprietários cuidam de seus clientes e implementam atualizações automáticas. Além disso, depois que identificamos o WAF, que acabou sendo atualizado, ainda podemos usar as informações sobre ele para aprender algo sobre sua lógica.

Aqui está uma lista de possíveis impressões digitais WAF:

  • Cookies adicionais
  • Cabeçalhos adicionais para qualquer resposta ou solicitação
  • Conteúdo da resposta (em caso de solicitação bloqueada)
  • Código de resposta (em caso de solicitação bloqueada)
  • Endereço IP (Cloud WAF)
  • Módulo do lado do cliente JS (WAF do lado do cliente)

Vamos ilustrá-lo com alguns exemplos

PT AF
Código de resposta para a solicitação bloqueada: 403
Pode inserir o módulo cliente waf.js na página de resposta
Corpo da resposta:

<h1>Forbidden</h1> <pre>Request ID: 2017-07-31-13-59-56-72BCA33A11EC3784</pre> 

Um cabeçalho extra que adiciona pelo waf.js:

 X-RequestId: cbb8ff9a-4e91-48b4-8ce6-1beddc197a30 

Nemesida waf
Código de resposta para a solicitação bloqueada: 403
Corpo da resposta:

 <p style="font-size: 16px; align: center;"> Suspicious activity detected. Access to the site is blocked. If you think that is's an erroneous blocking, please email us at <a href="mailto:nwaf@pentestit.ru">nwaf@pentestit.ru</a> and specify your IP-address. </p> 

Wallarm
Código de resposta para a solicitação bloqueada: 403
Cabeçalho adicional: nginx-wallarm

Citrix NetScaler AppFirewall
Cookie adicional:

 ns_af=31+LrS3EeEOBbxBV7AWDFIEhrn8A000; ns_af_.target.br_%2F_wat=QVNQU0VTU0lP TklEQVFRU0RDU0Nf?6IgJizHRbTRNuNoOpbBOiKRET2gA 

Mod_Security ver. 2.9
Código de resposta para a solicitação bloqueada: 403
Corpo de resposta:

 <head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access /form.php on this server.<br /></p> 

Mod_Security ver. <2,9
Código de resposta para solicitação bloqueada: 406 ou 501
No corpo da resposta, você pode encontrar mod_security, Mod_Security ou NOYB

Firewall de verniz
Adiciona os seguintes cabeçalhos à resposta:

 X-Varnish: 127936309 131303037. X-Varnish: 435491096 Via: 1.1 varnish-v4 

Os desenvolvedores do WAF decidem eles mesmos qual código de resposta retornar no caso de uma solicitação bloqueada; também existem alguns códigos específicos. Por exemplo, Web_Knight WAF retorna o código 999 e dotDefender retorna o código 200 com um corpo de resposta vazio ou com uma mensagem de erro. Além disso, os desenvolvedores podem criar uma página de resposta personalizada com algum outro conteúdo.

O WAF, como qualquer outro aplicativo, evolui e muda. É por isso que é importante verificar constantemente a relevância das impressões digitais que você possui.

Folha de dicas de desvio WAF


A idéia geral por trás de encontrar maneiras de ignorar o WAF é transformar a solicitação de que precisamos para que ainda seja válida para o aplicativo Web, mas não para o WAF ou pareça inofensiva. É importante que um tipo de WAF possa atender a muitos tipos diferentes de servidores, incluindo os "exóticos", como Unicorn, Tornado, Weblogic, Lighttpd, etc. Cada servidor pode perceber casos exclusivos de análise de solicitação HTTP de uma maneira diferente, que também deve ser considerada pelo WAF. Assim, um invasor pode usar as especificidades de análise de solicitação HTTP dos servidores para encontrar uma maneira de ignorar o WAF.



É difícil classificar todas as formas possíveis de ignorar o WAF pelos mecanismos de segurança do WAF ou pelo campo de uso. As mesmas formas de desvio podem interagir e afetar simultaneamente diferentes componentes de um WAF. As técnicas descritas abaixo foram coletadas de fontes abertas ou descobertas durante nossa própria pesquisa e provaram estar entre as mais eficazes.

Adicionando símbolos especiais


Vários símbolos especiais podem violar a lógica de análise de um WAF e, ao mesmo tempo, ser válidos interpretados pelo servidor. As variações desses símbolos podem ser diferentes: elas podem ser transformadas em código de URL (embora a maioria dos WAFs possa lidar com isso) ou outras codificações. Também é possível inserir símbolos especiais em uma solicitação sem qualquer codificação, no formato bruto, o que pode ser uma surpresa para um WAF. Por exemplo, \ r \ n \ r \ n nesta apresentação pode ser percebido como o final de um corpo de solicitação HTTP, e um byte nulo pode violar a lógica de análise de expressões regulares e analisadores de dados por completo. Além disso, outros símbolos especiais dos primeiros vinte símbolos da tabela ASCII podem ser úteis.
Exemplos:

  • 0x00 - byte nulo;
  • 0x0D - Retorno de carro;
  • 0x0A - avanço de linha;
  • 0x0B - Guia vertical;
  • 0x09 - guia Horizontal;
  • 0x0C - Nova página

Ao procurar um desvio, é útil inserir símbolos especiais em locais diferentes no corpo da solicitação e não apenas nos valores dos parâmetros. Por exemplo, se uma solicitação estiver no formato JSON, podemos inserir bytes nulos em um parâmetro e entre parâmetros, no início e no final do JSON. O mesmo se aplica a outros formatos do corpo de uma solicitação POST. Em geral, recomendamos fazer pesquisas e se divertir, procurar lugares que possam ser monitorados e analisados ​​pelo WAF e tentar usar diferentes símbolos especiais lá.

Por exemplo:

 {"id":1337,"string0x00":"test' or sleep(9)#"} {"id":1337,"string":"test'/*0x00*/ or sleep(9)#"} {"id":1337,"string"0x0A0x0D:"test' or sleep(9)#"} 

 <a href="ja0x09vas0x0A0x0Dcript:alert(1)">clickme</a> <a 0x00 href="javascript:alert(1)">clickme</a> <svg/0x00/onload="alert(1)"> 

 id=1337/*0x0C*/1 UNION SELECT version(), user() -- 

Para maior clareza, substituímos símbolos especiais por sua apresentação hexadecimal.

Substituindo símbolos de espaço


Na maioria das sintaxes, as palavras-chave e os operadores precisam ser separados, mas os símbolos de espaço preferenciais não são especificados. Portanto, em vez do 0x20 comum (Espaço), você pode usar 0x0B (Guia Vertical) ou 0x09 (Guia Horizontal). Substituir espaços por estruturas divididas sem significado próprio se enquadra na mesma categoria. No SQL, é / ** / (comentários SQL de várias linhas), # \ r \ n (comentário SQL de uma linha, terminando com feed de linha), - \ r \ n (comentário SQL de uma linha alternativo, finalizando com avanço de linha). Aqui estão alguns exemplos:

 http://test.com/test?id=1%09union/**/select/**/1,2,3 http://test.com/test?id=1%09union%23%0A%0Dselect%2D%2D%0A%0D1,2,3 

Além disso, podemos transformar uma expressão para se livrar de espaços usando a sintaxe da linguagem. Por exemplo, no SQL, podemos usar parênteses:

 UNION(SELECT(1),2,3,4,5,(6)FROM(Users)WHERE(login='admin')) 

E em JS, use / :

 <svg/onload=confirm(1)> 

Alterando a codificação


Esse método é baseado no uso de codificações diferentes para impedir que o WAF decodifique dados em determinados locais. Por exemplo, se um símbolo for substituído por seu código de URL, o WAF não será capaz de entender que precisa decodificar dados e passará a solicitação. Ao mesmo tempo, o mesmo parâmetro será aceito e decodificado com sucesso pelo aplicativo da web.

A forma decimal de um símbolo HTML é & # 106 ou & # 0000106 .WAF pode saber sobre a versão curta e não saber sobre a versão com zeros adicionais (não deve haver mais de 7 símbolos no total). Da mesma forma, a forma hexadecimal de um símbolo HTML é & # x6A ou & # x000006A .

Há também um truque para escapar caracteres com uma barra invertida \ , por exemplo:

 <svg/on\load=a\lert(1)> 

No entanto, depende de como um aplicativo Web processa esses dados de entrada. Portanto, a sequência \ l será processada como l e transformada em um único símbolo; O WAF pode processar cada símbolo separadamente e pode quebrar expressões regulares ou outra lógica do WAF. Assim, o WAF perderá as palavras-chave. Usando esta técnica, não podemos escapar dos caracteres \ n , \ r , \ t , pois eles serão transformados em caracteres diferentes: nova linha, retorno de carro e guia.

A codificação HTML pode ser usada dentro dos atributos da tag, por exemplo:

 <a href="javascript&colon;alert(1)">clickme</a> <input/onmouseover="javascript&colon;confirm&lpar;1rpar;"> 

Esses caracteres podem ser facilmente substituídos por outras representações HTML dos caracteres de destino. Você pode procurar diferentes transformações de caracteres aqui .

Além da codificação HTML, podemos inserir caracteres com \ u :

 <a href="javascript:\u0061lert(1)">Clickme</a> <svg onload=confir\u006d(1)> 

Vejamos também o vetor relacionado à inserção de caracteres especiais. Vamos quebrar a carga útil com a codificação HTML:

 <a href="ja&Tab;vas&#x0000A;cript:alert(1)">clickme</a> 

Nesse caso, também podemos colocar outros caracteres de separação.

Portanto, recomendamos combinar diferentes codificações com outros métodos, por exemplo, para codificar caracteres especiais.

Procure estruturas sintáticas equivalentes atípicas


Esse método visa encontrar uma maneira de exploração não considerada pelos desenvolvedores do WAF ou um vetor que não estava presente na amostra de treinamento de aprendizado de máquina. Exemplos simples seriam funções JavaScript: this, top self, parent, frames; atributos de tag: ligação de dados, ontoggle, onfilterchange, onbeforescriptexecute, onpointerover, srcdoc; e operadores SQL: lpad, field, bit_count .

Aqui estão alguns exemplos:

 <script>window['alert'](0)</script> <script>parent['alert'](1)</script> <script>self['alert'](2)</script> 

 SELECT if(LPAD(' ',4,version())='5.7',sleep(5),null); 

Você também pode usar a representação não simbólica das expressões JavaScript:


Um problema óbvio disso é a carga útil longa.

O desvio do WAF com essa técnica depende do ataque e da pilha de tecnologias explorada. A famosa exploração do ImageTragick é um bom exemplo disso. A maioria dos WAFs que protegem contra esse ataque tinha palavras-chave na lista negra, como URL , capacidade e rótulo, uma vez que essas palavras foram mencionadas na maioria dos artigos e PoCs que descrevem essa vulnerabilidade. Embora logo tenha sido revelado que outras palavras-chave também podem ser usadas, por exemplo, efêmero e pango . Como resultado, os WAFs podem ser ignorados com o uso dessas palavras-chave.

Poluição de Parâmetro HTTP (HPP) e Fragmentação de Parâmetro HTTP (HPF)


O ataque HPP é baseado em como um servidor interpreta parâmetros com os mesmos nomes. Aqui estão alguns desvios possíveis:

  • O servidor usa o último parâmetro recebido e o WAF verifica apenas o primeiro;
  • O servidor une o valor de parâmetros semelhantes e o WAF os verifica separadamente.

Você pode comparar como servidores diferentes processam os mesmos parâmetros na tabela abaixo:



Por sua vez, o ataque do HPF é baseado em um princípio diferente. Se a lógica de um aplicativo da Web unir dois e mais parâmetros em uma solicitação, o adversário poderá dividir a solicitação para ignorar determinadas verificações do WAF.
A injeção SQL a seguir é um exemplo de ataque:

 http://test.com/url?a=1+select&b=1+from&c=base 

HPF e HPP são muito semelhantes, mas o primeiro é direcionado a um aplicativo Web e o último é o ambiente em que ele opera. A combinação dessas técnicas aumenta a chance de ignorar um WAF.

Normalização Unicode


A Normalização Unicode é um recurso do Unicode destinado a comparar símbolos Unicode semelhantes. Por exemplo, os símbolos 'ª' e 'ᵃ' têm códigos diferentes, mas são muito similares caso contrário, portanto, após a normalização, ambos parecerão um simples 'a' e considerados iguais. A normalização permite transformar alguns símbolos Unicode complexos em alternativas mais simples. Há uma tabela de normalização Unicode com todos os símbolos Unicode e suas possíveis normalizações. Usando-o, você pode fazer diferentes cargas úteis e combiná-las com outros métodos. Embora não funcione para todos os aplicativos da Web e muito dependente do ambiente.

Por exemplo, na tabela acima, podemos ver que os símbolos e transformam em simples < . Se um aplicativo usar codificação HTML após a normalização, provavelmente o símbolo normalizado < será codificado em &lt; . Mas, em outros casos, os desenvolvedores podem ter ignorado esse recurso e não codificado símbolos Unicode. Assim, obtemos símbolos não codificados em HTML < e > , que podem ser transformados em ataques XSS. O WAF pode ter problemas para entender os símbolos Unicode - ele pode simplesmente não ter regras para esses truques, e o aprendizado de máquina também pode ser inútil. Ao encontrar um desvio em aplicativos Web com a normalização Unicode, podemos substituir não apenas <> mas também outros símbolos da carga útil.

Por exemplo:

 <img src﹦x onerror=alert︵1)> 

Recentemente, esse problema foi encontrado no programa Rockstar BugBounty no HackerOne. Não havia WAF, apenas filtragem estrita de entrada do usuário:

hackerone.com/reports/231444
hackerone.com/reports/231389

Disjuntores de tokens


Ataques em tokenizadores tentam quebrar a lógica de dividir uma solicitação em tokens com a ajuda dos chamados disjuntores. Disjuntores de tokens são símbolos que permitem afetar a correspondência entre um elemento de uma string e um determinado token e, assim, ignoram a pesquisa por assinatura. Porém, ao usar o disjuntor de token, a solicitação deve permanecer válida. A solicitação a seguir é um exemplo de ataque usando um disjuntor de token

 SELECT-@1,version() 

onde - @ é o disjuntor de token.

Existe uma planilha de chear que foi adquirida pelo mysql fuzzing e verificando os resultados na libinjection.

Mais sobre como encontrar problemas na libinjection:

Outro fuzzer
Fuzz para ignorar
Como ignorar a libinjeção

Usando os recursos do RFC


Nas especificações para o protocolo HTTP / 1.1 e vários tipos de solicitação (por exemplo, multipart / form-data), podemos encontrar algumas coisas curiosas relacionadas aos casos de limite e truques de processamento de cabeçalhos e parâmetros. Os desenvolvedores do WAF geralmente não consideram esses problemas; portanto, um WAF pode analisar uma solicitação incorretamente e perder a parte dos dados, onde um vetor de ataque está oculto. A maioria dos problemas nos WAFs está relacionada ao processamento de dados de várias partes / formulário e valores específicos do parâmetro boundary, que especifica os limites dos parâmetros em tais solicitações. Além disso, os desenvolvedores de servidores também podem errar e não suportar especificações completamente, portanto, pode haver recursos não documentados no analisador HTTP de um servidor.

Em uma solicitação HTTP com dados de várias partes / formulário, o limite do parâmetro é responsável pela segregação de diferentes parâmetros no corpo de uma solicitação. De acordo com a RFC, um limite especificado anteriormente com um prefixo contendo “-” deve ser colocado antes de cada novo parâmetro POST, para que o servidor possa discriminar os diferentes parâmetros de uma solicitação.

 POST /vuln.php HTTP/1.1 Host: test.com Connection: close Content-Type: multipart/form-data; boundary=1049989664 Content-Length: 192 --1049989664 Content-Disposition: form-data; name="id" 287356 --1049989664-- 

O ataque também pode se basear no fato de que um servidor e um WAF lidam de maneira diferente com uma situação em que o limite é deixado vazio. De acordo com a RFC, neste caso, “-” é o limite entre os parâmetros. No entanto, um WAF pode usar um analisador que não considere isso e, como resultado, o WAF passará a solicitação porque os dados dos parâmetros de uma solicitação POST não apareceriam no analisador. O servidor da Web pode analisar essa solicitação sem problemas e entregar os dados para processamento adicional.
Aqui estão alguns exemplos mais interessantes.

 POST /vuln.php HTTP/1.1 Host: test.com Connection: close Content-Type: multipart/form-data; boundary= Content-Length: 192 -- Content-Disposition: form-data; name="id" 123' or sleep(20)# ---- 

Vamos dar alguns exemplos mais interessantes dos slides do Bo0oM no ZeroNights 2016 e explicar:

 POST /vuln.php HTTP/1.1 Host: test.com Content-Type: multipart/form-data; boundary=FIRST; Content-Type: multipart/form-data; boundary=SECOND; Content-Type: multipart/form-data; boundary=THIRD; --THIRD Content-Disposition: form-data; name=param UNION SELECT version() --THIRD-- 

Neste ataque, estamos tentando definir qual dos parâmetros de limite será aceito pelo WAF e qual pelo servidor da web. Portanto, se eles aceitarem parâmetros diferentes, é possível executar um ataque especificando um limite que o WAF não verá. Esse ataque é um pouco como o HPP.

 POST /vuln.php HTTP/1.1 Host: test.com Content-Type: multipart/form-data; xxxboundaryxxx=FIRST; boundary=SECOND; --FIRST Content-Disposition: form-data; name=param UNION SELECT version() --FIRST-- 

Esse ataque é baseado na suposição de que há uma diferença na análise de uma solicitação HTTP pelo WAF e pelo servidor da web. Ou seja, o analisador do servidor da Web procura a primeira entrada 'limite' e, em seguida, o símbolo '=', e somente depois disso define o valor do limite. O analisador WAF, por sua vez, procura apenas a entrada "boundary =" e depois define o limite. Se essas condições forem atendidas, o WAF não encontrará o limite na solicitação e, portanto, não poderá encontrar e analisar o parâmetro. Pelo contrário, o servidor da Web receberá a solicitação e processará o parâmetro. Esse ataque também funcionará de maneira inversa: o analisador de servidor da Web procura por “boundary =” e o WAF parser procura apenas por 'boundary'. Nesse caso, teremos apenas que alterar o limite real de PRIMEIRO para SEGUNDO.

 POST /somepage.php HTTP/1.1 Host: test.com Content-Type: multipart/form-data; boundary=Test0x00othertext; --Test Content-Disposition: form-data; name=param Attack --Test-- 

Este ataque também usa caracteres especiais. No parâmetro boundary, adicionamos NULL-byte para que o servidor da Web o interrompa, mas o WAF o aceite integralmente. Nesse caso, o WAF não pode analisar o parâmetro porque não consegue encontrar seus limites.

Ignorando o aprendizado de máquina


A lógica é simples: temos que compor um ataque que satisfaça os parâmetros do modelo estatístico treinado. Mas isso depende muito de como a WAF foi treinada e de qual modelo de treinamento foi usado. Às vezes é possível encontrar uma brecha, e às vezes não. Normalmente, no estágio de implementação, um WAF com aprendizado de máquina precisa de treinamento extra com base na solicitação para o aplicativo Web do cliente. Isso representa um problema para os participantes do teste: parâmetros semelhantes e que não mudam muito de solicitação para solicitação não podem ser testados, pois qualquer digressão da forma usual de parâmetro seria considerada uma anomalia. Digamos que tenha um pedido para api.test.com/getuser?id=123 . A identificação do parâmetro é sempre numérica e foi numérica na amostra de treinamento. Se o módulo de aprendizado de máquina encontrar algo além de números nesse parâmetro, provavelmente decidirá que é uma anomalia. Outro exemplo: suponha que o WAF tenha sido treinado para classificar a solicitação POST em api.test.com/setMarkDown com parâmetros POST que possuem texto de remarcação. Obviamente, pode haver aspas, símbolos especiais e basicamente qualquer coisa na remarcação. Nesse caso, é muito mais fácil ignorar o módulo de aprendizado de máquina porque o WAF tolera aspas e símbolos especiais.

Além disso, nos exemplos de nossa prática, mostraremos que ele nem sempre chega ao módulo de aprendizado de máquina devido a problemas com a análise de parâmetros causados ​​pelos métodos de desvio descritos acima.

Em geral, precisamos considerar as especificidades de uma solicitação testada e seus parâmetros, presumir todas as opções possíveis dos valores dos parâmetros, aos quais o WAF pode ser tolerante, e basear-se neles.

Quando WAF é inútil?


O WAF analisa solicitações e procura um comportamento anômalo nelas, mas existem algumas classes de vulnerabilidades que não podem ser descobertas. Por exemplo, vulnerabilidades lógicas, que não têm anomalias, mas têm algumas ações que interrompem a lógica de um aplicativo Web. Provavelmente, o WAF também seria inútil em caso de condição de corrida, IDOR e autenticação de usuário insegura.

Utilitários existentes


Existem algumas ferramentas automáticas para encontrar desvios do WAF, escritos pelos entusiastas deste campo. Aqui estão os mais famosos e dignos:

lightbulb-framework - uma estrutura completa para testar aplicativos da web protegidos com WAF. Está escrito em Python e adicionalmente portado como um plugin para o Burp Suite. Suas principais características são esses dois algoritmos:

  • GOFA - um algoritmo ativo de aprendizado de máquina que permite analisar a filtragem e a higienização de parâmetros em um aplicativo da web.
  • SFADiff - algoritmo de teste deferente de caixa preta, baseado em treinamento com autômatos finitos simbólicos (SFA). Ele permite encontrar diferenças no comportamento dos aplicativos da web, o que ajuda a identificar o WAF e encontrar um desvio.

Bypass WAF - um plug-in para o Burp Suite, que permite configurar a alteração automática dos elementos no corpo de uma solicitação de acordo com diferentes regras e alterações de codificação. Ele também pode automatizar um ataque de HPP.

WAFW00F - uma ferramenta para identificação de WAF, escrita em Python. Ele possui uma base WAF decente e ainda está sendo atualizado. No entanto, os resultados podem ser imprecisos porque muitas WAFs são atualizadas com mais frequência do que o próprio projeto.

Ignorando o waf na prática




Temos realizado testes de penetração em uma loja on-line, protegida pelo PT AF (Positive Technologies Application Firewall). Era difícil encontrar um ponto fraco, que poderia ser a base para um desvio. Mas logo descobrimos um comportamento incomum no lado do aplicativo Web, que não foi filtrado pelo WAF. A anomalia foi encontrada na pesquisa no histórico de mercadorias compradas. A solicitação foi enviada no formato JSON e tinha a seguinte aparência:

 {"request":{"Count":10,"Offset":0,"ItemName":"Phone"}} 

Colocamos os valores Phone ' e Phone' + ' no parâmetro ItemName e descobrimos que o servidor retornou respostas diferentes para essas duas solicitações. No primeiro caso, a resposta estava vazia; no segundo caso, continha dados de outros produtos com a palavra telefone em seu nome, como se o parâmetro ItemName tivesse telefone como valor. Esse tipo de comportamento é bem conhecido entre hackers e criminosos e aponta para o aplicativo um problema com a filtragem da entrada do usuário, o que leva à injeção de SQL, entre outros.

Vamos ver por que isso acontece com um exemplo de injeção SQL. Se esse comportamento for encontrado em um aplicativo Web, é altamente provável que os dados para uma solicitação SQL estejam em concatenação com a própria solicitação. No primeiro caso, com o parâmetro Phone ' , teremos a seguinte consulta SQL:

 SELECT item FROM items WHERE item_name='Phone'' 

Obviamente, não será executado devido à sintaxe incorreta e não retornará nenhum resultado. A segunda solicitação, com o parâmetro Phone '+' , terá a seguinte aparência:

 SELECT item FROM items WHERE item_name='Phone'+'' 

Sua sintaxe está correta e, portanto, selecionará produtos com o nome Telefone . Esse método de detecção de vulnerabilidades tem uma enorme vantagem ao testar um aplicativo Web protegido pelo WAF. O símbolo de aspas simples não é considerado uma anomalia suficiente em um parâmetro pela maioria dos WAFs modernos; portanto, eles passam uma solicitação com ele.

Descrevemos a detecção de vulnerabilidades, mas e ignorando o WAF e explorando a vulnerabilidade? Depois de passar por alguns desvios, encontramos um problema no WAF. Verificou-se que este WAF é vulnerável a caracteres especiais adicionados aos parâmetros JSON. De fato, se adicionarmos os símbolos JSON 0x0A, 0x0D (\ r \ n ou carrige reutrn e nova linha) no formato bruto, sem qualquer codificação, em qualquer campo de texto, o WAF passará e o aplicativo da Web considerará esteja correto e processe-o. Provavelmente, o problema estava no analisador JSON, que não foi criado para símbolos especiais e analisou o JSON até um local onde esses símbolos apareceriam. Assim, o analisador WAF não receberia a solicitação completa, para que pudéssemos inserir qualquer vetor de ataque após caracteres especiais. Além da quebra de linha, outros caracteres (por exemplo, NULL-byte) também funcionariam. Como resultado, poderíamos escrever a seguinte solicitação, que desativaria o WAF ao tentar verificar essa solicitação (a quebra de linha e o retorno de carro foram substituídos por sua representação textual):

 {"request":{"kill-waf":"die0x0A0x0D", "Count":10,"Offset":0,"ItemName":["'+(SELECT 'Phone'+CHAR(ASCII(substring(@@version,1,1))-24))+'"]}} 

0x0A e 0x0D são bytes brutos.

Assim, poderíamos testar com facilidade e rapidez todos os parâmetros em busca de vulnerabilidades (algumas foram encontradas em outros parâmetros). Ignorar o WAF e explorar essa injeção nos permitiu comprometer totalmente todos os usuários do aplicativo da web.

Os mesmos problemas também foram encontrados no Nemesida WAF . A única diferença é que a solicitação não estava na codificação JSON, mas era uma solicitação POST comum com parâmetros, e um parâmetro foi concedido à consulta SQL como um número. Se alguns símbolos foram colocados em uma solicitação na codificação de URL, por exemplo, % 03% 04 , o WAF bloqueia uma solicitação, mas se os símbolos foram colocados na forma bruta sem codificação de URL, o WAF ignora essa solicitação. Vale ressaltar que a expressão SQL normal foi solicitada, assim como no WAF anterior. A expressão SQL era simples 'UNION SELECT' sem nenhuma ofuscação adicional, o que significa que o WAF simplesmente não pôde analisar a solicitação corretamente e passar adiante a análise. Mas há um problema - como corrigir a sintaxe da consulta SQL? Porque o uso de caracteres especiais como % 03% 04 na consulta SQL não está correto. A resposta é simples - basta usar comentários / ** /. Portanto, a solicitação de resultado parecia:

 /*0x03 0x04*/1 UNION SELECT version(), user() -- 

0x03 e 0x04 são bytes brutos.

Além disso, outro problema foi encontrado no Nemesida WAF. Isso estava relacionado ao processamento incorreto de solicitações POST com dados de várias partes / formulário. Conforme descrito abaixo, em uma solicitação HTTP com dados de várias partes / formulário, o limite do parâmetro é responsável pela segregação de diferentes parâmetros no corpo de uma solicitação. De acordo com a RFC, um limite especificado anteriormente com um prefixo contendo “-” deve ser colocado antes de cada novo parâmetro POST, para que o servidor possa discriminar os diferentes parâmetros de uma solicitação.
Portanto, o problema era que o servidor e o WAF trataram a situação de maneira diferente quando o parâmetro de limite estava vazio. Com base na RFC, em tal situação, o limite entre os parâmetros será uma sequência de caracteres “-” . No entanto, o WAF usou um analisador que não leva em consideração esse recurso, e é por isso que o WAF passa novamente a solicitação, porque os dados dos parâmetros de solicitação POST simplesmente não entraram no módulo analisador e o servidor analisou essa situação sem problemas. e transferiu os dados para o processamento. Esta é uma solicitação de amostra para este ataque:

 POST /wp-content/plugins/answer-my-question/modal.php HTTP/1.1 Host: example.com Content-Type: multipart/form-data; boundary= Content-Length: 209 -- Content-Disposition: form-data; name="id" 1 UNION SELECT 1,2,3,CONVERT(version() USING utf8) AS name,CONVERT(user() USING utf8) AS name,6,7,8,9,10,11,12 FROM wp_users WHERE id=1 ---- 

Ambos os problemas foram relatados ao Pentestit, os caras pagaram uma recompensa por seu programa de recompensa de bugs para o Nemesida WAF e os solucionaram o mais rápido possível. Agradeça a eles por isso.

Como podemos ver, os WAFs podem ser modernos e inteligentes, mas às vezes é possível ignorá-los apenas adicionando um único caractere especial. Hoje, não podemos prever todos os tipos possíveis de dados de entrada para todos os servidores no estágio de desenvolvimento, e o aprendizado de máquina, implementado para fazer exatamente isso, tropeça nos analisadores que ficam presos a caracteres especiais.

Conclusão


Então, devemos confiar inteiramente no WAF? A resposta é NÃO.

Em uma de nossas auditorias, descobrimos um desvio WAF que nos permitiu explorar algumas vulnerabilidades. Como se viu, os desenvolvedores já haviam realizado uma auditoria do aplicativo Web, antes de ser protegido pelo WAF, e ele revelou as mesmas vulnerabilidades. Em vez de consertá-los, eles decidiram comprar um WAF moderno, equipado com aprendizado de máquina. É uma pena que o fornecedor do WAF não tenha insistido em corrigir as vulnerabilidades primeiro; ou talvez os próprios desenvolvedores pensassem que o WAF seria uma opção melhor. Ainda não sabemos ao certo. De qualquer forma, este é um exemplo de uma prática muito ruim, tanto por parte dos desenvolvedores quanto do fornecedor. Também deve-se notar que o aprendizado de máquina ainda é uma caixa preta e parece mais um dispositivo de marketing do que uma defesa real.

Em geral, o WAF é uma solução de segurança moderna e não prejudica tê-lo com seus aplicativos da web. Embora hoje em dia, ele pode apenas atrapalhar o processo de pesquisa e exploração de vulnerabilidades, mas não pode se proteger completamente deles. No momento, esse é o estado da arte há um bom tempo. As vulnerabilidades nos aplicativos da Web só podem ser corrigidas corrigindo o código relacionado a eles, e essa é a única solução infalível.

Contribuintes

Ilia Bulatov barracud4
Denis Rybin thefaeriedragon
Alexander Romanov web_rock

Source: https://habr.com/ru/post/pt454592/


All Articles