Skip to content

Commit ef9a165

Browse files
committedNov 22, 2023
Changes from code review
1 parent 34bd661 commit ef9a165

File tree

5 files changed

+80
-32
lines changed

5 files changed

+80
-32
lines changed
 

‎lib/msf/core/framework.rb

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def initialize(options={})
8484

8585
if options.include?('CustomDnsResolver')
8686
self.dns_resolver = options['CustomDnsResolver']
87+
self.dns_resolver.set_framework(self)
8788
Rex::Socket._install_global_resolver(self.dns_resolver)
8889
end
8990

‎lib/msf/ui/console/command_dispatcher/dns.rb

+43-22
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,19 @@ def commands
4141
# Tab completion for the dns command
4242
#
4343
# @param str [String] the string currently being typed before tab was hit
44-
# @param words [Array<String>] the previously completed words on the command line. words is always
45-
# at least 1 when tab completion has reached this stage since the command itself has been completed
44+
# @param words [Array<String>] the previously completed words on the command line. The array
45+
# contains at least one entry when tab completion has reached this stage since the command itself has been completed
4646
def cmd_dns_tabs(str, words)
4747
return if driver.framework.dns_resolver.nil?
4848

4949
if words.length == 1
50-
options = ['add','del','remove','flush','print']
50+
options = ['add','del','remove','purge','print']
5151
return options.select { |opt| opt.start_with?(str) }
5252
end
5353

5454
cmd = words[1]
5555
case cmd
56-
when 'flush','print'
56+
when 'purge','print'
5757
# These commands don't have any arguments
5858
return
5959
when 'add'
@@ -95,33 +95,41 @@ def cmd_dns_tabs(str, words)
9595
end
9696

9797
def cmd_dns_help
98-
print_line 'Usage: dns'
99-
print_line
10098
print_line "Manage Metasploit's DNS resolution behaviour"
10199
print_line
102100
print_line "Usage:"
103-
print_line " dns [add/remove] [--session <session_id>] [--rule <wildcard DNS entry>] <IP Address> <IP Address> ..."
104-
print_line " dns [get] <hostname>"
105-
print_line " dns [flush]"
101+
print_line " dns [add] [--session <session_id>] [--rule <wildcard DNS entry>] <IP Address> <IP Address> ..."
102+
print_line " dns [remove/del] -i <entry id> [-i <entry id> ...]"
103+
print_line " dns [purge]"
106104
print_line " dns [print]"
107105
print_line
108106
print_line "Subcommands:"
109107
print_line " add - add a DNS resolution entry to resolve certain domain names through a particular DNS server"
110108
print_line " remove - delete a DNS resolution entry; 'del' is an alias"
111-
print_line " flush - remove all DNS resolution entries"
109+
print_line " purge - remove all DNS resolution entries"
112110
print_line " print - show all active DNS resolution entries"
113111
print_line
114112
print_line "Examples:"
115-
print_line " Set the DNS server to be used for *.metasploit.com to 192.168.1.10"
113+
print_line " Display all current DNS nameserver entries"
114+
print_line " dns"
115+
print_line " dns print"
116+
print_line
117+
print_line " Set the DNS server(s) to be used for *.metasploit.com to 192.168.1.10"
116118
print_line " route add --rule *.metasploit.com 192.168.1.10"
117119
print_line
118-
print_line " Set the DNS server to be used for *.metasploit.com to 192.168.1.10, but specifically to go through session 2"
120+
print_line " Add multiple entries at once"
121+
print_line " route add --rule *.metasploit.com --rule *.google.com 192.168.1.10 192.168.1.11"
122+
print_line
123+
print_line " Set the DNS server(s) to be used for *.metasploit.com to 192.168.1.10, but specifically to go through session 2"
119124
print_line " route add --session 2 --rule *.metasploit.com 192.168.1.10"
120125
print_line
121-
print_line " Delete the above DNS resolution rule"
122-
print_line " route remove --session 2 --rule *.metasploit.com 192.168.1.10"
126+
print_line " Delete the DNS resolution rule with ID 3"
127+
print_line " route remove -i 3"
123128
print_line
124-
print_line " Set the DNS server to be used for all requests that match no rules"
129+
print_line " Delete multiple entries in one command"
130+
print_line " route remove -i 3 -i 4 -i 5"
131+
print_line
132+
print_line " Set the DNS server(s) to be used for all requests that match no rules"
125133
print_line " route add 8.8.8.8 8.8.4.4"
126134
print_line
127135
end
@@ -217,7 +225,7 @@ def add_dns(*args)
217225
servers.each do |server|
218226
driver.framework.dns_resolver.add_nameserver(rules, server, comm_obj)
219227
end
220-
print_good("DNS #{servers.length > 1 ? 'entries' : 'entry'} added")
228+
print_good("#{servers.length} DNS #{servers.length > 1 ? 'entries' : 'entry'} added")
221229
end
222230

