Fixes #1936, Add accounts mixin and accompanying post module

git-svn-id: file:///home/svn/framework3/trunk@11629 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Joshua Drake 2011-01-24 17:23:48 +00:00
parent 3346a30023
commit 0af8915fd5
2 changed files with 178 additions and 0 deletions

View File

@ -0,0 +1,126 @@
module Msf
class Post
module Accounts
##
# resolve_sid(sid, system_name = nil)
#
# Summary:
# Retrieves the name, domain, and type of account for the given sid
#
# Parameters:
# sid - A SID string (e.g. S-1-5-32-544)
# system_name - Where to search. If nil, first local system then trusted DCs
#
# Returns:
# {
# :name => account name (e.g. "SYSTEM")
# :domain => domain where the account name was found. May have values such as
# the work station's name, BUILTIN, NT AUTHORITY, or an empty string
# :type => one of :user, :group, :domain, :alias, :well_known_group,
# :deleted_account, :invalid, :unknown, :computer
# :mapped => There was a mapping found for the SID
# }
#
# OR nil if there was an exceptional windows error (example: ran out of memory)
#
# Caveats:
# If a valid mapping is not found, only { :mapped => false } will be returned
# nil is returned if there is an *exceptional* windows error. That error is printed.
# If an invalid system_name is provided, there will be a windows error and nil returned
##
def resolve_sid(sid, system_name = nil)
adv = client.railgun.advapi32;
# Second param is the size of the buffer where the pointer will be written
# In railgun, if you specify 4 bytes for a PDWORD it will grow to 8, as needed.
conversion = adv.ConvertStringSidToSidA(sid, 4)
# If the call failed, handle errors accordingly.
unless conversion['return']
error = conversion['GetLastError']
case error
when client.railgun.const('ERROR_INVALID_SID')
# An invalid SID was supplied
return { :type => :invalid, :mapped => false }
else
print_error "Unexpected windows error #{error}"
return nil
end
end
# A reference to the SID data structure. Generally needed when working with sids
psid = conversion['pSid']
# http://msdn.microsoft.com/en-us/library/aa379166(v=vs.85).aspx
# TODO: The buffer sizes here need to be reviewed/adjusted/optimized
lookup = adv.LookupAccountSidA(system_name, psid, 100, 100, 100, 100, 1)
# We no longer need the sid so free it.
# NOTE: We do not check to see if this call succeeded. Do we care?
adv.FreeSid(psid)
# If the call failed, handle errors accordingly.
unless lookup['return']
error = lookup['GetLastError']
case error
when client.railgun.const('ERROR_INVALID_PARAMETER')
# Unless the railgun call is broken, this means revesion is wrong
return { :type => :invalid }
when client.railgun.const('ERROR_NONE_MAPPED')
# There were no accounts associated with this SID
return { :mapped => false }
else
print_error "Unexpected windows error #{error}"
return nil
end
end
# peUse is the enum "SID_NAME_USE"
sid_type = lookup_SID_NAME_USE(lookup['peUse'].unpack('C')[0])
return {
:name => lookup['Name'],
:domain => lookup['ReferencedDomainName'],
:type => sid_type,
:mapped => true
}
end
private
##
# Converts a WinAPI's SID_NAME_USE enum to a symbol
# Symbols are (in order) :user, :group, :domain, :alias, :well_known_group,
# :deleted_account, :invalid, :unknown, :computer
##
def lookup_SID_NAME_USE(enum_value)
[
# SidTypeUser = 1
:user,
# SidTypeGroup,
:group,
#SidTypeDomain,
:domain,
#SidTypeAlias,
:alias,
#SidTypeWellKnownGroup,
:well_known_group,
#SidTypeDeletedAccount,
:deleted_account,
#SidTypeInvalid,
:invalid,
#SidTypeUnknown,
:unknown,
#SidTypeComputer,
:computer,
#SidTypeLabel
:integrity_label
][enum_value - 1]
end
end # Accounts
end # Post
end # Msf

View File

@ -0,0 +1,52 @@
require 'msf/core'
require 'msf/core/post/windows/accounts'
class Metasploit3 < Msf::Post
include Msf::Post::Accounts
def initialize(info={})
super( update_info( info,
'Name' => 'Resolve SID',
'Description' => %q{ This module prints information about a given SID from the perspective of this session },
'License' => BSD_LICENSE,
'Author' => [ 'chao-mu'],
'Platform' => [ 'windows' ],
'SessionTypes' => [ 'meterpreter' ]
))
register_options(
[
OptString.new('SID', [ true, 'SID to lookup' ]),
OptString.new('SYSTEM_NAME', [ false, 'Where to search. If undefined, first local then trusted DCs' ]),
], self.class)
end
def run
sid = datastore['SID']
target_system = datastore['SYSTEM_NAME']
info = resolve_sid(sid, target_system ? target_system : nil)
if info.nil?
print_error 'Unable to resolve SID. Giving up.'
return
end
sid_type = info[:type]
if sid_type.eql? :invalid
print_error 'Invalid SID provided'
return
end
unless info[:mapped]
print_error 'No account found for the given SID'
return
end
print_status "SID Type: #{sid_type.to_s}"
print_status "Name: #{info[:name]}"
print_status "Domain: #{info[:domain]}"
end
end