@@ -7,18 +7,100 @@ module DNS
77 # for different requests, based on the domain being queried.
88 ##
99 module CustomNameserverProvider
10+ CONFIG_KEY = 'framework/dns'
11+
12+ #
13+ # A Comm implementation that always reports as dead, so should never
14+ # be used. This is used to prevent DNS leaks of saved DNS rules that
15+ # were attached to a specific channel.
16+ ##
17+ class CommSink
18+ include Msf ::Session ::Comm
19+ def alive?
20+ false
21+ end
22+
23+ def supports_udp?
24+ # It won't be used anyway, so let's just say we support it
25+ true
26+ end
27+
28+ def sid
29+ 'previous MSF session'
30+ end
31+ end
1032
1133 def init
1234 self . entries_with_rules = [ ]
1335 self . entries_without_rules = [ ]
1436 self . next_id = 0
1537 end
1638
39+ def save_config
40+ new_config = { }
41+ [ self . entries_with_rules , self . entries_without_rules ] . each do |entry_set |
42+ entry_set . each do |entry |
43+ key = entry [ :id ] . to_s
44+ val = [ entry [ :wildcard_rules ] . join ( ',' ) ,
45+ entry [ :dns_server ] ,
46+ ( !entry [ :comm ] . nil? ) . to_s
47+ ] . join ( ';' )
48+ new_config [ key ] = val
49+ end
50+ end
51+
52+ Msf ::Config . save ( CONFIG_KEY => new_config )
53+ end
54+
55+ def load_config
56+ config = Msf ::Config . load
57+
58+ with_rules = [ ]
59+ without_rules = [ ]
60+ next_id = 0
61+
62+ dns_settings = config . fetch ( CONFIG_KEY , { } ) . each do |name , value |
63+ id = name . to_i
64+ wildcard_rules , dns_server , uses_comm = value . split ( ';' )
65+ wildcard_rules = wildcard_rules . split ( ',' )
66+
67+ raise Msf ::Config ::ConfigError . new ( 'DNS parsing failed: Comm must be true or false' ) unless [ 'true' , 'false' ] . include? ( uses_comm )
68+ raise Msf ::Config ::ConfigError . new ( 'Invalid DNS config: Invalid DNS server' ) unless Rex ::Socket . is_ip_addr? ( dns_server )
69+ raise Msf ::Config ::ConfigError . new ( 'Invalid DNS config: Invalid rule' ) unless wildcard_rules . all? { |rule | valid_rule? ( rule ) }
70+
71+ comm = uses_comm == 'true' ? CommSink . new : nil
72+ entry = {
73+ :wildcard_rules => wildcard_rules ,
74+ :dns_server => dns_server ,
75+ :comm => comm ,
76+ :id => id
77+ }
78+
79+ if wildcard_rules . empty?
80+ without_rules << entry
81+ else
82+ with_rules << entry
83+ end
84+
85+ next_id = [ id , next_id ] . max
86+ end
87+
88+ # Now that config has successfully read, update the global values
89+ self . entries_with_rules = with_rules
90+ self . entries_without_rules = without_rules
91+ self . next_id = next_id
92+ end
93+
1794 # Add a custom nameserver entry to the custom provider
1895 # @param [wildcard_rules] Array<String> The wildcard rules to match a DNS request against
1996 # @param [dns_server] Array<String> The list of IP addresses that would be used for this custom rule
20- # @param comm [Integer ] The communication channel to be used for these DNS requests
97+ # @param comm [Msf::Session::Comm ] The communication channel to be used for these DNS requests
2198 def add_nameserver ( wildcard_rules , dns_server , comm )
99+ raise ::ArgumentError . new ( "Invalid DNS server: #{ dns_server } " ) unless Rex ::Socket . is_ip_addr? ( dns_server )
100+ wildcard_rules . each do |rule |
101+ raise ::ArgumentError . new ( "Invalid rule: #{ rule } " ) unless valid_rule? ( rule )
102+ end
103+
22104 entry = {
23105 :wildcard_rules => wildcard_rules ,
24106 :dns_server => dns_server ,
@@ -103,6 +185,13 @@ def self.extended(mod)
103185 end
104186
105187 private
188+ #
189+ # Is the given wildcard DNS entry valid?
190+ #
191+ def valid_rule? ( rule )
192+ rule =~ /^(\* \. )?([a-z\d ][a-z\d -]*[a-z\d ]\. )+[a-z]+$/
193+ end
194+
106195
107196 def matches ( domain , pattern )
108197 if pattern . start_with? ( '*.' )
0 commit comments