Skip to content

Commit a91a5f3

Browse files
committed
Land rapid7#4067, @fozavci's IN:SRV support for fakedns
2 parents 31b366d + 684975a commit a91a5f3

File tree

1 file changed

+72
-29
lines changed

1 file changed

+72
-29
lines changed

modules/auxiliary/server/fakedns.rb

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def initialize
2020
This module provides a DNS service that redirects
2121
all queries to a particular address.
2222
},
23-
'Author' => ['ddz', 'hdm'],
23+
'Author' => ['ddz', 'hdm', 'fozavci'],
2424
'License' => MSF_LICENSE,
2525
'Actions' =>
2626
[
@@ -44,22 +44,27 @@ def initialize
4444

4545
register_advanced_options(
4646
[
47+
OptPort.new('RR_SRV_PORT', [ false, "The port field in the SRV response when FAKE", 5060]),
4748
OptBool.new('LogConsole', [ false, "Determines whether to log all request to the console", true]),
4849
OptBool.new('LogDatabase', [ false, "Determines whether to log all request to the database", false]),
4950
], self.class)
5051
end
5152

5253

53-
def run
54-
@targ = datastore['TARGETHOST']
55-
if(@targ and @targ.strip.length == 0)
56-
@targ = nil
57-
end
58-
59-
if(@targ)
60-
@targ = ::Rex::Socket.resolv_to_dotted(@targ)
54+
def target_host(addr = nil)
55+
target = datastore['TARGETHOST']
56+
if target.blank?
57+
if addr
58+
::Rex::Socket.source_address(addr)
59+
else
60+
nil
61+
end
62+
else
63+
::Rex::Socket.resolv_to_dotted(target)
6164
end
65+
end
6266

67+
def run
6368
@port = datastore['SRVPORT'].to_i
6469

6570
@log_console = false
@@ -90,10 +95,12 @@ def run
9095
while @run
9196
@error_resolving = false
9297
packet, addr = @sock.recvfrom(65535)
98+
src_addr = addr[3]
9399
@requestor = addr
94-
break if packet.length == 0
100+
next if packet.length == 0
95101

96102
request = Resolv::DNS::Message.decode(packet)
103+
next unless request.qr == 0
97104

98105
#
99106
# XXX: Track request IDs by requesting IP address and port
@@ -109,6 +116,18 @@ def run
109116
lst = []
110117

111118
request.each_question {|name, typeclass|
119+
# Identify potential domain exceptions
120+
@match_target = false
121+
@match_name = name.to_s
122+
@domain_target_list.each do |ex|
123+
escaped = Regexp.escape(ex).gsub('\*','.*?')
124+
regex = Regexp.new "^#{escaped}$", Regexp::IGNORECASE
125+
if ( name.to_s =~ regex )
126+
@match_target = true
127+
@match_name = ex
128+
end
129+
end
130+
112131
tc_s = typeclass.to_s().gsub(/^Resolv::DNS::Resource::/, "")
113132

114133
request.qr = 1
@@ -130,25 +149,12 @@ def run
130149
# <hostname> SOA -> windows XP self hostname lookup
131150
#
132151

133-
answer = Resolv::DNS::Resource::IN::A.new( @targ || ::Rex::Socket.source_address(addr[3].to_s) )
134-
135-
# Identify potential domain exceptions
136-
@match_target = false
137-
@match_name = name.to_s
138-
@domain_target_list.each do |ex|
139-
escaped = Regexp.escape(ex).gsub('\*','.*?')
140-
regex = Regexp.new "^#{escaped}$", Regexp::IGNORECASE
141-
if ( name.to_s =~ regex )
142-
@match_target = true
143-
@match_name = ex
144-
end
145-
end
152+
answer = Resolv::DNS::Resource::IN::A.new(target_host(src_addr))
146153

147154
if (@match_target and not @bypass) or (not @match_target and @bypass)
148155
# Resolve FAKE response
149156
if (@log_console)
150-
print_status("DNS target domain found: #{@match_name}")
151-
print_status("DNS target domain #{name.to_s} faked")
157+
print_status("DNS target domain #{@match_name} found; Returning fake A records for #{name}")
152158
end
153159
else
154160
# Resolve the exception domain
@@ -160,8 +166,7 @@ def run
160166
next
161167
end
162168
if (@log_console)
163-
print_status("DNS bypass domain found: #{@match_name}")
164-
print_status("DNS bypass domain #{name.to_s} resolved #{ip}")
169+
print_status("DNS bypass domain #{@match_name} found; Returning real A records for #{name}")
165170
end
166171
end
167172

@@ -171,16 +176,54 @@ def run
171176
when 'IN::MX'
172177
mx = Resolv::DNS::Resource::IN::MX.new(10, Resolv::DNS::Name.create("mail.#{name}"))
173178
ns = Resolv::DNS::Resource::IN::NS.new(Resolv::DNS::Name.create("dns.#{name}"))
174-
ar = Resolv::DNS::Resource::IN::A.new( @targ || ::Rex::Socket.source_address(addr[3].to_s) )
179+
ar = Resolv::DNS::Resource::IN::A.new(target_host(src_addr))
175180
request.add_answer(name, 60, mx)
176181
request.add_authority(name, 60, ns)
177182
request.add_additional(Resolv::DNS::Name.create("mail.#{name}"), 60, ar)
178183

179184
when 'IN::NS'
180185
ns = Resolv::DNS::Resource::IN::NS.new(Resolv::DNS::Name.create("dns.#{name}"))
181-
ar = Resolv::DNS::Resource::IN::A.new( @targ || ::Rex::Socket.source_address(addr[3].to_s) )
186+
ar = Resolv::DNS::Resource::IN::A.new(target_host(src_addr))
182187
request.add_answer(name, 60, ns)
183188
request.add_additional(name, 60, ar)
189+
190+
when 'IN::SRV'
191+
if @bypass || !@match_target
192+
if @log_console
193+
print_status("DNS bypass domain #{@match_name} found; Returning real SRV records for #{name}")
194+
end
195+
# if we are in bypass mode or we are in fake mode but the target didn't match,
196+
# just return the real response RRs
197+
resources = Resolv::DNS.new().getresources(Resolv::DNS::Name.create(name), Resolv::DNS::Resource::IN::SRV)
198+
if resources.empty?
199+
@error_resolving = true
200+
print_error("Unable to resolve SRV record for #{name} -- skipping")
201+
next
202+
end
203+
resources.each do |resource|
204+
host = resource.target
205+
port = resource.port.to_i
206+
weight = resource.weight.to_i
207+
priority = resource.priority.to_i
208+
ttl = resource.ttl.to_i
209+
request.add_answer(
210+
name,
211+
ttl,
212+
Resolv::DNS::Resource::IN::SRV.new(priority, weight, port, Resolv::DNS::Name.create(host))
213+
)
214+
end
215+
else
216+
if @log_console
217+
print_status("DNS target domain #{@match_name} found; Returning fake SRV records for #{name}")
218+
# Prepare the FAKE response
219+
request.add_answer(
220+
name,
221+
10,
222+
Resolv::DNS::Resource::IN::SRV.new(5, 0, datastore['RR_SRV_PORT'], Resolv::DNS::Name.create(name))
223+
)
224+
request.add_additional(Resolv::DNS::Name.create(name), 60, Resolv::DNS::Resource::IN::A.new(target_host(src_addr)))
225+
end
226+
end
184227
when 'IN::PTR'
185228
soa = Resolv::DNS::Resource::IN::SOA.new(
186229
Resolv::DNS::Name.create("ns.internet.com"),

0 commit comments

Comments
 (0)