@@ -49,260 +49,15 @@ def run_batch_size
49
49
# Operate on an entire batch of hosts at once
50
50
def run_batch ( batch )
51
51
52
- @found = { }
53
- @tried = [ ]
52
+ batch . each do |ip |
54
53
55
- begin
56
- udp_sock = nil
57
- idx = 0
58
54
59
- # Create an unbound UDP socket if no CHOST is specified, otherwise
60
- # create a UDP socket bound to CHOST (in order to avail of pivoting)
61
- udp_sock = Rex ::Socket ::Udp . create ( { 'LocalHost' => datastore [ 'CHOST' ] || nil , 'Context' => { 'Msf' => framework , 'MsfExploit' => self } } )
62
- add_socket ( udp_sock )
63
55
64
- each_user_pass do |user , pass |
65
- comm = pass
66
-
67
- data1 = create_probe_snmp1 ( comm )
68
- data2 = create_probe_snmp2 ( comm )
69
-
70
- batch . each do |ip |
71
- fq_pass = [ ip , pass ]
72
- next if @tried . include? fq_pass
73
- @tried << fq_pass
74
- vprint_status "#{ ip } :#{ datastore [ 'RPORT' ] } - SNMP - Trying #{ ( pass . nil? || pass . empty? ) ? "<BLANK>" : pass } ..."
75
-
76
- begin
77
- udp_sock . sendto ( data1 , ip , datastore [ 'RPORT' ] . to_i , 0 )
78
- udp_sock . sendto ( data2 , ip , datastore [ 'RPORT' ] . to_i , 0 )
79
- rescue ::Interrupt
80
- raise $!
81
- rescue ::Rex ::HostUnreachable , ::Rex ::ConnectionTimeout , ::Rex ::ConnectionRefused
82
- nil
83
- end
84
-
85
- if ( idx % 10 == 0 )
86
- while ( r = udp_sock . recvfrom ( 65535 , 0.25 ) and r [ 1 ] )
87
- parse_reply ( r )
88
- end
89
- end
90
-
91
- idx += 1
92
-
93
- end
94
- end
95
-
96
- idx = 0
97
- while ( r = udp_sock . recvfrom ( 65535 , 3 ) and r [ 1 ] and idx < 500 )
98
- parse_reply ( r )
99
- idx += 1
100
- end
101
-
102
- if @found . keys . length > 0
103
- print_status ( "Validating scan results from #{ @found . keys . length } hosts..." )
104
- end
105
-
106
- # Review all successful communities and determine write access
107
- @found . keys . sort . each do |host |
108
- fake_comm = Rex ::Text . rand_text_alphanumeric ( 8 )
109
- anycomm_ro = false
110
- anycomm_rw = false
111
- comms_ro = [ ]
112
- comms_rw = [ ]
113
- finished = false
114
- versions = [ "1" , "2" ]
115
-
116
- versions . each do |version |
117
- comms_todo = @found [ host ] . keys . sort
118
- comms_todo . unshift ( fake_comm )
119
-
120
- comms_todo . each do |comm |
121
- begin
122
- sval = nil
123
- snmp = snmp_client ( host , datastore [ 'RPORT' ] . to_i , version , udp_sock , comm )
124
- resp = snmp . get ( "sysName.0" )
125
- resp . each_varbind { |var | sval = var . value }
126
- next if not sval
127
-
128
- svar = ::SNMP ::VarBind . new ( "1.3.6.1.2.1.1.5.0" , ::SNMP ::OctetString . new ( sval ) )
129
- resp = snmp . set ( svar )
130
-
131
- if resp . error_status == :noError
132
- comms_rw << comm
133
- print_status ( "Host #{ host } provides READ-WRITE access with community '#{ comm } '" )
134
- if comm == fake_comm
135
- anycomm_rw = true
136
- finished = true
137
- break
138
- end
139
- else
140
- comms_ro << comm
141
- print_status ( "Host #{ host } provides READ-ONLY access with community '#{ comm } '" )
142
- if comm == fake_comm
143
- anycomm_ro = true
144
- finished = true
145
- break
146
- end
147
- end
148
-
149
- # Used to flag whether this version was compatible
150
- finished = true
151
-
152
- rescue ::SNMP ::UnsupportedPduTag , ::SNMP ::InvalidPduTag , ::SNMP ::ParseError ,
153
- ::SNMP ::InvalidErrorStatus , ::SNMP ::InvalidTrapVarbind , ::SNMP ::InvalidGenericTrap ,
154
- ::SNMP ::BER ::OutOfData , ::SNMP ::BER ::InvalidLength , ::SNMP ::BER ::InvalidTag ,
155
- ::SNMP ::BER ::InvalidObjectId , ::SNMP ::MIB ::ModuleNotLoadedError ,
156
- ::SNMP ::UnsupportedValueTag
157
- next
158
-
159
- rescue ::SNMP ::UnsupportedVersion
160
- break
161
- rescue ::SNMP ::RequestTimeout
162
- next
163
- end
164
- end
165
-
166
- break if finished
167
- end
168
-
169
- # Report on the results
170
- comms_ro = [ "anything" ] if anycomm_ro
171
- comms_rw = [ "anything" ] if anycomm_rw
172
-
173
- comms_rw . each do |comm |
174
- report_auth_info (
175
- :host => host ,
176
- :port => datastore [ 'RPORT' ] . to_i ,
177
- :proto => 'udp' ,
178
- :sname => 'snmp' ,
179
- :user => '' ,
180
- :pass => comm ,
181
- :duplicate_ok => true ,
182
- :active => true ,
183
- :source_type => "user_supplied" ,
184
- :type => "password"
185
- )
186
- end
187
-
188
- comms_ro . each do |comm |
189
- report_auth_info (
190
- :host => host ,
191
- :port => datastore [ 'RPORT' ] . to_i ,
192
- :proto => 'udp' ,
193
- :sname => 'snmp' ,
194
- :user => '' ,
195
- :pass => comm ,
196
- :duplicate_ok => true ,
197
- :active => true ,
198
- :source_type => "user_supplied" ,
199
- :type => "password_ro"
200
- )
201
- end
202
- end
203
-
204
- rescue ::Interrupt
205
- raise $!
206
- rescue ::Exception => e
207
- print_error ( "Unknown error: #{ e . class } #{ e } " )
208
56
end
209
57
210
58
end
211
59
212
- #
213
- # Allocate a SNMP client using the existing socket
214
- #
215
- def snmp_client ( host , port , version , socket , community )
216
- version = :SNMPv1 if version == "1"
217
- version = :SNMPv2c if version == "2c"
218
-
219
- snmp = ::SNMP ::Manager . new (
220
- :Host => host ,
221
- :Port => port ,
222
- :Community => community ,
223
- :Version => version ,
224
- :Timeout => 1 ,
225
- :Retries => 2 ,
226
- :Transport => SNMP ::RexUDPTransport ,
227
- :Socket => socket
228
- )
229
- end
230
-
231
- #
232
- # The response parsers
233
- #
234
- def parse_reply ( pkt )
235
-
236
- return if not pkt [ 1 ]
237
-
238
- if ( pkt [ 1 ] =~ /^::ffff:/ )
239
- pkt [ 1 ] = pkt [ 1 ] . sub ( /^::ffff:/ , '' )
240
- end
241
-
242
- asn = OpenSSL ::ASN1 . decode ( pkt [ 0 ] ) rescue nil
243
- return if not asn
244
-
245
- snmp_error = asn . value [ 0 ] . value rescue nil
246
- snmp_comm = asn . value [ 1 ] . value rescue nil
247
- snmp_data = asn . value [ 2 ] . value [ 3 ] . value [ 0 ] rescue nil
248
- snmp_oid = snmp_data . value [ 0 ] . value rescue nil
249
- snmp_info = snmp_data . value [ 1 ] . value rescue nil
250
60
251
- return if not ( snmp_error and snmp_comm and snmp_data and snmp_oid and snmp_info )
252
- snmp_info = snmp_info . to_s . gsub ( /\s +/ , ' ' )
253
61
254
- inf = snmp_info
255
- com = snmp_comm
256
-
257
- if ( com )
258
- @found [ pkt [ 1 ] ] ||={ }
259
- if ( not @found [ pkt [ 1 ] ] [ com ] )
260
- print_good ( "SNMP: #{ pkt [ 1 ] } community string: '#{ com } ' info: '#{ inf } '" )
261
- @found [ pkt [ 1 ] ] [ com ] = inf
262
- end
263
-
264
- report_service (
265
- :host => pkt [ 1 ] ,
266
- :port => pkt [ 2 ] ,
267
- :proto => 'udp' ,
268
- :name => 'snmp' ,
269
- :info => inf ,
270
- :state => "open"
271
- )
272
- end
273
- end
274
-
275
-
276
- def create_probe_snmp1 ( name )
277
- xid = rand ( 0x100000000 )
278
- pdu =
279
- "\x02 \x01 \x00 " +
280
- "\x04 " + [ name . length ] . pack ( 'c' ) + name +
281
- "\xa0 \x1c " +
282
- "\x02 \x04 " + [ xid ] . pack ( 'N' ) +
283
- "\x02 \x01 \x00 " +
284
- "\x02 \x01 \x00 " +
285
- "\x30 \x0e \x30 \x0c \x06 \x08 \x2b \x06 \x01 \x02 \x01 " +
286
- "\x01 \x01 \x00 \x05 \x00 "
287
- head = "\x30 " + [ pdu . length ] . pack ( 'C' )
288
- data = head + pdu
289
- data
290
- end
291
-
292
- def create_probe_snmp2 ( name )
293
- xid = rand ( 0x100000000 )
294
- pdu =
295
- "\x02 \x01 \x01 " +
296
- "\x04 " + [ name . length ] . pack ( 'c' ) + name +
297
- "\xa1 \x19 " +
298
- "\x02 \x04 " + [ xid ] . pack ( 'N' ) +
299
- "\x02 \x01 \x00 " +
300
- "\x02 \x01 \x00 " +
301
- "\x30 \x0b \x30 \x09 \x06 \x05 \x2b \x06 \x01 \x02 \x01 " +
302
- "\x05 \x00 "
303
- head = "\x30 " + [ pdu . length ] . pack ( 'C' )
304
- data = head + pdu
305
- data
306
- end
307
62
308
63
end
0 commit comments