223231
#
@@ -238,7 +246,7 @@ def remove_dns(*args)
238246
print_warning("Some entries were not removed: #{difference.join(', ')}") unless difference.empty?
239247
if removed.length > 0
240248
print_good("#{removed.length} DNS #{removed.length > 1 ? 'entries' : 'entry'} removed")
241-
print_dns_set('Deleted entries', ['ID', 'Rules(s)', 'DNS Server', 'Commm channel'], removed.map {|hash| [hash[:id], hash[:wildcard_rules].join(','), hash[:dns_server], prettify_comm(hash[:comm], hash[:dns_server])]})
249+
print_dns_set('Deleted entries', removed)
242250
end
243251
end
244252

@@ -256,11 +264,13 @@ def purge_dns
256264
def print_dns
257265
results = driver.framework.dns_resolver.nameserver_entries
258266
columns = ['ID','Rule(s)', 'DNS Server', 'Comm channel']
259-
print_dns_set('Custom nameserver rules', columns, results[0].map {|hash| [hash[:id], hash[:wildcard_rules].join(','), hash[:dns_server], prettify_comm(hash[:comm], hash[:dns_server])]})
267+
print_dns_set('Custom nameserver rules', results[0])
260268

261269
# Default nameservers don't include a rule
262270
columns = ['ID', 'DNS Server', 'Comm channel']
263-
print_dns_set('Default nameservers', columns, results[1].map {|hash| [hash[:id], hash[:dns_server], prettify_comm(hash[:comm], hash[:dns_server])]})
271+
print_dns_set('Default nameservers', results[1])
272+
273+
print_line('No custom DNS nameserver entries configured') if results[0].length + results[1].length == 0
264274
end
265275

266276
private
@@ -285,16 +295,27 @@ def prettify_comm(comm, dns_server)
285295
end
286296
end
287297

288-
def print_dns_set(heading, columns, result_set)
298+
def print_dns_set(heading, result_set)
299+
return if result_set.length == 0
300+
if result_set[0][:wildcard_rules].any?
301+
columns = ['ID', 'Rules(s)', 'DNS Server', 'Commm channel']
302+
else
303+
columns = ['ID', 'DNS Server', 'Commm channel']
304+
end
305+
289306
tbl = Table.new(
290307
Table::Style::Default,
291308
'Header' => heading,
292309
'Prefix' => "\n",
293310
'Postfix' => "\n",
294311
'Columns' => columns
295312
)
296-
result_set.each do |row|
297-
tbl << row
313+
result_set.each do |hash|
314+
if columns.size == 4
315+
tbl << [hash[:id], hash[:wildcard_rules].join(','), hash[:dns_server], prettify_comm(hash[:comm], hash[:dns_server])]
316+
else
317+
tbl << [hash[:id], hash[:dns_server], prettify_comm(hash[:comm], hash[:dns_server])]
318+
end
298319
end
299320

300321
print(tbl.to_s) if tbl.rows.length > 0

‎lib/rex/proto/dns/custom_nameserver_provider.rb

+10-2
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ def purge
161161
# @return [Array<Array>] A list of nameservers, each with Rex::Socket options
162162
#
163163
def nameservers_for_packet(packet)
164+
unless feature_set.enabled?(Msf::FeatureManager::DNS_FEATURE)
165+
return super
166+
end
164167
# Leaky abstraction: a packet could have multiple question entries,
165168
# and each of these could have different nameservers, or travel via
166169
# different comm channels. We can't allow DNS leaks, so for now, we
@@ -172,9 +175,9 @@ def nameservers_for_packet(packet)
172175

173176
self.entries_with_rules.each do |entry|
174177
entry[:wildcard_rules].each do |rule|
175-
socket_options = {}
176-
socket_options['Comm'] = entry[:comm] unless entry[:comm].nil?
177178
if matches(name, rule)
179+
socket_options = {}
180+
socket_options['Comm'] = entry[:comm] unless entry[:comm].nil?
178181
dns_servers.append([entry[:dns_server], socket_options])
179182
break
180183
end
@@ -208,6 +211,10 @@ def self.extended(mod)
208211
mod.init
209212
end
210213

214+
def set_framework(framework)
215+
self.feature_set = framework.features
216+
end
217+
211218
private
212219
#
213220
# Is the given wildcard DNS entry valid?
@@ -228,6 +235,7 @@ def matches(domain, pattern)
228235
attr_accessor :entries_with_rules # Set of custom nameserver entries that specify a rule
229236
attr_accessor :entries_without_rules # Set of custom nameserver entries that do not include a rule
230237
attr_accessor :next_id # The next ID to have been allocated to an entry
238+
attr_accessor :feature_set
231239
end
232240
end
233241
end

‎lib/rex/proto/dns/resolver.rb

+8-8
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,11 @@ def proxies=(prox, timeout_added = 250)
112112

113113
#
114114
# Find the nameservers to use for a given DNS request
115-
# @param dns_message [Dnsruby::Message] The DNS message to be sent
115+
# @param _dns_message [Dnsruby::Message] The DNS message to be sent
116116
#
117117
# @return [Array<Array>] A list of nameservers, each with Rex::Socket options
118118
#
119-
def nameservers_for_packet(dns_message)
119+
def nameservers_for_packet(_dns_message)
120120
@config[:nameservers].map {|ns| [ns, {}]}
121121
end
122122

