CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/spoof/dns/compare_results.rb
Views: 11623
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'net/dns'
7
require 'resolv'
8
9
class MetasploitModule < Msf::Auxiliary
10
11
def initialize(info = {})
12
super(update_info(info,
13
'Name' => 'DNS Lookup Result Comparison',
14
'Description' => %q{
15
This module can be used to determine differences
16
in the cache entries between two DNS servers. This is
17
primarily useful for detecting cache poisoning attacks,
18
but can also be used to detect geo-location load balancing.
19
},
20
'Author' => [ 'hdm' ],
21
'License' => MSF_LICENSE,
22
'References' =>
23
[
24
],
25
'DisclosureDate' => '2008-07-21'
26
))
27
28
register_options(
29
[
30
OptAddress.new('BASEDNS', [ true, 'The DNS cache server to use as a baseline', '4.2.2.3' ]),
31
OptAddress.new('TARGDNS', [ true, 'The DNS cache server to test', nil ]),
32
OptString.new('NAMES', [ true, 'The list of host names that should be tested (comma separated)', 'www.google.com,www.yahoo.com,www.msn.com']),
33
OptBool.new('CHECK_AUTHORITY', [ false, 'Set this to true to verify authority records', false ]),
34
OptBool.new('CHECK_ADDITIONAL', [ false, 'Set this to true to verify additional records', false ]),
35
36
])
37
38
end
39
40
41
def run
42
base_addr = datastore['BASEDNS']
43
targ_addr = datastore['TARGDNS']
44
check_ar = datastore['CHECK_ADDITIONAL']
45
check_aa = datastore['CHECK_AUTHORITY']
46
names = datastore['NAMES'].split(",").map {|c| c.strip }
47
recurse = true
48
results = {}
49
50
print_status("Comparing results between #{base_addr} and #{targ_addr}...")
51
52
base_sock = Rex::Socket.create_udp(
53
'PeerHost' => base_addr,
54
'PeerPort' => 53
55
)
56
57
targ_sock = Rex::Socket.create_udp(
58
'PeerHost' => targ_addr,
59
'PeerPort' => 53
60
)
61
62
names.each do |entry|
63
entry.strip!
64
next if (entry.length == 0)
65
66
req = Resolv::DNS::Message.new
67
req.add_question(entry, Resolv::DNS::Resource::IN::A)
68
req.rd = recurse ? 1 : 0
69
70
buf = req.encode
71
print_status("Querying servers for #{entry}...")
72
base_sock.put(buf)
73
targ_sock.put(buf)
74
75
base_res, base_saddr = base_sock.recvfrom(65535, 3.0)
76
targ_res, targ_saddr = targ_sock.recvfrom(65535, 3.0)
77
78
if !(base_res and targ_res and base_res.length > 0 and targ_res.length > 0)
79
print_error(" Error: The baseline server did not respond to our request.") if ! (base_res and base_res.length > 0)
80
print_error(" Error: The target server did not respond to our request.") if ! (targ_res and targ_res.length > 0)
81
next
82
end
83
84
base_res = Resolv::DNS::Message.decode(base_res)
85
targ_res = Resolv::DNS::Message.decode(targ_res)
86
87
[base_res, targ_res].each do |res|
88
hkey = (res == base_res) ? :base : :targ
89
90
rrset = res.answer
91
rrset += res.authority if check_aa
92
rrset += res.additional if check_ar
93
94
(rrset).each do |ref|
95
name,ttl,data = ref
96
97
name = name.to_s
98
anst = data.class.to_s.gsub(/^.*Resolv::DNS::Resource::IN::/, '')
99
case data
100
when Resolv::DNS::Resource::IN::NS
101
data = data.name.to_s
102
when Resolv::DNS::Resource::IN::MX
103
data = data.exchange.to_s
104
when Resolv::DNS::Resource::IN::A
105
data = data.address.to_s
106
when Resolv::DNS::Resource::IN::TXT
107
data = data.strings.join
108
when Resolv::DNS::Resource::IN::CNAME
109
data = data.name.to_s
110
else
111
data = anst
112
end
113
114
results[entry]||={}
115
results[entry][hkey]||={}
116
results[entry][hkey][anst]||=[]
117
results[entry][hkey][anst] << data
118
end
119
end
120
end
121
122
[ base_sock, targ_sock ].each {|s| s.close }
123
124
125
print_status("Analyzing results for #{results.keys.length} entries...")
126
127
results.each_key do |entry|
128
129
n_add = []
130
n_sub = []
131
132
# Look for additional entries in the target NS
133
if(results[entry][:targ])
134
results[entry][:targ].each_key do |rtype|
135
if(not results[entry][:base] or not results[entry][:base][rtype])
136
results[entry][:targ][rtype].sort.each do |ref|
137
n_sub << (" + #{entry} #{rtype} #{ref}")
138
end
139
end
140
end
141
end
142
143
if (results[entry][:base])
144
results[entry][:base].each_key do |rtype|
145
146
# Look for missing entries in the target NS
147
if(not results[entry][:targ] or not results[entry][:targ][rtype])
148
results[entry][:base][rtype].sort.each do |ref|
149
n_sub << (" - #{entry} #{rtype} #{ref}")
150
end
151
next
152
end
153
154
# Look for differences
155
if( results[entry][:base][rtype].sort != results[entry][:targ][rtype].sort )
156
results[entry][:base][rtype].sort.each do |ref|
157
if(not results[entry][:targ][rtype].include?(ref))
158
n_sub << (" - #{entry} #{rtype} #{ref}")
159
end
160
end
161
results[entry][:targ][rtype].sort.each do |ref|
162
if(not results[entry][:base][rtype].include?(ref))
163
n_add << (" + #{entry} #{rtype} #{ref}")
164
end
165
end
166
end
167
end
168
end
169
170
n_sub.each {|s| print_status(s) }
171
n_add.each {|s| print_status(s) }
172
end
173
174
end
175
end
176
177