8
8
class Metasploit3 < Msf ::Auxiliary
9
9
10
10
include Msf ::Auxiliary ::Report
11
- include Msf ::Auxiliary ::Scanner
11
+ include Msf ::Exploit ::Remote ::Udp
12
+ include Msf ::Auxiliary ::UDPScanner
13
+ include Msf ::Auxiliary ::NTP
14
+ include Msf ::Auxiliary ::DRDoS
12
15
13
16
def initialize
14
17
super (
@@ -33,10 +36,7 @@ def initialize
33
36
34
37
register_options (
35
38
[
36
- Opt ::RPORT ( 123 ) ,
37
- Opt ::CHOST ,
38
39
OptInt . new ( 'RETRY' , [ false , "Number of tries to query the NTP server" , 3 ] ) ,
39
- OptInt . new ( 'BATCHSIZE' , [ true , 'The number of hosts to probe in each set' , 256 ] ) ,
40
40
OptBool . new ( 'SHOW_LIST' , [ false , 'Show the recent clients list' , 'false' ] )
41
41
] , self . class )
42
42
@@ -46,134 +46,112 @@ def initialize
46
46
] , self . class )
47
47
end
48
48
49
- # Define our batch size
50
- def run_batch_size
51
- datastore [ 'BATCHSIZE' ] . to_i
49
+ # Called for each IP in the batch
50
+ def scan_host ( ip )
51
+ scanner_send ( @probe , ip , datastore [ 'RPORT' ] )
52
52
end
53
53
54
- # Fingerprint a single host
55
- def run_batch ( batch )
54
+ # Called for each response packet
55
+ def scanner_process ( data , shost , sport )
56
+ @results [ shost ] ||= { messages : [ ] , peers : [ ] }
57
+ @results [ shost ] [ :messages ] << Rex ::Proto ::NTP ::NTPPrivate . new ( data )
58
+ @results [ shost ] [ :peers ] << extract_peer_tuples ( data )
59
+ end
56
60
61
+ # Called before the scan block
62
+ def scanner_prescan ( batch )
57
63
@results = { }
58
64
@aliases = { }
65
+ @probe = Rex ::Proto ::NTP . ntp_private ( datastore [ 'VERSION' ] , datastore [ 'IMPLEMENTATION' ] , 42 )
66
+ end
59
67
60
- vprint_status ( "Sending probes to #{ batch [ 0 ] } ->#{ batch [ -1 ] } (#{ batch . length } hosts)" )
61
-
62
- begin
63
- udp_sock = nil
64
- idx = 0
65
-
66
- # Create an unbound UDP socket if no CHOST is specified, otherwise
67
- # create a UDP socket bound to CHOST (in order to avail of pivoting)
68
- udp_sock = Rex ::Socket ::Udp . create ( {
69
- 'LocalHost' => datastore [ 'CHOST' ] || nil ,
70
- 'Context' => { 'Msf' => framework , 'MsfExploit' => self }
71
- } )
72
- add_socket ( udp_sock )
73
-
74
- # Try more times since NTP servers can be a bit busy
75
- 1 . upto ( datastore [ 'RETRY' ] . to_i ) do
76
- batch . each do |ip |
77
- next if @results [ ip ]
78
-
79
- begin
80
- data = probe_pkt_ntp
81
- udp_sock . sendto ( data , ip , datastore [ 'RPORT' ] . to_i , 0 )
82
- rescue ::Interrupt
83
- raise $!
84
- rescue ::Rex ::HostUnreachable , ::Rex ::ConnectionTimeout , ::Rex ::ConnectionRefused
85
- nil
86
- end
87
-
88
- if ( idx % 30 == 0 )
89
- while ( r = udp_sock . recvfrom ( 65535 , 0.1 ) and r [ 1 ] )
90
- parse_reply ( r )
91
- end
92
- end
93
-
94
- idx += 1
95
- end
96
- end
97
-
98
- while ( r = udp_sock . recvfrom ( 65535 , 10 ) and r [ 1 ] )
99
- parse_reply ( r )
100
- end
101
-
102
- rescue ::Interrupt
103
- raise $!
104
- rescue ::Exception => e
105
- print_error ( "Unknown error: #{ e . class } #{ e } " )
106
- end
107
-
68
+ # Called after the scan block
69
+ def scanner_postscan ( batch )
108
70
@results . keys . each do |k |
71
+ response_map = { @probe => @results [ k ] [ :messages ] }
72
+ peer = "#{ k } :#{ rport } "
109
73
74
+ # TODO: check to see if any of the responses are actually NTP before reporting
110
75
report_service (
111
76
:host => k ,
112
77
:proto => 'udp' ,
113
- :port => datastore [ 'RPORT' ] . to_i ,
78
+ :port => rport ,
114
79
:name => 'ntp'
115
80
)
116
81
117
- report_note (
118
- :host => k ,
119
- :proto => 'udp' ,
120
- :port => datastore [ 'RPORT' ] . to_i ,
121
- :type => 'ntp.monlist' ,
122
- :data => { :monlist => @results [ k ] }
123
- )
124
-
125
- if ( @aliases [ k ] and @aliases [ k ] . keys [ 0 ] != k )
126
- print_good ( "#{ k } :#{ datastore [ 'RPORT' ] . to_i } NTP monlist request permitted (#{ @results [ k ] . length } entries)" )
82
+ peers = @results [ k ] [ :peers ] . flatten ( 1 )
83
+ unless peers . empty?
84
+ print_good ( "#{ peer } NTP monlist request permitted (#{ peers . length } entries)" )
85
+ # store the peers found from the monlist
86
+ report_note (
87
+ :host => k ,
88
+ :proto => 'udp' ,
89
+ :port => rport ,
90
+ :type => 'ntp.monlist' ,
91
+ :data => { :monlist => peers }
92
+ )
93
+ # print out peers if desired
94
+ if datastore [ 'SHOW_LIST' ]
95
+ peers . each do |ntp_peer |
96
+ print_status ( "#{ peer } #{ ntp_peer } " )
97
+ end
98
+ end
99
+ # store any aliases for our target
127
100
report_note (
128
101
:host => k ,
129
102
:proto => 'udp' ,
130
- :port => datastore [ 'RPORT' ] . to_i ,
103
+ :port => rport ,
131
104
:type => 'ntp.addresses' ,
132
- :data => { :addresses => @aliases [ k ] . keys }
105
+ :data => { :addresses => peers . map { | p | p . last } . sort . uniq }
133
106
)
134
- end
135
107
136
- if ( datastore [ 'StoreNTPClients' ] )
137
- print_status ( "#{ k } Storing #{ @results [ k ] . length } NTP client hosts in the database..." )
138
- @results [ k ] . each do |r |
139
- maddr , mport , mserv = r
140
- report_note (
141
- :host => maddr ,
142
- :type => 'ntp.client.history' ,
143
- :data => {
144
- :address => maddr ,
145
- :port => mport ,
146
- :server => mserv
147
- }
148
- )
108
+ if ( datastore [ 'StoreNTPClients' ] )
109
+ print_status ( "#{ peer } Storing #{ peers . length } NTP client hosts in the database..." )
110
+ peers . each do |r |
111
+ maddr , mport , mserv = r
112
+ next if maddr == '127.0.0.1' # some NTP servers peer with themselves..., but we can't store loopback
113
+ report_note (
114
+ :host => maddr ,
115
+ :type => 'ntp.client.history' ,
116
+ :data => {
117
+ :address => maddr ,
118
+ :port => mport ,
119
+ :server => mserv
120
+ }
121
+ )
122
+ end
149
123
end
150
124
end
151
- end
152
-
153
- end
154
-
155
- def parse_reply ( pkt )
156
125
157
- # Ignore "empty" packets
158
- return if not pkt [ 1 ]
159
-
160
- if ( pkt [ 1 ] =~ /^::ffff:/ )
161
- pkt [ 1 ] = pkt [ 1 ] . sub ( /^::ffff:/ , '' )
126
+ vulnerable , proof = prove_drdos ( response_map )
127
+ what = 'NTP Mode 7 monlist DRDoS (CVE-2013-5211)'
128
+ if vulnerable
129
+ print_good ( "#{ peer } - Vulnerable to #{ what } : #{ proof } " )
130
+ report_vuln ( {
131
+ :host => k ,
132
+ :port => rport ,
133
+ :proto => 'udp' ,
134
+ :name => what ,
135
+ :refs => self . references
136
+ } )
137
+ else
138
+ vprint_status ( "#{ peer } - Not vulnerable to #{ what } : #{ proof } " )
139
+ end
162
140
end
163
141
164
- data = pkt [ 0 ]
165
- host = pkt [ 1 ]
166
- port = pkt [ 2 ]
142
+ end
167
143
168
- return if pkt [ 0 ] . length < ( 72 + 16 )
144
+ # Examine the monlist reponse +data+ and extract all peer tuples (saddd, dport, daddr)
145
+ def extract_peer_tuples ( data )
146
+ return [ ] if data . length < 76
169
147
170
148
# NTP headers 8 bytes
171
149
ntp_flags , ntp_auth , ntp_vers , ntp_code = data . slice! ( 0 , 4 ) . unpack ( 'C*' )
172
- vprint_status ( "#{ host } :#{ port } - ntp_auth: #{ ntp_auth } , ntp_vers: #{ ntp_vers } " )
173
150
pcnt , plen = data . slice! ( 0 , 4 ) . unpack ( 'nn' )
174
- return if plen != 72
151
+ return [ ] if plen != 72
175
152
176
153
idx = 0
154
+ peer_tuples = [ ]
177
155
1 . upto ( pcnt ) do
178
156
#u_int32 firsttime; /* first time we received a packet */
179
157
#u_int32 lasttime; /* last packet from this host */
@@ -184,21 +162,11 @@ def parse_reply(pkt)
184
162
#u_int32 flags; /* flags about destination */
185
163
#u_short port; /* port number of last reception */
186
164
187
- firsttime , lasttime , restr , count , saddr , daddr , flags , dport = data [ idx , 30 ] . unpack ( "NNNNNNNn" )
165
+ _ , _ , _ , _ , saddr , daddr , _ , dport = data [ idx , 30 ] . unpack ( "NNNNNNNn" )
188
166
189
- @results [ host ] ||= [ ]
190
- @aliases [ host ] ||= { }
191
- @results [ host ] << [ Rex ::Socket . addr_itoa ( daddr ) , dport , Rex ::Socket . addr_itoa ( saddr ) ]
192
- @aliases [ host ] [ Rex ::Socket . addr_itoa ( saddr ) ] = true
193
- if datastore [ 'SHOW_LIST' ]
194
- print_status ( "#{ host } :#{ port } #{ Rex ::Socket . addr_itoa ( saddr ) } (lst: #{ lasttime } sec., cnt: #{ count } )" )
195
- end
167
+ peer_tuples << [ Rex ::Socket . addr_itoa ( saddr ) , dport , Rex ::Socket . addr_itoa ( daddr ) ]
196
168
idx += plen
197
169
end
170
+ peer_tuples
198
171
end
199
-
200
- def probe_pkt_ntp
201
- "\x17 \x00 \x03 \x2a " + "\x00 " * 188
202
- end
203
-
204
172
end
0 commit comments