Introdução
O Web Finder tem por objetivo auxiliar na localização de endereços IP que respondem por uma URL específica, podendo, desta forma ocorrer o Bypass do WAF.
Conceito técnico
Ao realizar uma requisição HTTP/S para um host a primeira fase a ser realizada pelo cliente é a resolução de nome para IP e posteriormente conexão direta para este IP. Este procedimento se refere até a camada de Transporte do modelo OSI (camada 4) onde temos apenas IP e porta. Após a conexão TCP ocorrer com sucesso o cliente monta um cabeçalho de requisição HTTP e envia ao servidor, veja o exemplo a seguir:
Supondo que em um navegador seja digitado https://www.helviojunior.com.br (conforme o comando curl abaixo), primeiramente o cliente resolverá o nome DNS para o IP (cujo resultado será 54.244.151.52) e posteriormente enviará o cabeçalho conforme abaixo:
1
curl -k https://www.helviojunior.com.br
Cabeçalho:
1
2
3
4
5
6
7
8
9
GET / HTTP/1.1
Host: www.helviojunior.com.br
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Upgrade-Insecure-Requests: 1
Te: trailers
Connection: close
Como podemos observar no cabeçalho Host
temos o nome completo do servidor. Com o advento do HTTP 1.1 em diante o servidor leva em consideração este campo para rotear internamente em qual site deve responder, sendo que se o servidor estiver preparado para responder por este host (www.helviojunior.com.br) o mesmo o fará.
Porém nós podemos realizar o mesmo processo de forma diferente, onde direcionamos o cliente em qual endereço IP o mesmo deve conectar e forçamos o host no cabeçalho do HTTP conforme o comando abaixo:
1
curl -k -H 'Host: www.helviojunior.com.br' https://54.244.151.52
Deste modo obrigatoriamente a conexão TCP ocorrerá para o IP 54.244.151.52 independente da resolução DNS, porém no cabeçalho http será enviado o host www.helviojunior.com.br. Desta forma iremos obter o mesmo resultado como resposta.
Porém deste modo podemos alterar o endereço IP para qualquer outro, como por exemplo 10.10.10.10 que de o servidor deste IP existir e tiver preparado para responder ao site www.helviojunior.com.br a resposta (HTTP Status code e tamanho) será a mesma.
1
curl -k -H 'Host: www.helviojunior.com.br' https://10.10.10.10
Porém, no cenário acima o
Subject Name
informado viaSNI
será o IP ao invés dohost
, sendo assim em cenários onde o TLS exige SNI o comando acima não irá funcionar, desta forma precisaremos utilizar outra estratégia.
Para isso utilizaremos o parâmetro --resolve [DOMAIN]:[PORT]:[IP]
do CURL
1
curl -k --resolve www.helviojunior.com.br:443:54.244.151.52 https://www.helviojunior.com.br
Deste modo, igualmente no cenário anterior, obrigatoriamente a conexão TCP ocorrerá para o IP 54.244.151.52 pois o parâmetro --resolve
ignora a resolução de nome via DNS. Adicionalmente desta forma o cabeçalho host
e o Subject Name
do SNI
serão definidos corretamente.
Sendo assim podemos utilizar essa técnica para passar uma lista de IPs e verificar se eles estão configurados para responder por um determinado site.
Instalação
Instalando pipx
Recomendamos a utilização do
pipx
ao invés dopip
para instalação no sistema.
1
2
python3 -m pip install pipx
python3 -m pipx ensurepath
Instalando do Web Finder
1
python3 -m pipx install wafwebfinder
Exemplo prático
Para este tutorial realizaremos o teste com o serviço do X (antigo Twitter). A motivação da escrolha se dá pelo fato do mesmo ter alterado recentemente o seu serviço para uma CDN evitando os bloqueios impostos no Brasil.
Enumeração de IPs
O primeiro passo necessário é a coleta/enumeração de possíveis IPs, para este processo utilizaremos 3 técnicas diferentes:
- Emumeração ativa por força bruta no DNS
- Enumeração passiva através do Virus Total
- Enumeração passiva através do Shodan
EnumDNS
o enumdns
é um script criado por mim e disponível em https://github.com/helviojunior/libs/blob/master/python/enumdns.py
Realizando o download da SecList (wordlist que utilizaremos)
1
2
3
mkdir -p /usr/share/wordlists/
cd /usr/share/wordlists/
git clone https://github.com/danielmiessler/SecLists
1
2
3
cd ~
wget https://raw.githubusercontent.com/helviojunior/libs/master/python/enumdns.py
python3 enumdns.py -d x.com -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -o enumdns.txt
Mantenha o arquivo gerado
enumdns.txt
para que posteriormente possamos filtrar os IPs
Virus Total
Acesse o VirusTotal e digite a URL desejada, realize a busca e posteriormente clique em Relations.
Na aba Relations teremos diversos endereços IPs
Selecione todo o texto/html do site, copie e cole em um arquivo texto.
Não se importe se vier outros textos neste processo, pois futuramente iremos filtrar somente os endereços IP
Shodan
Visualize todos os endereços listados pelo Shodan através da URL https://www.shodan.io/domain/{DOMAIN}
, substituindo o texto {DOMAIN}
pelo domínio desejado. Exemplo: https://www.shodan.io/domain/x.com
Selecione todo o texto/html do site, copie e cole em um arquivo texto.
Não se importe se vier outros textos neste processo, pois futuramente iremos filtrar somente os endereços IP
Filtrando somente os IPs
Salve todo o conteúdo obtido anteriormente em um único arquivo de texto.
Para fins de ilustração segue um comando grep
para filtrar somente as linhas com endereçamento IPv4.
1
cat tmp.txt | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
Agora vamos obter os endereços IP, ordena-los e filtrar por endereços únicos.
1
cat tmp.txt | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sort -u > tst.txt
Expandindo a busca
Em alguns cenários se faz necessário expandir a busca para todas as subnets /24
dos IPs encontrados.
Este passo não é obrigatório, mas pode ser importante para expandir a busca e encontrar outros endereçamentos que não foram listados nos passos anteriores. Em ambiente clould certamente virá bastante IP que possivelmente não faz parte do escopo do teste, mas em ambiente on-premisses a acertividade é bem alta.
Para isso vamos extrair somente as subnets:
1
for net in $(cat *.txt | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.'):; do echo "${net}0/24"; done | sort -u > subnets.txt
Posteriormente realizar um NMAP para localizar os endereços que respondem por HTTP e HTTPS.
1
nmap -Pn -v -T4 -sTV -p80,443 -iL subnets.txt | tee -a nmap_subnets_1.txt
Após a finalização podemos filtrar os endereços
1
cat nmap_subnets_1.txt | grep 'open port' | grep '443\|80' | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sort -u > tst.txt
Utilizando o WebFinder
Agora que temos uma lista de IPs, podemos utiliza-la para verificar quais servidores respondem pelo serviço desejado.
1
webfinder -t https://x.com/ -ip tst.txt -o x.txt --random-agent
O comando acima irá respeitar o protocolo estipulado pela URL
http
ouhttps
. Caso deseje realizar a busca em ambos protocolos basta utilizar o parâmetro--check-both
Blind check
O Web Finder em seu modo de busca padrão, primeiramente irá se conectar ao site original e obter o código de retorno bem como o tamanho do corpo da resposta, este processo tem por objetivo entender o padrão do site original para posteriormente buscar pelo mesmo padrão diretamente nos endereços IP informados.
Porém existem alguns cenários onde o acesso ao site original não é possível, por diversas razões, como bloqueio, conectividade de rede e etc… Nestes casos o Web Finder detém de um parâmetro --static
onde é possível a parametrização do código de retorno (Ex: 200, 204, 404, 500 e etc…) em conjunto (ou não) com o tamanho da resposta esperada.
Adotando como base a requisição anterior que obtivemos o código de retorno 200
com o tamanho de 2610 bytes
podemos realizar a execução com 2 variantes:
- Somente o status code:
webfinder -t https://x.com/ -ip tst.txt -o x.txt --random-agent --static 200
- Status code + tamanho:
webfinder -t https://x.com/ -ip tst.txt -o x.txt --random-agent --static 200:2610
A utilização do
--static
com somente o código de retorno pode acarretar em falso-positivo, uma vez que a identificação do retorno pode não ser precisa.
Conclusão
Como pudemos ver neste artigo, é possível obter os endereços IPs que respondem por um deternimado serviço.
Adicionalmente a ferramenta webfinder
apois neste processo e ilustra caso o IP endontrado esteja protegido por alguma ferramenta de CDN e/ou WAF.