metasploit-framework/lib/rex/proto/kerberos/pac/logon_info.rb

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