November 5, 2019
This blog is part of our Rails 6 series.
In a DNS Rebinding attack, a malicious webpage runs client-side script when it is loaded, to attack endpoints within a given network.
DNS Rebinding can be summarized as follows.
rebinding.network
which is
resolved by a DNS server controlled by a malicious entity.24.56.78.99
of http://rebinding.network
. This DNS server also sets a very
short TTL value ( say 1 second ) on the response so that the client won't
cache this response for long.http://rebinding.network/setup/reboot
with a
JSON payload {params: factory-reset}
.24.56.78.99
(real IP address), with
the DNS info from the cache, but then the browser sends out a DNS query for
rebinding.network
when it observes that the cache has gone stale.24.56.78.99
(which is the real IP address of
rebinding.network
), it responds with 192.168.1.90
, an address at which, a
poorly secured smart device runs.Using this exploit, an attacker is able to factory-reset a device which relied on security provided by local network.
This attack is explained in much more detail in this blog post.
Rails’s web console was particularly vulnerable to a Remote Code Execution (RCE) via a DNS Rebinding.
In this blog post, Ben Murphy goes into technical details of exploiting this vulnerability to open Calculator app (only works in OS X).
Rails mitigates DNS Rebinding attack by maintaining a whitelist of domains from which it can receive requests. This is achieved with a new HostAuthorization middleware. This middleware leverages the fact that HOST request header is a forbidden header.
# taken from Rails documentation
# Allow requests from subdomains like `www.product.com` and
# `beta1.product.com`.
Rails.application.config.hosts << ".*\.product\.com/"
In the above example, Rails would render a blocked host template, if it receives requests from domains outside of above whitelist.
In development environment, default whitelist includes 0.0.0.0/0, ::0
(CIDR notations for IPv4 and IPv6 default routes)
and localhost
. For all other environments, config.hosts is empty and host
header checks are not done.
If this blog was helpful, check out our full blog archive.