438 lines
12 KiB
Ruby
438 lines
12 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
module Rex
|
|
module Proto
|
|
module Kerberos
|
|
module Pac
|
|
# TODO: Allow more user provided attributes
|
|
class LogonInfo < Element
|
|
|
|
# @!attribute logon_time
|
|
# @return [Time] The time the client last logged on
|
|
attr_accessor :logon_time
|
|
# @!attribute effective_name
|
|
# @return [String] The client's Windows 2000 user name
|
|
attr_accessor :effective_name
|
|
# @!attribute user_id
|
|
# @return [Fixnum] The relative ID for the client
|
|
attr_accessor :user_id
|
|
# @!attribute primary_group_id
|
|
# @return [Fixnum] The relative ID for the client's primary group
|
|
attr_accessor :primary_group_id
|
|
# @!attribute group_ids
|
|
# @return [Array<Fixnum>] Array of relative Ids of the groups which the client is a member
|
|
attr_accessor :group_ids
|
|
# @!attribute logon_domain_name
|
|
# @return [String] The netbios name of the client's domain
|
|
attr_accessor :logon_domain_name
|
|
# @!attribute logon_domain_sid
|
|
# @return [String] The SID of the client's domain
|
|
attr_accessor :logon_domain_id
|
|
|
|
# Encodes the Rex::Proto::Kerberos::Pac::LogonInfo
|
|
#
|
|
# @return [String]
|
|
def encode
|
|
elements = []
|
|
elements[0] = ''
|
|
elements[0] << encode_element_id
|
|
elements[0] << encode_logon_time
|
|
elements[0] << encode_logoff_time
|
|
elements[0] << encode_kickoff_time
|
|
elements[0] << encode_password_last_set
|
|
elements[0] << encode_password_can_change
|
|
elements[0] << encode_password_must_change
|
|
elements[0] << encode_effective_name
|
|
elements << encode_effective_name_info
|
|
elements[0] << encode_full_name
|
|
elements << encode_full_name_info
|
|
elements[0] << encode_logon_script
|
|
elements << encode_logon_script_info
|
|
elements[0] << encode_profile_path
|
|
elements << encode_profile_path_info
|
|
elements[0] << encode_home_directory
|
|
elements << encode_home_directory_info
|
|
elements[0] << encode_home_directory_drive
|
|
elements << encode_home_directory_drive_info
|
|
elements[0] << encode_logon_count
|
|
elements[0] << encode_bad_password_count
|
|
elements[0] << encode_user_id
|
|
elements[0] << encode_primary_group_id
|
|
elements[0] << encode_group_count
|
|
elements[0] << encode_group_ids
|
|
elements << encode_group_ids_info
|
|
elements[0] << encode_user_flags
|
|
elements[0] << encode_user_session_key
|
|
elements[0] << encode_logon_server
|
|
elements << encode_logon_server_info
|
|
elements[0] << encode_logon_domain_name
|
|
elements << encode_logon_domain_name_info
|
|
elements[0] << encode_logon_domain_id
|
|
elements << encode_logon_domain_id_info
|
|
elements[0] << encode_reserved_one
|
|
elements[0] << encode_user_account_control
|
|
elements[0] << encode_reserved_three
|
|
elements[0] << encode_sid_count
|
|
elements[0] << encode_extra_sids
|
|
elements[0] << encode_resource_group_domain_sid
|
|
elements[0] << encode_resource_group_count
|
|
elements[0] << encode_resource_group_ids
|
|
|
|
decoded = ''
|
|
elements.each do |elem|
|
|
decoded << elem
|
|
decoded << "\x00" * ((elem.length + 3) / 4 * 4 - elem.length)
|
|
end
|
|
|
|
header = "\x01\x10\x08\x00\xcc\xcc\xcc\xcc"
|
|
header << [decoded.length, 0].pack('VV')
|
|
|
|
header + decoded
|
|
end
|
|
|
|
private
|
|
|
|
def encode_element_id
|
|
[0x20000].pack('V')
|
|
end
|
|
|
|
def encode_logon_time
|
|
file_time = (logon_time.to_i + 11644473600) * 10000000
|
|
encoded = ''
|
|
encoded << [file_time].pack('Q<')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_logoff_time
|
|
[0x7fffffffffffffff].pack('Q<')
|
|
end
|
|
|
|
def encode_kickoff_time
|
|
[0x7fffffffffffffff].pack('Q<')
|
|
end
|
|
|
|
def encode_password_last_set
|
|
[0].pack('Q<')
|
|
end
|
|
|
|
def encode_password_can_change
|
|
[0].pack('Q<')
|
|
end
|
|
|
|
def encode_password_must_change
|
|
[0x7fffffffffffffff].pack('Q<')
|
|
end
|
|
|
|
def encode_effective_name
|
|
unicode = Rex::Text.to_unicode(effective_name)
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x20004
|
|
].pack('vvV')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_effective_name_info
|
|
unicode = Rex::Text.to_unicode(effective_name)
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
effective_name.length,
|
|
effective_name.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
end
|
|
|
|
def encode_full_name
|
|
unicode = Rex::Text.to_unicode('')
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x20008
|
|
].pack('vvV')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_full_name_info
|
|
unicode = Rex::Text.to_unicode('')
|
|
encoded = ''
|
|
encoded << [
|
|
''.length,
|
|
''.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_script
|
|
unicode = Rex::Text.to_unicode('')
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x2000c
|
|
].pack('vvV')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_script_info
|
|
unicode = Rex::Text.to_unicode('')
|
|
encoded = ''
|
|
encoded << [
|
|
''.length,
|
|
''.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_profile_path
|
|
unicode = Rex::Text.to_unicode('')
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x20010
|
|
].pack('vvV')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_profile_path_info
|
|
unicode = Rex::Text.to_unicode('')
|
|
encoded = ''
|
|
encoded << [
|
|
''.length,
|
|
''.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_home_directory
|
|
unicode = Rex::Text.to_unicode('')
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x20014
|
|
].pack('vvV')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_home_directory_info
|
|
unicode = Rex::Text.to_unicode('')
|
|
encoded = ''
|
|
encoded << [
|
|
''.length,
|
|
''.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_home_directory_drive
|
|
unicode = Rex::Text.to_unicode('')
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x20018
|
|
].pack('vvV')
|
|
encoded
|
|
end
|
|
|
|
def encode_home_directory_drive_info
|
|
unicode = Rex::Text.to_unicode('')
|
|
encoded = ''
|
|
encoded << [
|
|
''.length,
|
|
''.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_count
|
|
[0].pack('v')
|
|
end
|
|
|
|
def encode_bad_password_count
|
|
[0].pack('v')
|
|
end
|
|
|
|
def encode_user_id
|
|
[user_id].pack('V')
|
|
end
|
|
|
|
def encode_primary_group_id
|
|
[primary_group_id].pack('V')
|
|
end
|
|
|
|
def encode_group_count
|
|
[group_ids.length].pack('V')
|
|
end
|
|
|
|
def encode_group_ids
|
|
encoded = ''
|
|
encoded << [0x2001c].pack('V')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_group_ids_info
|
|
encoded = ''
|
|
encoded << [group_ids.length].pack('V')
|
|
group_ids.each do |group|
|
|
encoded << [
|
|
group,
|
|
SE_GROUP_ALL
|
|
].pack('VV')
|
|
end
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_user_flags
|
|
[0].pack('V')
|
|
end
|
|
|
|
def encode_user_session_key
|
|
[0, 0].pack('Q<Q<')
|
|
end
|
|
|
|
def encode_logon_server
|
|
unicode = Rex::Text.to_unicode('')
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x20020
|
|
].pack('vvV')
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_server_info
|
|
unicode = Rex::Text.to_unicode('')
|
|
encoded = ''
|
|
encoded << [
|
|
''.length,
|
|
''.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_domain_name
|
|
unicode = Rex::Text.to_unicode(logon_domain_name)
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
unicode.length,
|
|
unicode.length,
|
|
0x20024
|
|
].pack('vvV')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_domain_name_info
|
|
unicode = Rex::Text.to_unicode(logon_domain_name)
|
|
encoded = ''
|
|
encoded << [
|
|
logon_domain_name.length,
|
|
logon_domain_name.length
|
|
].pack('Q<V')
|
|
encoded << unicode
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_domain_id
|
|
encoded = ''
|
|
encoded << [0x20028].pack('V')
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_logon_domain_id_info
|
|
components = logon_domain_id.split('-')
|
|
unless components[0] == 'S'
|
|
raise ::RuntimeError, 'PAC-LOGON-INFO encoding failed: incorrect LogonDomainId'
|
|
end
|
|
components.slice!(0) # Delete the 'S' component
|
|
|
|
encoded = ''
|
|
encoded << [
|
|
components.length - 2,
|
|
components[0].to_i,
|
|
components.length - 2
|
|
].pack('VCC')
|
|
|
|
encoded << [
|
|
components[1].to_i >> 16,
|
|
components[1].to_i & 0xffff
|
|
].pack('Nn')
|
|
|
|
components[2, components.length].each do |c|
|
|
encoded << [c.to_i].pack('V')
|
|
end
|
|
|
|
encoded
|
|
end
|
|
|
|
def encode_reserved_one
|
|
[0, 0].pack('VV')
|
|
end
|
|
|
|
def encode_user_account_control
|
|
[USER_NORMAL_ACCOUNT | USER_DONT_EXPIRE_PASSWORD].pack('V')
|
|
end
|
|
|
|
def encode_reserved_three
|
|
[0, 0, 0, 0, 0, 0, 0].pack('V*')
|
|
end
|
|
|
|
def encode_sid_count
|
|
[0].pack('V')
|
|
end
|
|
|
|
def encode_extra_sids
|
|
[0].pack('V')
|
|
end
|
|
|
|
def encode_resource_group_domain_sid
|
|
[0].pack('V')
|
|
end
|
|
|
|
def encode_resource_group_count
|
|
[0].pack('V')
|
|
end
|
|
|
|
def encode_resource_group_ids
|
|
[0].pack('V')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end |