module RubySMB module Dcerpc module Drsr UUID = 'E3514235-4B06-11D1-AB04-00C04FC2DCD2' VER_MAJOR = 4 VER_MINOR = 0 # [5.138 NTSAPI_CLIENT_GUID](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/d4ff2fb2-bf57-455e-9646-426a92737d6e) NTSAPI_CLIENT_GUID = 'e24d201a-4fd6-11d1-a3da-0000f875ae0d' # Operation numbers DRS_BIND = 0x0000 DRS_UNBIND = 0x0001 DRS_GET_NC_CHANGES = 0x0003 DRS_CRACK_NAMES = 0x000C DRS_DOMAIN_CONTROLLER_INFO = 0x0010 # DRS_EXTENSIONS_INT Flags # [5.39 DRS_EXTENSIONS_INT](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/3ee529b1-23db-4996-948a-042f04998e91) DRS_EXT_BASE = 0x00000001 DRS_EXT_ASYNCREPL = 0x00000002 DRS_EXT_REMOVEAPI = 0x00000004 DRS_EXT_MOVEREQ_V2 = 0x00000008 DRS_EXT_GETCHG_DEFLATE = 0x00000010 DRS_EXT_DCINFO_V1 = 0x00000020 DRS_EXT_RESTORE_USN_OPTIMIZATION = 0x00000040 DRS_EXT_ADDENTRY = 0x00000080 DRS_EXT_KCC_EXECUTE = 0x00000100 DRS_EXT_ADDENTRY_V2 = 0x00000200 DRS_EXT_LINKED_VALUE_REPLICATION = 0x00000400 DRS_EXT_DCINFO_V2 = 0x00000800 DRS_EXT_INSTANCE_TYPE_NOT_REQ_ON_MOD = 0x00001000 DRS_EXT_CRYPTO_BIND = 0x00002000 DRS_EXT_GET_REPL_INFO = 0x00004000 DRS_EXT_STRONG_ENCRYPTION = 0x00008000 DRS_EXT_DCINFO_VFFFFFFFF = 0x00010000 DRS_EXT_TRANSITIVE_MEMBERSHIP = 0x00020000 DRS_EXT_ADD_SID_HISTORY = 0x00040000 DRS_EXT_POST_BETA3 = 0x00080000 DRS_EXT_GETCHGREQ_V5 = 0x00100000 DRS_EXT_GETMEMBERSHIPS2 = 0x00200000 DRS_EXT_GETCHGREQ_V6 = 0x00400000 DRS_EXT_NONDOMAIN_NCS = 0x00800000 DRS_EXT_GETCHGREQ_V8 = 0x01000000 DRS_EXT_GETCHGREPLY_V5 = 0x02000000 DRS_EXT_GETCHGREPLY_V6 = 0x04000000 DRS_EXT_GETCHGREPLY_V9 = 0x00000100 DRS_EXT_WHISTLER_BETA3 = 0x08000000 DRS_EXT_W2K3_DEFLATE = 0x10000000 DRS_EXT_GETCHGREQ_V10 = 0x20000000 DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART2 = 0x40000000 DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART3 = 0x80000000 # DRS_EXTENSIONS_INT FlagsExt # [5.39 DRS_EXTENSIONS_INT](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/3ee529b1-23db-4996-948a-042f04998e91) DRS_EXT_ADAM = 0x00000001 DRS_EXT_LH_BETA2 = 0x00000002 DRS_EXT_RECYCLE_BIN = 0x00000004 # DRS_EXT_GETCHGREPLY_V9 = 0x00000100 (already defined) DRS_EXT_RPC_CORRELATIONID_1 = 0x00000400 # [5.41 DRS_OPTIONS](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/ac9c8a11-cd46-4080-acbf-9faa86344030) DRS_ASYNC_OP = 0x00000001 DRS_GETCHG_CHECK = 0x00000002 DRS_UPDATE_NOTIFICATION = 0x00000002 DRS_ADD_REF = 0x00000004 DRS_SYNC_ALL = 0x00000008 DRS_DEL_REF = 0x00000008 DRS_WRIT_REP = 0x00000010 DRS_INIT_SYNC = 0x00000020 DRS_PER_SYNC = 0x00000040 DRS_MAIL_REP = 0x00000080 DRS_ASYNC_REP = 0x00000100 DRS_IGNORE_ERROR = 0x00000100 DRS_TWOWAY_SYNC = 0x00000200 DRS_CRITICAL_ONLY = 0x00000400 DRS_GET_ANC = 0x00000800 DRS_GET_NC_SIZE = 0x00001000 DRS_LOCAL_ONLY = 0x00001000 DRS_NONGC_RO_REP = 0x00002000 DRS_SYNC_BYNAME = 0x00004000 DRS_REF_OK = 0x00004000 DRS_FULL_SYNC_NOW = 0x00008000 DRS_NO_SOURCE = 0x00008000 DRS_FULL_SYNC_IN_PROGRESS = 0x00010000 DRS_FULL_SYNC_PACKET = 0x00020000 DRS_SYNC_REQUEUE = 0x00040000 DRS_SYNC_URGENT = 0x00080000 DRS_REF_GCSPN = 0x00100000 DRS_NO_DISCARD = 0x00100000 DRS_NEVER_SYNCED = 0x00200000 DRS_SPECIAL_SECRET_PROCESSING = 0x00400000 DRS_INIT_SYNC_NOW = 0x00800000 DRS_PREEMPTED = 0x01000000 DRS_SYNC_FORCED = 0x02000000 DRS_DISABLE_AUTO_SYNC = 0x04000000 DRS_DISABLE_PERIODIC_SYNC = 0x08000000 DRS_USE_COMPRESSION = 0x10000000 DRS_NEVER_NOTIFY = 0x20000000 DRS_SYNC_PAS = 0x40000000 DRS_GET_ALL_GROUP_MEMBERSHIP = 0x80000000 # [4.1.10.2.22 EXOP_REQ Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/05de65ee-af0d-46d1-a9c8-4f0f856031cb) EXOP_FSMO_REQ_ROLE = 0x00000001 EXOP_FSMO_REQ_RID_ALLOC = 0x00000002 EXOP_FSMO_RID_REQ_ROLE = 0x00000003 EXOP_FSMO_REQ_PDC = 0x00000004 EXOP_FSMO_ABANDON_ROLE = 0x00000005 EXOP_REPL_OBJ = 0x00000006 EXOP_REPL_SECRETS = 0x00000007 # Enumeration for identifying a compression algorithm. # [4.1.10.2.18 DRS_COMP_ALG_TYPE](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/bb303730-0667-49f0-b117-288404c4b4cb) DRS_COMP_ALG_NONE = 0, DRS_COMP_ALG_UNUSED = 1, DRS_COMP_ALG_MSZIP = 2, DRS_COMP_ALG_WIN2K3 = 3 # [4.1.10.2.21 EXOP_ERR Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/bb303730-0667-49f0-b117-288404c4b4cb) EXOP_ERR_SUCCESS = 0x00000001 EXOP_ERR_UNKNOWN_OP = 0x00000002 EXOP_ERR_FSMO_NOT_OWNER = 0x00000003 EXOP_ERR_UPDATE_ERR = 0x00000004 EXOP_ERR_EXCEPTION = 0x00000005 EXOP_ERR_UNKNOWN_CALLER = 0x00000006 EXOP_ERR_RID_ALLOC = 0x00000007 EXOP_ERR_FSMO_OWNER_DELETED = 0x00000008 EXOP_ERR_FSMO_PENDING_OP = 0x00000009 EXOP_ERR_MISMATCH = 0x0000000A EXOP_ERR_COULDNT_CONTACT = 0x0000000B EXOP_ERR_FSMO_REFUSING_ROLES = 0x0000000C EXOP_ERR_DIR_ERROR = 0x0000000D EXOP_ERR_FSMO_MISSING_SETTINGS = 0x0000000E EXOP_ERR_ACCESS_DENIED = 0x0000000F EXOP_ERR_PARAM_ERROR = 0x00000010 # DRS_MSG_CRACKREQ_V1 dwFlags # [4.1.4.1.2 DRS_MSG_CRACKREQ_V1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/b47debc0-59ee-40e4-ad0f-4bc9f96043b2) DS_NAME_FLAG_GCVERIFY = 0x00000004 DS_NAME_FLAG_TRUST_REFERRAL = 0x00000008 DS_NAME_FLAG_PRIVATE_RESOLVE_FPOS = 0x80000000 # [4.1.4.1.3 DS_NAME_FORMAT](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/73c73cf2-0824-4d65-97f4-f56244f3e8a6) DS_UNKNOWN_NAME = 0x00000000, DS_FQDN_1779_NAME = 0x00000001, DS_NT4_ACCOUNT_NAME = 0x00000002, DS_DISPLAY_NAME = 0x00000003, DS_UNIQUE_ID_NAME = 0x00000006, DS_CANONICAL_NAME = 0x00000007, DS_USER_PRINCIPAL_NAME = 0x00000008, DS_CANONICAL_NAME_EX = 0x00000009, DS_SERVICE_PRINCIPAL_NAME = 0x0000000A, DS_SID_OR_SID_HISTORY_NAME = 0x0000000B, DS_DNS_DOMAIN_NAME = 0x0000000C # formatOffered: DS_NAME_FORMAT flags, plus these flags DS_LIST_SITES = 0xFFFFFFFF DS_LIST_SERVERS_IN_SITE = 0xFFFFFFFE DS_LIST_DOMAINS_IN_SITE = 0xFFFFFFFD DS_LIST_SERVERS_FOR_DOMAIN_IN_SITE = 0xFFFFFFFC DS_LIST_INFO_FOR_SERVER = 0xFFFFFFFB DS_LIST_ROLES = 0xFFFFFFFA DS_NT4_ACCOUNT_NAME_SANS_DOMAIN = 0xFFFFFFF9 DS_MAP_SCHEMA_GUID = 0xFFFFFFF8 DS_LIST_DOMAINS = 0xFFFFFFF7 DS_LIST_NCS = 0xFFFFFFF6 DS_ALT_SECURITY_IDENTITIES_NAME = 0xFFFFFFF5 DS_STRING_SID_NAME = 0xFFFFFFF4 DS_LIST_SERVERS_WITH_DCS_IN_SITE = 0xFFFFFFF3 DS_LIST_GLOBAL_CATALOG_SERVERS = 0xFFFFFFF1 DS_NT4_ACCOUNT_NAME_SANS_DOMAIN_EX = 0xFFFFFFF0 DS_USER_PRINCIPAL_NAME_AND_ALTSECID = 0xFFFFFFEF # formatDesired: DS_NAME_FORMAT flags, plus these flags DS_USER_PRINCIPAL_NAME_FOR_LOGON = 0xFFFFFFF2 # DS_STRING_SID_NAME = 0xFFFFFFF4 (already defined) ATTRTYP_TO_ATTID = { 'userPrincipalName' => '1.2.840.113556.1.4.656', 'sAMAccountName' => '1.2.840.113556.1.4.221', 'unicodePwd' => '1.2.840.113556.1.4.90', 'dBCSPwd' => '1.2.840.113556.1.4.55', 'ntPwdHistory' => '1.2.840.113556.1.4.94', 'lmPwdHistory' => '1.2.840.113556.1.4.160', 'supplementalCredentials' => '1.2.840.113556.1.4.125', 'objectSid' => '1.2.840.113556.1.4.146', 'pwdLastSet' => '1.2.840.113556.1.4.96', 'userAccountControl' => '1.2.840.113556.1.4.8', 'accountExpires' => '1.2.840.113556.1.4.159', 'lastLogonTimestamp' => '1.2.840.113556.1.4.1696' } class DrsHandle < Ndr::NdrContextHandle; end class DrsConfStringz16 < Ndr::NdrConfArray extend Ndr::ArrayClassPlugin default_parameters type: :ndr_wide_char end # [5.50 DSNAME](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/385d478f-3eb6-4d2c-ac58-f25c4debdd86) class DsName < Ndr::NdrStruct default_parameter byte_align: 4 endian :little # We don't want to include ref_id (4 bytes) if it is a pointer ndr_uint32 :struct_len, initial_value: -> { @obj.parent.respond_to?(:ref_id) ? num_bytes - 4 : num_bytes } ndr_uint32 :sid_len uuid :guid string :sid, byte_align: 1, length: 28 ndr_uint32 :name_len, initial_value: -> { string_name.max_count - 1 } drs_conf_stringz16 :string_name end class DsNamePtr < DsName default_parameters referent_byte_align: 4 extend Ndr::PointerClassPlugin end # [5.209 USN](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/1be1e991-a2db-4f91-9953-8eab69f60e64) class Usn < BinData::Int64le default_parameter byte_align: 8 end # [5.210 USN_VECTOR](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/595d11b8-6ca7-4a61-bd56-3e6a2b99b76b) class UsnVector < Ndr::NdrStruct default_parameter byte_align: 8 usn :usn_high_obj_update usn :usn_reserved usn :usn_high_prop_update end # [5.202 UPTODATE_CURSOR_V1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/cf88f341-fb49-4cd5-b7e2-6920cbd91f1b) class UptodateCursorV1 < Ndr::NdrStruct default_parameter byte_align: 8 uuid :uuid_dsa usn :usn_high_prop_update end # [5.204 UPTODATE_VECTOR_V1_EXT](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/462b424a-b50a-4c4a-a81f-48d0f4cf40fe) class UptodateVectorV1Ext < Ndr::NdrStruct default_parameter byte_align: 8 ndr_uint32 :dw_version ndr_uint32 :dw_reserved1 ndr_uint32 :c_num_cursors ndr_uint32 :dw_reserved2 ndr_conf_array :rg_cursors, type: :uptodate_cursor_v1 end class UptodateVectorV1ExtPtr < UptodateVectorV1Ext default_parameters referent_byte_align: 8 extend Ndr::PointerClassPlugin end module AttrtypRequestPlugin # [5.16.4 ATTRTYP-to-OID Conversion](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/6f53317f-2263-48ee-86c1-4580bf97232c) def add_attrtyp_from_oid(oid, to_field: :p_partial_attr_set) last_value = oid.split('.').last.to_i binary_oid = OpenSSL::ASN1::ObjectId.new(oid).to_der[2..-1] if last_value < 128 oid_prefix = binary_oid[0...-1].bytes else oid_prefix = binary_oid[0...-2].bytes end prefix_table = self.prefix_table_dest.p_prefix_entry prefix_table.instantiate_referent if prefix_table.is_null_ptr? pos = prefix_table.size index = prefix_table.to_ary.index { |e| e.prefix.elements == oid_prefix } if index pos = index else entry = PrefixTableEntry.new(ndx: pos) entry.prefix.elements = oid_prefix prefix_table << entry end lower_word = last_value % 0x4000 # mark it so that it is known to not be the whole lastValue lower_word += 0x8000 if last_value >= 0x4000 upper_word = pos attrtyp = (upper_word << 16) + lower_word attr_set_field = send(to_field) attr_set_field.instantiate_referent if attr_set_field.is_null_ptr? attr_set_field.rg_partial_attr << attrtyp end end module AttrtypResponsePlugin # [5.16.4 ATTRTYP-to-OID Conversion](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/6f53317f-2263-48ee-86c1-4580bf97232c) def oid_from_attid(attr_typ) upper_word = attr_typ / 0x10000 lower_word = attr_typ % 0x10000 prefix_table = self.prefix_table_src.p_prefix_entry binary_oid = nil prefix_table.each do |prefix_table_entry| if prefix_table_entry.ndx == upper_word binary_oid = prefix_table_entry.prefix.elements.to_ary.pack('C*') if lower_word < 128 binary_oid << [lower_word].pack('C') else lower_word -= 0x8000 if lower_word >= 0x8000 binary_oid << [((lower_word / 128) % 128) + 128].pack('C') binary_oid << [lower_word % 128].pack('C') end break end end return unless binary_oid OpenSSL::ASN1.decode("\x06#{[binary_oid.length].pack('C')}#{binary_oid}").value end end # [5.14 ATTRTYP](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/91173129-08e6-497c-8266-b5ac0aa5f983) class Attrtyp < Ndr::NdrUint32; end # [5.146 PARTIAL_ATTR_VECTOR_V1_EXT](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/1d5c1b34-daa4-4761-a8b5-d3c0146a0e30) class PartialAttrVectorV1Ext < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :dw_version, initial_value: 1 ndr_uint32 :dw_reserved1 ndr_uint32 :c_attrs, initial_value: -> { rg_partial_attr.max_count } ndr_conf_array :rg_partial_attr, type: :attrtyp end class PartialAttrVectorV1ExtPtr < PartialAttrVectorV1Ext default_parameters referent_byte_align: 4 extend Ndr::PointerClassPlugin end class DrsByteArrayPtr < Ndr::NdrConfArray default_parameters type: :ndr_uint8 extend Ndr::PointerClassPlugin end # [5.143 OID_t](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/cbc2b761-8938-4591-a9f7-2d1512ed7f05) class OidT < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :oid_length, initial_value: -> { elements.max_count } drs_byte_array_ptr :elements end # [5.154 PrefixTableEntry](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/d26d36cd-10c4-4b27-a84e-98336abf357a) class PrefixTableEntry < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :ndx oid_t :prefix end class PrefixTableEntryArrayPtr < Ndr::NdrConfArray default_parameter type: :prefix_table_entry extend Ndr::PointerClassPlugin end # [5.180 SCHEMA_PREFIX_TABLE](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/9b371267-e8b8-4c69-9979-02dae02e5e38) class SchemaPrefixTable < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :prefix_count, initial_value: -> { p_prefix_entry.max_count } prefix_table_entry_array_ptr :p_prefix_entry end class DrsConfStringz < Ndr::NdrConfArray extend Ndr::ArrayClassPlugin default_parameters type: :ndr_char end # [5.132 MTX_ADDR](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/107b7c0e-0f0d-4fe2-8232-14ec3b78f40d) class MtxAddr < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :mtx_name_len, initial_value: -> { mtx_name.length } drs_conf_stringz :mtx_name end class MtxAddrPtr < MtxAddr default_parameters referent_byte_align: 4 extend Ndr::PointerClassPlugin end # [5.219 VAR_SIZE_BUFFER_WITH_VERSION](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/589574c1-eaa1-456f-ac53-de597b2cff6b) class VarSizeBufferWithVersion < Ndr::NdrStruct default_parameter byte_align: 8 ndr_uint32 :ul_version ndr_uint32 :cb_byte_buffer, initial_value: -> { rg_buffer.size } ndr_uint64 :ul_padding ndr_conf_array :rg_buffer, type: :ndr_uint8 end class VarSizeBufferWithVersionPtr < VarSizeBufferWithVersion default_parameters referent_byte_align: 8 extend Ndr::PointerClassPlugin end # [5.16 ATTRVAL](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/cc002cbf-efe0-42f8-9295-a5a6577263d4) class Attrval < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :val_len, initial_value: -> { p_val.length } drs_byte_array_ptr :p_val end class AttrvalArrayPtr < Ndr::NdrConfArray default_parameters type: :attrval extend Ndr::PointerClassPlugin end # [5.17 ATTRVALBLOCK](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/b526370f-dfe5-4e85-9041-90d07bc16ff5) class Attrvalblock < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :val_count, initial_value: -> { p_aval.length } attrval_array_ptr :p_aval end # [5.9 ATTR](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/a2db41e2-7803-4d3c-a499-0fee92b1c149) class Attr < Ndr::NdrStruct default_parameter byte_align: 4 attrtyp :attr_typ attrvalblock :attr_val end class AttrArrayPtr < Ndr::NdrConfArray default_parameters type: :attr extend Ndr::PointerClassPlugin end # [5.10 ATTRBLOCK](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/f81324b8-6400-41b5-bc25-5117589c602a) class Attrblock < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :attr_count, initial_value: -> { p_attr.length } attr_array_ptr :p_attr end # [5.53 ENTINF](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/6d69822e-adb6-4977-8553-c2d529c17e5b) class Entinf < Ndr::NdrStruct default_parameter byte_align: 4 ds_name_ptr :p_name ndr_uint32 :ul_flags attrblock :attr_block end # [5.51 DSTIME](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/a72a16b9-73e4-41ca-a5c1-afc5fc54e175) class Dstime < BinData::Int64le default_parameter byte_align: 8 end # [5.155 PROPERTY_META_DATA_EXT](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/aef7ebde-c305-4224-95fd-585c86b19c38) class PropertyMetaDataExt < Ndr::NdrStruct default_parameter byte_align: 8 ndr_uint32 :dw_version dstime :time_changed uuid :uuid_dsa_originating usn :usn_originating end # [5.156 PROPERTY_META_DATA_EXT_VECTOR](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/22bccd51-1e7d-4502-aef8-b84da983f94f) class PropertyMetaDataExtVector < Ndr::NdrStruct default_parameter byte_align: 8 ndr_uint32 :c_num_props, initial_value: -> { rg_meta_data.size } ndr_conf_array :rg_meta_data, type: :property_meta_data_ext end class PropertyMetaDataExtVectorPtr < PropertyMetaDataExtVector default_parameters referent_byte_align: 8 extend Ndr::PointerClassPlugin end # [5.162 REPLENTINFLIST](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/c38b0412-cf00-4b0c-b4f4-4662a4484a00) class ReplentinflistPtr < Ndr::NdrStruct default_parameters byte_align: 4, referent_byte_align: 4 extend Ndr::PointerClassPlugin replentinflist_ptr :p_next_ent_inf entinf :entinf ndr_boolean :f_is_nc_prefix uuid_ptr :p_parent_guid property_meta_data_ext_vector_ptr :p_meta_data_ext end # [4.1.10.2.19 DRS_COMPRESSED_BLOB](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/6d3e7f57-3ef8-46e0-a6ad-e9331f297957) class DrsCompressedBlob < Ndr::NdrStruct default_parameter byte_align: 4 ndr_uint32 :cb_uncompressed_size ndr_uint32 :cb_compressed_size ndr_conf_array :pb_compressed_data, type: :ndr_uint8 end # [5.215 VALUE_META_DATA_EXT_V1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/7530cf2e-a2ad-4716-a570-8383f8b1846f) class ValueMetaDataExtV1 < Ndr::NdrStruct default_parameter byte_align: 8 dstime :time_created property_meta_data_ext :meta_data end # [5.167 REPLVALINF_V1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/22946fbf-170e-4ab4-82c7-dabdfd97bf5a) class ReplvalinfV1 < Ndr::NdrStruct default_parameter byte_align: 8 ds_name_ptr :p_object attrtyp :attr_typ attrval :aval ndr_boolean :f_is_present value_meta_data_ext_v1 :meta_data end class ReplvalinfV1ArrayPtr < Ndr::NdrConfArray default_parameters type: :replvalinf_v1 extend Ndr::PointerClassPlugin end # [4.1.10.2.18 DRS_COMP_ALG_TYPE](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/bb303730-0667-49f0-b117-288404c4b4cb) class DrsCompAlgType < Ndr::NdrUint32; end # [5.216 VALUE_META_DATA_EXT_V3](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/eab72899-a828-427d-8384-9a51ffdb77e1) class ValueMetaDataExtV3 < Ndr::NdrStruct default_parameter byte_align: 8 dstime :time_created property_meta_data_ext :meta_data ndr_uint32 :unused1 ndr_uint32 :unused2 ndr_uint32 :unused3 dstime :time_expired end # [5.168 REPLVALINF_V3](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/9c15369b-b7d2-437a-b73d-66a92c367795) class ReplvalinfV3 < Ndr::NdrStruct default_parameter byte_align: 8 ds_name_ptr :p_object attrtyp :attr_typ attrval :aval ndr_boolean :f_is_present value_meta_data_ext_v3 :meta_data end class ReplvalinfV3ArrayPtr < Ndr::NdrConfArray default_parameters type: :replvalinf_v3 extend Ndr::PointerClassPlugin end # [5.203 UPTODATE_CURSOR_V2](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/d3e30021-b6ac-413e-b08a-b69b9b0c6592) class UptodateCursorV2 < Ndr::NdrStruct default_parameter byte_align: 8 uuid :uuid_dsa usn :usn_high_prop_update dstime :time_last_sync_success end #[5.205 UPTODATE_VECTOR_V2_EXT](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/cebd1ccb-891b-4268-b056-4b714cdf981e) class UptodateVectorV2Ext < Ndr::NdrStruct default_parameter byte_align: 8 ndr_uint32 :dw_version ndr_uint32 :dw_reserved1 ndr_uint32 :c_num_cursors ndr_uint32 :dw_reserved2 ndr_conf_array :rg_cursors, type: :uptodate_cursor_v2 end class UptodateVectorV2ExtPtr < UptodateVectorV2Ext default_parameters referent_byte_align: 8 extend Ndr::PointerClassPlugin end require 'ruby_smb/dcerpc/drsr/drs_extensions' require 'ruby_smb/dcerpc/drsr/drs_bind_request' require 'ruby_smb/dcerpc/drsr/drs_bind_response' require 'ruby_smb/dcerpc/drsr/drs_unbind_request' require 'ruby_smb/dcerpc/drsr/drs_unbind_response' require 'ruby_smb/dcerpc/drsr/drs_domain_controller_info_request' require 'ruby_smb/dcerpc/drsr/drs_domain_controller_info_response' require 'ruby_smb/dcerpc/drsr/drs_crack_names_request' require 'ruby_smb/dcerpc/drsr/drs_crack_names_response' require 'ruby_smb/dcerpc/drsr/drs_get_nc_changes_request' require 'ruby_smb/dcerpc/drsr/drs_get_nc_changes_response' # Creates a context handle that is necessary to call any other method in this interface # # @return [RubySMB::Dcerpc::Drsr::DrsHandle] Context handle # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # DrsBind packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def drs_bind drs_extensions_int = DrsExtensionsInt.new( dw_flags: DRS_EXT_GETCHGREQ_V6 | DRS_EXT_GETCHGREPLY_V6 | DRS_EXT_GETCHGREQ_V8 | DRS_EXT_STRONG_ENCRYPTION, dw_ext_caps: 0xFFFFFFFF ) drs_bind_request = DrsBindRequest.new(pext_client: drs_extensions_int) response = dcerpc_request( drs_bind_request, auth_level: @auth_level, auth_type: @auth_type ) begin drs_bind_response = DrsBindResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading DrsBindResponse' end unless drs_bind_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::DrsrError, "Error returned with drs_bind: "\ "#{WindowsError::NTStatus.find_by_retval(drs_bind_response.error_status.value).join(',')}" end ppext_server = drs_bind_response.ppext_server raw_drs_extensions_int = ppext_server.cb.to_binary_s + ppext_server.rgb.to_binary_s drs_extensions_int_response = DrsExtensionsInt.new # If dwExtCaps is not included, just add zeros to parse it correctly raw_drs_extensions_int << "\x00".b * (drs_extensions_int.num_bytes - ppext_server.cb) drs_extensions_int_response.read(raw_drs_extensions_int) unless drs_extensions_int_response.dw_repl_epoch == 0 # Different epoch, we have to call DRSBind again drs_extensions_int.dw_repl_epoch = drs_extensions_int_response.dw_repl_epoch drs_bind_request.pext_client.assign(drs_extensions_int) response = dcerpc_request( drs_bind_request, auth_level: @auth_level, auth_type: @auth_type ) begin drs_bind_response = DrsBindResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading DrsBindResponse' end unless drs_bind_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::DrsrError, "Error returned with drs_bind: "\ "#{WindowsError::NTStatus.find_by_retval(drs_bind_response.error_status.value).join(',')}" end end drs_bind_response.ph_drs end # Destroys a context handle previously created by the #drs_bind method # # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # DrsUnbind packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def drs_unbind(ph_drs) drs_unbind_request = DrsUnbindRequest.new(ph_drs: ph_drs) response = dcerpc_request( drs_unbind_request, auth_level: @auth_level, auth_type: @auth_type ) begin drs_unbind_response = DrsUnbindResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading DrsUnbindResponse' end unless drs_unbind_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::DrsrError, "Error returned with drs_unbind: "\ "#{WindowsError::NTStatus.find_by_retval(drs_unbind_response.error_status.value).join(',')}" end nil end # Retrieves information about DCs in a given domain # # @param h_drs [RubySMB::Dcerpc::Drsr::DrsHandle] Context handle # previously created by the #drs_bind method # @param domain [String] Domain name # @return [Array] # Array of DsDomainControllerInfo1wPtr containing information about DCs # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # DrsDomainControllerInfo packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def drs_domain_controller_info(h_drs, domain) drs_domain_controller_info_request = DrsDomainControllerInfoRequest.new( h_drs: h_drs, pmsg_in: { switch_type: 1, msg_dcinfo: { domain: domain, info_level: 2 } } ) response = dcerpc_request( drs_domain_controller_info_request, auth_level: @auth_level, auth_type: @auth_type ) begin drs_domain_controller_info_response = DrsDomainControllerInfoResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading DrsDomainControllerInfoResponse' end unless drs_domain_controller_info_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::DrsrError, "Error returned with drs_domain_controller_info: "\ "#{WindowsError::NTStatus.find_by_retval(drs_domain_controller_info_response.error_status.value).join(',')}" end drs_domain_controller_info_response.pmsg_out.msg_dcinfo.r_items.to_ary end # Looks up each of a set of objects in the directory and returns it to # the caller in the requested format # # @param h_drs [RubySMB::Dcerpc::Drsr::DrsHandle] Context handle # previously created by the #drs_bind method # @param flags [Integer] Flags (see `DRS_MSG_CRACKREQ_V1 dwFlags` in this # file) # @param format_offered [Integer] The format of the names in rp_names # (see DS_NAME_FORMAT constants in this file ) # @param format_desired [Integer] The format of the names returned # (see DS_NAME_FORMAT constants in this file ) # @param rp_names [Array] Input names to translate # @return [Array] # Array of DsNameResultItemwPtr containing the translated names # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # DrsCrackNames packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def drs_crack_names(h_drs, flags: 0, format_offered: DS_SID_OR_SID_HISTORY_NAME, format_desired: DS_UNIQUE_ID_NAME, rp_names: []) drs_crack_names_request = DrsCrackNamesRequest.new( h_drs: h_drs, pmsg_in: { switch_type: 1, msg_crack: { dw_flags: flags, format_offered: format_offered, format_desired: format_desired, rp_names: rp_names } } ) response = dcerpc_request( drs_crack_names_request, auth_level: @auth_level, auth_type: @auth_type ) begin drs_crack_names_response = DrsCrackNamesResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading DrsCrackNamesResponse' end unless drs_crack_names_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::DrsrError, "Error returned with drs_crack_names: "\ "#{WindowsError::NTStatus.find_by_retval(drs_crack_names_response.error_status.value).join(',')}" end drs_crack_names_response.pmsg_out.msg_crack.p_result.r_items.to_ary end # [4.1.10.2.20 ENCRYPTED_PAYLOAD](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/7b60d2b3-5bb1-49aa-aefc-fa887e683977) class EncryptedPayload < BinData::Record endian :little uint8_array :salt, initial_length: 16 uint32 :check_sum uint8_array :encrypted_data, read_until: :eof end # [4.1.10.6.17 DecryptValuesIfNecessary](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/a14e34f0-69ff-484e-820c-1170c63c19ab) def decrypt_attribute_value(attribute) unless @session_key raise RubySMB::Error::EncryptionError, 'Unable to decrypt attribute value: session key is empty' end encrypted_payload = EncryptedPayload.read(attribute) signature = OpenSSL::Digest::MD5.digest(@session_key + encrypted_payload.salt.to_binary_s) rc4 = OpenSSL::Cipher.new('rc4') rc4.decrypt rc4.key = signature plain_text = rc4.update( encrypted_payload.check_sum.to_binary_s + encrypted_payload.encrypted_data.to_binary_s ) plain_text += rc4.final plain_text[4..-1] end # From [MS-LSAD] [5.1.3 DES-ECB-LM Cipher Definition](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lsad/32a2c8af-dc6e-4662-918d-ef333d570dd2) def transform_key(input_key) output_key = [] output_key << (input_key[0].ord >> 0x01).chr output_key << (((input_key[0].ord & 0x01) << 6) | (input_key[1].ord >> 2)).chr output_key << (((input_key[1].ord & 0x03) << 5) | (input_key[2].ord >> 3)).chr output_key << (((input_key[2].ord & 0x07) << 4) | (input_key[3].ord >> 4)).chr output_key << (((input_key[3].ord & 0x0F) << 3) | (input_key[4].ord >> 5)).chr output_key << (((input_key[4].ord & 0x1F) << 2) | (input_key[5].ord >> 6)).chr output_key << (((input_key[5].ord & 0x3F) << 1) | (input_key[6].ord >> 7)).chr output_key << (input_key[6].ord & 0x7F).chr output_key.map { |byte| ((byte.ord << 1) & 0xFE).chr }.join end # From [MS-SAMR] [2.2.11.1.3 Deriving Key1 and Key2 from a Little-Endian, Unsigned Integer Key](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/b1b0094f-2546-431f-b06d-582158a9f2bb) def derive_key(base_key) key = [base_key].pack('L<') key1 = [key[0] , key[1] , key[2] , key[3] , key[0] , key[1] , key[2]] key2 = [key[3] , key[0] , key[1] , key[2] , key[3] , key[0] , key[1]] [transform_key(key1.join), transform_key(key2.join)] end def remove_des_layer(crypted_hash, rid) key1, key2 = derive_key(rid) des = OpenSSL::Cipher.new('des-ecb') des.decrypt des.key = key1 des.padding = 0 decrypted_hash = des.update(crypted_hash[0,8]) decrypted_hash += des.final des.reset des.decrypt des.key = key2 des.padding = 0 decrypted_hash += des.update(crypted_hash[8..-1]) decrypted_hash += des.final decrypted_hash end # Replicates updates from an NC replica on the server # # @param h_drs [RubySMB::Dcerpc::Drsr::DrsHandle] Context handle # previously created by the #drs_bind method # @param nc_guid [String] GUID of the DSName representing the NC # (naming context) root of the replica to replicate # @param nc_guid [String] DSA GUID of the DC. # @return [RubySMB::Dcerpc::Drsr::DrsGetNcChangesResponse] Response # structure containing the updates # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a # DrsGetNcChanges packet # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status # is not STATUS_SUCCESS def drs_get_nc_changes(h_drs, nc_guid:, dsa_object_guid:) drs_get_nc_changes_request = DrsGetNcChangesRequest.new( h_drs: h_drs, dw_in_version: 8, pmsg_in: { msg_getchg: { uuid_dsa_obj_dest: dsa_object_guid, uuid_invoc_id_src: dsa_object_guid, p_nc: { guid: nc_guid, string_name: ["\0"] }, ul_flags: DRS_INIT_SYNC | DRS_WRIT_REP, c_max_objects: 1, ul_extended_op: EXOP_REPL_OBJ } } ) ATTRTYP_TO_ATTID.values.each do |oid| drs_get_nc_changes_request.pmsg_in.msg_getchg.add_attrtyp_from_oid(oid) end response = dcerpc_request( drs_get_nc_changes_request, auth_level: @auth_level, auth_type: @auth_type ) begin drs_get_nc_changes_response = DrsGetNcChangesResponse.read(response) rescue IOError raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading DrsGetNcChangesResponse' end unless drs_get_nc_changes_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Dcerpc::Error::DrsrError, "Error returned with drs_get_nc_changes: "\ "#{WindowsError::NTStatus.find_by_retval(drs_get_nc_changes_response.error_status.value).join(',')}" end drs_get_nc_changes_response end end end end