Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/lib/rex/proto/ms_dtyp.rb
Views: 11655
# -*- coding: binary -*-12require 'bindata'3require 'ruby_smb'4require 'rex/proto/secauthz/well_known_sids'56module Rex::Proto::MsDtyp7# [2.4.3 ACCESS_MASK](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/7a53f60e-e730-4dfe-bbe9-b21b62eb790b)8class MsDtypAccessMask < BinData::Record9endian :little10hide :reserved0, :reserved11112# the protocol field id reserved for protocol-specific access rights13uint16 :protocol1415bit3 :reserved016bit1 :sy17bit1 :wo18bit1 :wd19bit1 :rc20bit1 :de2122bit1 :gr23bit1 :gw24bit1 :gx25bit1 :ga26bit2 :reserved127bit1 :ma28bit1 :as29def bit_names30names = []31names << :GENERIC_READ if self.gr != 032names << :GENERIC_WRITE if self.gw != 033names << :GENERIC_EXECUTE if self.gx != 034names << :GENERIC_ALL if self.ga != 035names << :MAXIMUM_ALLOWED if self.ma != 036names << :ACCESS_SYSTEM_SECURITY if self.as != 037names << :SYNCHRONIZE if self.sy != 038names << :WRITE_OWNER if self.wo != 039names << :WRITE_DACL if self.wd != 040names << :READ_CONTROL if self.rc != 041names << :DELETE if self.de != 042names43end4445ALL = MsDtypAccessMask.new({ gr: 1, gw: 1, gx: 1, ga: 1, ma: 1, as: 1, sy: 1, wo: 1, wd: 1, rc: 1, de: 1, protocol: 0xffff })46NONE = MsDtypAccessMask.new({ gr: 0, gw: 0, gx: 0, ga: 0, ma: 0, as: 0, sy: 0, wo: 0, wd: 0, rc: 0, de: 0, protocol: 0 })47end4849# [2.4.2.2 SID--Packet Representation](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/f992ad60-0fe4-4b87-9fed-beb478836861)50class MsDtypSid < BinData::Primitive51endian :little5253uint8 :revision, initial_value: 154uint8 :sub_authority_count, initial_value: -> { self.sub_authority.length }55array :identifier_authority, type: :uint8, initial_length: 656array :sub_authority, type: :uint32, initial_length: :sub_authority_count5758def set(val)59# allow assignment from the human-readable string representation60raise ArgumentError.new("Invalid SID: #{val}") unless val.is_a?(String) && val =~ /^S-1-(\d+)(-\d+)*$/6162_, _, ia, sa = val.split('-', 4)63self.identifier_authority = [ia.to_i].pack('Q>')[2..].bytes64self.sub_authority = sa.nil? ? [] : sa.split('-').map(&:to_i)65end6667def get68str = 'S-1'69str << "-#{("\x00\x00" + identifier_authority.to_binary_s).unpack1('Q>')}"70str << '-' + sub_authority.map(&:to_s).join('-') unless sub_authority.empty?71str72end7374def rid75sub_authority.last76end77end7879# [Universal Unique Identifier](http://pubs.opengroup.org/onlinepubs/9629399/apdxa.htm)80# The online documentation at [2.3.4.2](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/001eec5a-7f8b-4293-9e21-ca349392db40)81# weirdly doesn't mention this needs to be 4 byte aligned for us to read it correctly,82# which the RubySMB::Dcerpc::Uuid definition takes care of.83class MsDtypGuid < RubySMB::Dcerpc::Uuid84def self.random_generate85# Taken from the "D" format as specified in86# https://learn.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=net-7.087"{#{Rex::Text.rand_text_hex(8)}-#{Rex::Text.rand_text_hex(4)}-#{Rex::Text.rand_text_hex(4)}-#{Rex::Text.rand_text_hex(4)}-#{Rex::Text.rand_text_hex(12)}}".downcase88end89end9091# Definitions taken from [2.4.4.1 ACE_HEADER](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/628ebb1d-c509-4ea0-a10f-77ef97ca4586)92class MsDtypAceType93ACCESS_ALLOWED_ACE_TYPE = 0x094ACCESS_DENIED_ACE_TYPE = 0x195SYSTEM_AUDIT_ACE_TYPE = 0x296SYSTEM_ALARM_ACE_TYPE = 0x3 # Reserved for future use according to documentation.97ACCESS_ALLOWED_COMPOUND_ACE_TYPE = 0x4 # Reserved for future use according to documentation.98ACCESS_ALLOWED_OBJECT_ACE_TYPE = 0x599ACCESS_DENIED_OBJECT_ACE_TYPE = 0x6100SYSTEM_AUDIT_OBJECT_ACE_TYPE = 0x7101SYSTEM_ALARM_OBJECT_ACE_TYPE = 0x8 # Reserved for future use according to documentation.102ACCESS_ALLOWED_CALLBACK_ACE_TYPE = 0x9103ACCESS_DENIED_CALLBACK_ACE_TYPE = 0xA104ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE = 0xB105ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE = 0xC106SYSTEM_AUDIT_CALLBACK_ACE_TYPE = 0xD107SYSTEM_ALARM_CALLBACK_ACE_TYPE = 0xE # Reserved for future use according to documentation.108SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE = 0xF109SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE = 0x10 # Reserved for future use according to documentation.110SYSTEM_MANDATORY_LABEL_ACE_TYPE = 0x11111SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE = 0x12112SYSTEM_SCOPED_POLICY_ID_ACE_TYPE = 0x13113114def self.name(value)115constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }116end117end118119# [2.4.4.1 ACE_HEADER](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/628ebb1d-c509-4ea0-a10f-77ef97ca4586)120class MsDtypAceHeader < BinData::Record121endian :little122123uint8 :ace_type124struct :ace_flags do125bit1 :failed_access_ace_flag126bit1 :successful_access_ace_flag127bit1 :critical_ace_flag # used only with access allowed ACE types, see: https://www.codemachine.com/downloads/win10.1903/ntifs.h128bit1 :inherited_ace129bit1 :inherit_only_ace130bit1 :no_propagate_inherit_ace131bit1 :container_inherit_ace132bit1 :object_inherit_ace133end134uint16 :ace_size, initial_value: -> { parent&.num_bytes || 0 }135end136137class MsDtypAceNonObjectBody < BinData::Record138endian :little139140ms_dtyp_access_mask :access_mask141ms_dtyp_sid :sid, byte_align: 4142end143144class MsDtypAceObjectBody < BinData::Record145endian :little146147ms_dtyp_access_mask :access_mask148struct :flags do149bit1 :reserved5150bit1 :reserved4151bit1 :reserved3152bit1 :reserved2153bit1 :reserved1154bit1 :reserved155bit1 :ace_inherited_object_type_present156bit1 :ace_object_type_present157end158ms_dtyp_guid :object_type, onlyif: -> { flags.ace_object_type_present != 0x0 }159ms_dtyp_guid :inherited_object_type, onlyif: -> { flags.ace_inherited_object_type_present != 0x0 }160ms_dtyp_sid :sid, byte_align: 4161end162163# [2.4.4.2 ACCESS_ALLOWED_ACE](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/72e7c7ea-bc02-4c74-a619-818a16bf6adb)164class MsDtypAccessAllowedAceBody < MsDtypAceNonObjectBody165end166167# [2.4.4.4 ACCESS_DENIED_ACE](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/b1e1321d-5816-4513-be67-b65d8ae52fe8)168class MsDtypAccessDeniedAceBody < MsDtypAceNonObjectBody169end170171# [2.4.4.10 SYSTEM_AUDIT_ACE](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/9431fd0f-5b9a-47f0-b3f0-3015e2d0d4f9)172class MsDtypSystemAuditAceBody < MsDtypAceNonObjectBody173end174175# [2.4.4.3 ACCESS_ALLOWED_OBJECT_ACE](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c79a383c-2b3f-4655-abe7-dcbb7ce0cfbe)176class MsDtypAccessAllowedObjectAceBody < MsDtypAceObjectBody177end178179# [2.4.4.5 ACCESS_DENIED_OBJECT_ACE](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/8720fcf3-865c-4557-97b1-0b3489a6c270)180class MsDtypAccessDeniedObjectAceBody < MsDtypAceObjectBody181end182183# [2.4.4.11 SYSTEM_AUDIT_OBJECT_ACE](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c8da72ae-6b54-4a05-85f4-e2594936d3d5)184class MsDtypSystemAuditObjectAceBody < MsDtypAceObjectBody185endian :little186187string :application_data, read_length: -> { calc_app_data_length }188189def calc_app_data_length190ace_header = parent&.header191return 0 if ace_header.nil?192ace_size = ace_header&.ace_size193return 0 if ace_size.nil? or (ace_size == 0)194195ace_header_length = ace_header.to_binary_s.length196body = parent&.body197if body.nil?198return 0 # Read no data as there is no body, so either we have done some data misalignment or we shouldn't be reading data.199else200ace_body_length = body.to_binary_s.length201return ace_size - (ace_header_length + ace_body_length)202end203end204end205206class MsDtypAce < BinData::Record207endian :little208209ms_dtyp_ace_header :header210choice :body, selection: -> { header.ace_type } do211ms_dtyp_access_allowed_ace_body Rex::Proto::MsDtyp::MsDtypAceType::ACCESS_ALLOWED_ACE_TYPE212ms_dtyp_access_denied_ace_body Rex::Proto::MsDtyp::MsDtypAceType::ACCESS_DENIED_ACE_TYPE213ms_dtyp_system_audit_ace_body Rex::Proto::MsDtyp::MsDtypAceType::SYSTEM_AUDIT_ACE_TYPE214# Type 3 is reserved for future use215# Type 4 is reserved for future use216ms_dtyp_access_allowed_object_ace_body Rex::Proto::MsDtyp::MsDtypAceType::ACCESS_ALLOWED_OBJECT_ACE_TYPE217ms_dtyp_access_denied_object_ace_body Rex::Proto::MsDtyp::MsDtypAceType::ACCESS_DENIED_OBJECT_ACE_TYPE218ms_dtyp_system_audit_object_ace_body Rex::Proto::MsDtyp::MsDtypAceType::SYSTEM_AUDIT_OBJECT_ACE_TYPE219# Type 8 is reserved for future use220# Type 14 aka 0xE is reserved for future use221# Type 16 aka 0x10 is reserved for future use222string :default, read_length: -> { header.ace_size - body.rel_offset }223end224end225226# [2.4.5 ACL](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/20233ed8-a6c6-4097-aafa-dd545ed24428)227class MsDtypAcl < BinData::Record228ACL_REVISION = 2229ACL_REVISION_DS = 4230231endian :little232233uint8 :acl_revision, initial_value: ACL_REVISION234uint8 :sbz1235uint16 :acl_size, initial_value: -> { num_bytes }236uint16 :acl_count, initial_value: -> { aces.length }237uint16 :sbz2238array :aces, type: :ms_dtyp_ace, initial_length: :acl_count239end240241# [2.4.6 SECURITY_DESCRIPTOR](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/7d4dac05-9cef-4563-a058-f108abecce1d)242class MsDtypSecurityDescriptor < BinData::Record243endian :little244245uint8 :revision, initial_value: 1246uint8 :sbz1247struct :control do248bit1 :ss249bit1 :dt250bit1 :sd251bit1 :sp, initial_value: -> { sacl? ? 1 : 0 }252bit1 :dd253bit1 :dp, initial_value: -> { dacl? ? 1 : 0 }254bit1 :gd255bit1 :od256257bit1 :sr, initial_value: 1258bit1 :rm259bit1 :ps260bit1 :pd261bit1 :si262bit1 :di263bit1 :sc264bit1 :dc265end266uint32 :offset_owner, value: -> { offset_for(:owner_sid) }267uint32 :offset_group, value: -> { offset_for(:group_sid) }268uint32 :offset_sacl, value: -> { offset_for(:sacl) }269uint32 :offset_dacl, value: -> { offset_for(:dacl) }270rest :buffer, value: -> { build_buffer }271hide :buffer272273def self.from_sddl_text(sddl_text, domain_sid:)274sacl_set = dacl_set = false275sd = self.new276sddl_text = sddl_text.dup.gsub(/\s/, '') # start by removing all whitespace277sddl_text.scan(/([OGDS]:(?:.(?!:))*)/).each do |part,|278component, _, value = part.partition(':')279case component280when 'O'281if sd.owner_sid.present?282raise RuntimeError.new('SDDL parse error on extra owner SID')283end284285sd.owner_sid = self.parse_sddl_sid(value, domain_sid: domain_sid)286when 'G'287if sd.group_sid.present?288raise RuntimeError.new('SDDL parse error on extra group SID')289end290291sd.group_sid = self.parse_sddl_sid(value, domain_sid: domain_sid)292when 'D'293raise RuntimeError.new('SDDL parse error on extra DACL') if dacl_set294295value.upcase!296dacl_set = true297access_control = true298flags = value.split('(', 2).first || ''299flags.split(/(P|AR|AI|NO_ACCESS_CONTROL)/).each do |flag|300case flag301when 'AI'302sd.control.di = true303when 'AR'304sd.control.dc = true305when 'P'306sd.control.pd = true307when 'NO_ACCESS_CONTROL'308access_control = false309when ''310else311raise RuntimeError.new('SDDL parse error on unknown DACL flag: ' + flag)312end313end314315next unless access_control316317sd.dacl = MsDtypAcl.new318sd.dacl.aces = self.parse_sddl_aces(value.delete_prefix(flags), domain_sid: domain_sid)319when 'S'320raise RuntimeError.new('SDDL parse error on extra SACL') if sacl_set321322value.upcase!323sacl_set = true324access_control = true325flags = value.split('(', 2).first || ''326flags.split(/(P|AR|AI|NO_ACCESS_CONTROL)/).each do |flag|327case flag328when 'AI'329sd.control.si = true330when 'AR'331sd.control.sc = true332when 'P'333sd.control.ps = true334when 'NO_ACCESS_CONTROL'335access_control = false336when ''337else338raise RuntimeError.new('SDDL parse error on unknown SACL flag: ' + flag)339end340end341342next unless access_control343344sd.sacl = MsDtypAcl.new345sd.sacl.aces = self.parse_sddl_aces(value.delete_prefix(flags), domain_sid: domain_sid)346else347raise RuntimeError.new('SDDL parse error on unknown directive: ' + part[0])348end349end350351sd352end353354class << self355private356357def parse_sddl_ace(ace, domain_sid:)358parts = ace.upcase.split(';', -1)359raise RuntimeError.new('SDDL parse error on too few ACE fields') if parts.length < 6360raise RuntimeError.new('SDDL parse error on too many ACE fields') if parts.length > 7361362ace_type, ace_flags, rights, object_guid, inherit_object_guid, account_sid = parts[0...6]363resource_attribute = parts[6]364365ace = MsDtypAce.new366case ace_type367when 'A'368ace.header.ace_type = MsDtypAceType::ACCESS_ALLOWED_ACE_TYPE369when 'D'370ace.header.ace_type = MsDtypAceType::ACCESS_DENIED_ACE_TYPE371when 'OA'372ace.header.ace_type = MsDtypAceType::ACCESS_ALLOWED_OBJECT_ACE_TYPE373when 'OD'374ace.header.ace_type = MsDtypAceType::ACCESS_DENIED_OBJECT_ACE_TYPE375when 'AU'376ace.header.ace_type = MsDtypAceType::SYSTEM_AUDIT_ACE_TYPE377when 'OU'378ace.header.ace_type = MsDtypAceType::SYSTEM_AUDIT_OBJECT_ACE_TYPE379when 'AL', 'OL', 'ML', 'XA', 'SD', 'RA', 'SP', 'XU', 'ZA', 'TL', 'FL'380raise RuntimeError.new('SDDL parse error on unsupported ACE type: ' + ace_type)381else382raise RuntimeError.new('SDDL parse error on unknown ACE type: ' + ace_type)383end384385ace_flags.split(/(CI|OI|NP|IO|ID|SA|FA|TP|CR)/).each do |flag|386case flag387when 'CI'388ace.header.ace_flags.container_inherit_ace = true389when 'OI'390ace.header.ace_flags.object_inherit_ace = true391when 'NP'392ace.header.ace_flags.no_propagate_inherit_ace = true393when 'IO'394ace.header.ace_flags.inherit_only_ace = true395when 'ID'396ace.header.ace_flags.inherited_ace = true397when 'SA'398ace.header.ace_flags.successful_access_ace_flag = true399when 'FA'400ace.header.ace_flags.failed_access_ace_flag = true401when 'TP'402raise RuntimeError.new('SDDL parse error on unsupported ACE flag: TP')403when 'CR'404ace.header.ace_flags.critical_ace_flag = true405when ''406else407raise RuntimeError.new('SDDL parse error on unknown ACE flag: ' + flag)408end409end410411rights.split(/(G[ARWX]|RC|SD|WD|WO|RP|WP|CC|DC|LC|SW|LO|DT|CR|F[ARWX]|K[ARWX]|N[RWX])/).each do |right|412case right413# generic access rights414when 'GA', 'GR', 'GW', 'GX'415ace.body.access_mask.send("#{right.downcase}=", true)416# standard access rights417when 'RC'418ace.body.access_mask.rc = true419when 'SD'420ace.body.access_mask.de = true421when 'WD', 'WO'422ace.body.access_mask.send("#{right.downcase}=", true)423# directory service object access rights424when 'RP'425ace.body.access_mask.protocol |= 16426when 'WP'427ace.body.access_mask.protocol |= 32428when 'CC'429ace.body.access_mask.protocol |= 1430when 'DC'431ace.body.access_mask.protocol |= 2432when 'LC'433ace.body.access_mask.protocol |= 4434when 'SW'435ace.body.access_mask.protocol |= 8436when 'LO'437ace.body.access_mask.protocol |= 128438when 'DT'439ace.body.access_mask.protocol |= 64440when 'CR'441ace.body.access_mask.protocol |= 256442# file access rights443when 'FA'444ace.body.access_mask.protocol |= 0x1ff445ace.body.access_mask.de = true446ace.body.access_mask.rc = true447ace.body.access_mask.wd = true448ace.body.access_mask.wo = true449ace.body.access_mask.sy = true450when 'FR'451ace.body.access_mask.protocol |= 0x89452when 'FW'453ace.body.access_mask.protocol |= 0x116454when 'FX'455ace.body.access_mask.protocol |= 0xa0456# registry key access rights457when 'KA'458ace.body.access_mask.protocol |= 0x3f459ace.body.access_mask.de = true460ace.body.access_mask.rc = true461ace.body.access_mask.wd = true462ace.body.access_mask.wo = true463when 'KR'464ace.body.access_mask.protocol |= 0x19465when 'KW'466ace.body.access_mask.protocol |= 0x06467when 'KX'468ace.body.access_mask.protocol |= 0x19469when 'NR', 'NW', 'NX'470raise RuntimeError.new('SDDL parse error on unsupported ACE access right: ' + right)471when ''472else473raise RuntimeError.new('SDDL parse error on unknown ACE access right: ' + right)474end475end476477unless object_guid.blank?478begin479guid = MsDtypGuid.new(object_guid)480rescue StandardError481raise RuntimeError.new('SDDL parse error on invalid object GUID: ' + object_guid)482end483484unless ace.body.respond_to?('object_type=')485raise RuntimeError.new('SDDL error on setting object type for incompatible ACE type')486end487ace.body.flags.ace_object_type_present = true488ace.body.object_type = guid489end490491unless inherit_object_guid.blank?492begin493guid = MsDtypGuid.new(inherit_object_guid)494rescue StandardError495raise RuntimeError.new('SDDL parse error on invalid object GUID: ' + inherit_object_guid)496end497498unless ace.body.respond_to?('inherited_object_type=')499raise RuntimeError.new('SDDL error on setting object type for incompatible ACE type')500end501ace.body.flags.ace_inherited_object_type_present = true502ace.body.inherited_object_type = guid503end504505unless account_sid.blank?506ace.body.sid = self.parse_sddl_sid(account_sid, domain_sid: domain_sid)507end508509unless resource_attribute.blank?510raise RuntimeError.new('SDDL parse error on unsupported resource attribute: ' + resource_attribute)511end512513ace514end515516def parse_sddl_aces(aces, domain_sid:)517ace_regex = /\([^\)]*\)/518519invalid_aces = aces.split(ace_regex).reject(&:empty?)520unless invalid_aces.empty?521raise RuntimeError.new('SDDL parse error on malformed ACE: ' + invalid_aces.first)522end523524aces.scan(ace_regex).map do |ace_text|525self.parse_sddl_ace(ace_text[1...-1], domain_sid: domain_sid)526end527end528529def parse_sddl_sid(sid, domain_sid:)530# see: https://learn.microsoft.com/en-us/windows/win32/secauthz/sid-strings531sid = sid.dup.upcase532533# these can be validated using powershell where ?? is the code534# (ConvertFrom-SddlString -Sddl "O:??").RawDescriptor.Owner535case sid536when 'AA' # SDDL_ACCESS_CONTROL_ASSISTANCE_OPS537sid = Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_ACCESS_CONTROL_ASSISTANCE_OPS538when 'AC' # SDDL_ALL_APP_PACKAGES539sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_ALL_APP_PACKAGES540when 'AN' # SDDL_ANONYMOUS541sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_ANONYMOUS_LOGON_SID542when 'AO' # SDDL_ACCOUNT_OPERATORS543sid = Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_ACCOUNT_OPS544when 'AP' # SDDL_PROTECTED_USERS545sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_PROTECTED_USERS}"546when 'AU' # SDDL_AUTHENTICATED_USERS547sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_AUTHENTICATED_USER_SID548when 'BA' # SDDL_BUILTIN_ADMINISTRATORS549sid = Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_ADMINS550when 'BG' # SDDL_BUILTIN_GUESTS551sid = Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_GUESTS552when 'BO' # SDDL_BACKUP_OPERATORS553sid = Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_BACKUP_OPS554when 'BU' # SDDL_BUILTIN_USERS555sid = Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_SID_USERS556when 'CA' # SDDL_CERT_SERV_ADMINISTRATORS557sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_CERT_ADMINS}"558when 'CD' # SDDL_CERTSVC_DCOM_ACCESS559sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP}"560when 'CG' # SDDL_CREATOR_GROUP561sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_CREATOR_GROUP_SID562when 'CN' # SDDL_CLONEABLE_CONTROLLERS563sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_CLONEABLE_CONTROLLERS}"564when 'CO' # SDDL_CREATOR_OWNER565sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_CREATOR_OWNER_SID566when 'CY' # SDDL_CRYPTO_OPERATORS567sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_CRYPTO_OPERATORS}"568when 'DA' # SDDL_DOMAIN_ADMINISTRATORS569sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_ADMINS}"570when 'DC' # SDDL_DOMAIN_COMPUTERS571sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_COMPUTERS}"572when 'DD' # SDDL_DOMAIN_DOMAIN_CONTROLLERS573sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_CONTROLLERS}"574when 'DG' # SDDL_DOMAIN_GUESTS575sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_GUESTS}"576when 'DU' # SDDL_DOMAIN_USERS577sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_USERS}"578when 'EA' # SDDL_ENTERPRISE_ADMINS579sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_ENTERPRISE_ADMINS}"580when 'ED' # SDDL_ENTERPRISE_DOMAIN_CONTROLLERS581sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_ENTERPRISE_CONTROLLERS_SID}"582when 'EK' # SDDL_ENTERPRISE_KEY_ADMINS583sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_ENTERPRISE_KEY_ADMINS}"584when 'ER' # SDDL_EVENT_LOG_READERS585sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP}"586when 'ES' # SDDL_RDS_ENDPOINT_SERVERS587sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_RDS_ENDPOINT_SERVERS}"588when 'HA' # SDDL_HYPER_V_ADMINS589sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_HYPER_V_ADMINS}"590when 'HI' # SDDL_ML_HIGH591sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_MANDATORY_HIGH_RID}"592when 'IS' # SDDL_IIS_USERS593sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_IUSERS}"594when 'IU' # SDDL_INTERACTIVE595sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_INTERACTIVE_SID596when 'KA' # SDDL_KEY_ADMINS597sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_KEY_ADMINS}"598when 'LA' # SDDL_LOCAL_ADMIN599sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_USER_RID_ADMIN}"600when 'LG' # SDDL_LOCAL_GUEST601sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_USER_RID_GUEST}"602when 'LS' # SDDL_LOCAL_SERVICE603sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_LOCAL_SERVICE_SID604when 'LU' # SDDL_PERFLOG_USERS605sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_LOGGING_USERS}"606when 'LW' # SDDL_ML_LOW607sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_MANDATORY_LOW_RID}"608when 'ME' # SDDL_ML_MEDIUM609sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_MANDATORY_MEDIUM_RID}"610when 'MP' # SDDL_ML_MEDIUM_PLUS611sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_MANDATORY_MEDIUM_PLUS_RID}"612when 'MU' # SDDL_PERFMON_USERS613sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_MONITORING_USERS}"614when 'NO' # SDDL_NETWORK_CONFIGURATION_OPS615sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS}"616when 'NS' # SDDL_NETWORK_SERVICE617sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_NETWORK_SERVICE_SID618when 'NU' # SDDL_NETWORK619sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_NETWORK_SID620when 'OW' # SDDL_OWNER_RIGHTS621sid = "#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_CREATOR_SID_AUTHORITY}-4"622when 'PA' # SDDL_GROUP_POLICY_ADMINS623sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_POLICY_ADMINS}"624when 'PO' # SDDL_PRINTER_OPERATORS625sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_PRINT_OPS}"626when 'PS' # SDDL_PERSONAL_SELF627sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_PRINCIPAL_SELF_SID628when 'PU' # SDDL_POWER_USERS629sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_POWER_USERS}"630when 'RA' # SDDL_RDS_REMOTE_ACCESS_SERVERS631sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_RDS_REMOTE_ACCESS_SERVERS}"632when 'RC' # SDDL_RESTRICTED_CODE633sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_RESTRICTED_CODE_SID634when 'RD' # SDDL_REMOTE_DESKTOP635sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS}"636when 'RE' # SDDL_REPLICATOR637sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_REPLICATOR}"638when 'RM' # SDDL_RMS__SERVICE_OPERATORS639sid = "#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_BUILTIN_DOMAIN_SID}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_REMOTE_MANAGEMENT_USERS}"640when 'RO' # SDDL_ENTERPRISE_RO_DCs641sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_ENTERPRISE_READONLY_DOMAIN_CONTROLLERS}"642when 'RS' # SDDL_RAS_SERVERS643sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_RAS_SERVERS}"644when 'RU' # SDDL_ALIAS_PREW2KCOMPACC645sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_PREW2KCOMPACCESS}"646when 'SA' # SDDL_SCHEMA_ADMINISTRATORS647sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_GROUP_RID_SCHEMA_ADMINS}"648when 'SI' # SDDL_ML_SYSTEM649sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_MANDATORY_SYSTEM_SID650when 'SO' # SDDL_SERVER_OPERATORS651sid = "#{domain_sid}-#{Rex::Proto::Secauthz::WellKnownSids::DOMAIN_ALIAS_RID_SYSTEM_OPS}"652when 'SS' # SDDL_SERVICE_ASSERTED653sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_AUTHENTICATION_SERVICE_ASSERTED_SID654when 'SU' # SDDL_SERVICE655sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_SERVICE_SID656when 'SY' # SDDL_LOCAL_SYSTEM657sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_LOCAL_SYSTEM_SID658when 'UD' # SDDL_USER_MODE_DRIVERS659sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_USERMODEDRIVERHOST_ID_BASE_SID660when 'WD' # SDDL_EVERYONE661sid = "#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_WORLD_SID_AUTHORITY}-#{Rex::Proto::Secauthz::WellKnownSids::SECURITY_WORLD_RID}"662when 'WR' # SDDL_WRITE_RESTRICTED_CODE663sid = Rex::Proto::Secauthz::WellKnownSids::SECURITY_WRITE_RESTRICTED_CODE_SID664when /^S(-\d+)+/665else666raise RuntimeError, 'SDDL parse error on invalid SID string: ' + sid667end668669670MsDtypSid.new(sid)671end672end673674def initialize_shared_instance675# define accessor methods for the custom fields to expose the same API as BinData676define_field_accessors_for2(:owner_sid)677define_field_accessors_for2(:group_sid)678define_field_accessors_for2(:sacl)679define_field_accessors_for2(:dacl)680super681end682683def initialize_instance684value = super685@owner_sid = get_parameter(:owner_sid)686@group_sid = get_parameter(:group_sid)687@sacl = get_parameter(:sacl)688@dacl = get_parameter(:dacl)689value690end691692def do_read(val)693value = super694if offset_owner != 0695@owner_sid = MsDtypSid.read(buffer[offset_owner - buffer.rel_offset..])696end697if offset_group != 0698@group_sid = MsDtypSid.read(buffer[offset_group - buffer.rel_offset..])699end700if offset_sacl != 0701@sacl = MsDtypAcl.read(buffer[offset_sacl - buffer.rel_offset..])702end703if offset_dacl != 0704@dacl = MsDtypAcl.read(buffer[offset_dacl - buffer.rel_offset..])705end706value707end708709def snapshot710snap = super711snap[:owner_sid] ||= owner_sid&.snapshot712snap[:group_sid] ||= group_sid&.snapshot713snap[:sacl] ||= sacl&.snapshot714snap[:dacl] ||= dacl&.snapshot715snap716end717718attr_accessor :owner_sid, :group_sid, :sacl, :dacl719720private721722def build_buffer723buf = ''724buf << owner_sid.to_binary_s if owner_sid725buf << group_sid.to_binary_s if group_sid726buf << sacl.to_binary_s if sacl727buf << dacl.to_binary_s if dacl728buf729end730731def define_field_accessors_for2(name)732define_singleton_method("#{name}?") do733!send(name).nil?734end735end736737def offset_for(field)738return 0 unless instance_variable_get("@#{field}")739740offset = buffer.rel_offset741%i[ owner_sid group_sid sacl dacl ].each do |cursor|742break if cursor == field743744cursor = instance_variable_get("@#{cursor}")745offset += cursor.num_bytes if cursor746end747748offset749end750end751752# [2.3.7 LUID](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/48cbee2a-0790-45f2-8269-931d7083b2c3)753class MsDtypLuid < BinData::Record754endian :little755756uint32 :low_part757int32 :high_part758759def to_s760"0x#{high_part.to_i.to_s(16)}#{low_part.to_i.to_s(16).rjust(8, '0')}"761end762end763764# [2.3.5 LARGE_INTEGER](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/e904b1ba-f774-4203-ba1b-66485165ab1a)765class MsDtypLargeInteger < BinData::Record766endian :big_and_little767768uint32 :low_part769int32 :high_part770771def to_datetime772RubySMB::Field::FileTime.new(to_i).to_datetime773end774775def to_i776(high_part.to_i << 32) | low_part.to_i777end778end779end780781782