@@ -174,7 +174,7 @@ def send(argument, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN)
174174
method = :send_tcp
175175
end
176176

177-
ans = self.__send__(method, packet, packet_data)
177+
ans = self.__send__(method, packet, packet_data, nameservers)
178178

179179
unless (ans and ans[0].length > 0)
180180
@logger.fatal "No response from nameservers list: aborting"
@@ -203,13 +203,13 @@ def send(argument, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN)
203203
#
204204
# @param packet [Net::DNS::Packet] Packet associated with packet_data
205205
# @param packet_data [String] Data segment of DNS request packet
206+
# @param nameservers [Array<[String,Hash]>] List of nameservers to use for this request, and their associated socket options
206207
# @param prox [String] Proxy configuration for TCP socket
207208
#
208209
# @return ans [String] Raw DNS reply
209-
def send_tcp(packet,packet_data,prox = @config[:proxies])
210+
def send_tcp(packet, packet_data, nameservers, prox = @config[:proxies])
210211
ans = nil
211212
length = [packet_data.size].pack("n")
212-
nameservers = nameservers_for_packet(packet)
213213
nameservers.each do |ns, socket_options|
214214
begin
215215
socket = nil
@@ -307,12 +307,12 @@ def send_tcp(packet,packet_data,prox = @config[:proxies])
307307
#
308308
# @param packet [Net::DNS::Packet] Packet associated with packet_data
309309
# @param packet_data [String] Data segment of DNS request packet
310+
# @param nameservers [Array<[String,Hash]>] List of nameservers to use for this request, and their associated socket options
310311
#
311312
# @return ans [String] Raw DNS reply
312-
def send_udp(packet,packet_data)
313+
def send_udp(packet,packet_data, nameservers)
313314
ans = nil
314315
response = ""
315-
nameservers = nameservers_for_packet(packet)
316316
nameservers.each do |ns, socket_options|
317317
catch(:next_ns) do
318318
begin
@@ -414,7 +414,7 @@ def query(name, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN)
414414

415415
def supports_udp?(nameserver_results)
416416
nameserver_results.each do |nameserver, socket_options|
417-
comm = socket_options.fetch('Comm') { @config.fetch(:comm) { Rex::Socket::SwitchBoard.best_comm(ns) }}
417+
comm = socket_options.fetch('Comm') { @config[:comm] || Rex::Socket::SwitchBoard.best_comm(nameserver) }
418418
next if comm.nil?
419419
return false unless comm.supports_udp?
420420
end

‎spec/lib/rex/proto/dns/custom_nameserver_provider_spec.rb

+18
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,20 @@ def packet_for(name)
3333
{:dns_cache_no_start => true}
3434
end
3535

36+
let (:framework_with_dns_enabled) do
37+
framework = Object.new
38+
def framework.features
39+
f = Object.new
40+
def f.enabled?(_name)
41+
true
42+
end
43+
44+
f
45+
end
46+
47+
framework
48+
end
49+
3650
subject(:many_ruled_provider) do
3751
dns_resolver = Rex::Proto::DNS::CachedResolver.new(config)
3852
dns_resolver.extend(Rex::Proto::DNS::CustomNameserverProvider)
@@ -41,6 +55,7 @@ def packet_for(name)
4155
dns_resolver.add_nameserver(['*.metasploit.com'], ruled_nameserver, nil)
4256
dns_resolver.add_nameserver(['*.metasploit.com'], ruled_nameserver2, nil)
4357
dns_resolver.add_nameserver(['*.notmetasploit.com'], ruled_nameserver3, nil)
58+
dns_resolver.set_framework(framework_with_dns_enabled)
4459

4560
dns_resolver
4661
end
@@ -51,6 +66,7 @@ def packet_for(name)
5166
dns_resolver.nameservers = [base_nameserver]
5267
dns_resolver.add_nameserver([], ruleless_nameserver, nil)
5368
dns_resolver.add_nameserver(['*.metasploit.com'], ruled_nameserver, nil)
69+
dns_resolver.set_framework(framework_with_dns_enabled)
5470

5571
dns_resolver
5672
end
@@ -60,6 +76,7 @@ def packet_for(name)
6076
dns_resolver.extend(Rex::Proto::DNS::CustomNameserverProvider)
6177
dns_resolver.nameservers = [base_nameserver]
6278
dns_resolver.add_nameserver([], ruleless_nameserver, nil)
79+
dns_resolver.set_framework(framework_with_dns_enabled)
6380

6481
dns_resolver
6582
end
@@ -68,6 +85,7 @@ def packet_for(name)
6885
dns_resolver = Rex::Proto::DNS::CachedResolver.new(config)
6986
dns_resolver.extend(Rex::Proto::DNS::CustomNameserverProvider)
7087
dns_resolver.nameservers = [base_nameserver]
88+
dns_resolver.set_framework(framework_with_dns_enabled)
7189

7290
dns_resolver
7391
end

0 commit comments

Comments
 (0)
Please sign in to comment.