diff --git a/lib/ruby_smb/dcerpc/request.rb b/lib/ruby_smb/dcerpc/request.rb index 7931ff39..819b18e2 100644 --- a/lib/ruby_smb/dcerpc/request.rb +++ b/lib/ruby_smb/dcerpc/request.rb @@ -70,6 +70,8 @@ class Request < BinData::Record samr_close_handle_request Samr::SAMR_CLOSE_HANDLE samr_get_alias_membership_request Samr::SAMR_GET_ALIAS_MEMBERSHIP samr_open_user_request Samr::SAMR_OPEN_USER + samr_open_group_request Samr::SAMR_OPEN_GROUP + samr_get_members_in_group_request Samr::SAMR_GET_MEMBERS_IN_GROUP samr_get_groups_for_user_request Samr::SAMR_GET_GROUPS_FOR_USER samr_enumerate_domains_in_sam_server_request Samr::SAMR_ENUMERATE_DOMAINS_IN_SAM_SERVER samr_lookup_names_in_domain_request Samr::SAMR_LOOKUP_NAMES_IN_DOMAIN diff --git a/lib/ruby_smb/dcerpc/samr.rb b/lib/ruby_smb/dcerpc/samr.rb index 7c1a7d4f..00f1633c 100644 --- a/lib/ruby_smb/dcerpc/samr.rb +++ b/lib/ruby_smb/dcerpc/samr.rb @@ -20,6 +20,8 @@ module Samr SAMR_ENUMERATE_USERS_IN_DOMAIN = 0x000D SAMR_GET_ALIAS_MEMBERSHIP = 0x0010 SAMR_LOOKUP_NAMES_IN_DOMAIN = 0x0011 + SAMR_OPEN_GROUP = 0x0013 + SAMR_GET_MEMBERS_IN_GROUP = 0x0019 SAMR_OPEN_USER = 0x0022 SAMR_DELETE_USER = 0x0023 SAMR_GET_GROUPS_FOR_USER = 0x0027 @@ -509,8 +511,12 @@ def get_key_values require 'ruby_smb/dcerpc/samr/samr_rid_to_sid_response' require 'ruby_smb/dcerpc/samr/samr_close_handle_request' require 'ruby_smb/dcerpc/samr/samr_close_handle_response' + require 'ruby_smb/dcerpc/samr/samr_get_members_in_group_request' + require 'ruby_smb/dcerpc/samr/samr_get_members_in_group_response' require 'ruby_smb/dcerpc/samr/samr_get_alias_membership_request' require 'ruby_smb/dcerpc/samr/samr_get_alias_membership_response' + require 'ruby_smb/dcerpc/samr/samr_open_group_request' + require 'ruby_smb/dcerpc/samr/samr_open_group_response' require 'ruby_smb/dcerpc/samr/samr_open_user_request' require 'ruby_smb/dcerpc/samr/samr_open_user_response' require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_request' @@ -935,6 +941,40 @@ def samr_get_alias_membership(domain_handle:, sids:) samr_get_alias_membership_reponse.membership.elements.to_ary end + # Returns a handle to a group, given a RID + # + # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context + # representing a domain object + # @param access [Integer] An access control that indicates the requested + # access for the returned handle. It is a bitwise OR of common + # ACCESS_MASK and user ACCESS_MASK values (see + # lib/ruby_smb/dcerpc/samr.rb) + # @param group_id [Integer] RID of a group + # @return [RubySMB::Dcerpc::Samr::SamprHandle] The group handle + # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a + # SamrOpenGroup packet + # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status + # is not STATUS_SUCCESS + def samr_open_group(domain_handle:, access: MAXIMUM_ALLOWED, group_id:) + samr_open_group_request = SamrOpenGroupRequest.new( + domain_handle: domain_handle, + desired_access: access, + group_id: group_id + ) + response = dcerpc_request(samr_open_group_request) + begin + samr_open_group_response = SamrOpenGroupResponse.read(response) + rescue IOError + raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrOpenGroupResponse' + end + unless samr_open_group_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS + raise RubySMB::Dcerpc::Error::SamrError, + "Error returned when getting a handle to group #{group_id}: "\ + "#{WindowsError::NTStatus.find_by_retval(samr_open_grou_response.error_status.value).join(',')}" + end + samr_open_group_response.group_handle + end + # Returns a handle to a user, given a RID # # @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context @@ -969,6 +1009,36 @@ def samr_open_user(domain_handle:, access: MAXIMUM_ALLOWED, user_id:) samr_open_user_response.user_handle end + # Returns a listing of members of the given group + # + # @param group_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context + # representing a group object. + # @return [Array>] Array of RID and Attributes + # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a + # SamrGetMembersInGroup packet + # @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status + # is not STATUS_SUCCESS + def samr_get_members_in_group(group_handle:) + samr_get_members_in_group_request = SamrGetMembersInGroupRequest.new( + group_handle: group_handle + ) + response = dcerpc_request(samr_get_members_in_group_request) + begin + samr_get_members_in_group_response = SamrGetMembersInGroupResponse.read(response) + rescue IOError + raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrGetMembersInGroupResponse' + end + unless samr_get_members_in_group_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS + raise RubySMB::Dcerpc::Error::SamrError, + "Error returned while getting group membership: "\ + "#{WindowsError::NTStatus.find_by_retval(samr_get_members_in_group_response.error_status.value).join(',')}" + end + members = samr_get_members_in_group_response.members.members.to_ary + attributes = samr_get_members_in_group_response.members.attributes.to_ary + + members.zip(attributes) + end + # Returns a listing of groups that a user is a member of # # @param user_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context diff --git a/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_request.rb b/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_request.rb new file mode 100755 index 00000000..319cd1f2 --- /dev/null +++ b/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_request.rb @@ -0,0 +1,23 @@ +module RubySMB + module Dcerpc + module Samr + + # [3.1.5.8.3 SamrGetMembersInGroup (Opnum 25)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/3ed5030d-88a3-42ca-a6e0-8c12aa2fdfbd) + class SamrGetMembersInGroupRequest < BinData::Record + attr_reader :opnum + + endian :little + + sampr_handle :group_handle + + def initialize_instance + super + @opnum = SAMR_GET_MEMBERS_IN_GROUP + end + end + + end + end +end + + diff --git a/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb b/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb new file mode 100755 index 00000000..bf317f1f --- /dev/null +++ b/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb @@ -0,0 +1,34 @@ +module RubySMB + module Dcerpc + module Samr + # [2.2.7.14 SAMPR_GET_MEMBERS_BUFFER](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/225147b1-45b7-4fde-a5bf-bf420e18fa08) + class SamprGetMembersBuffer < Ndr::NdrStruct + default_parameter byte_align: 4 + + ndr_uint32 :member_count + ndr_uint32_conf_array_ptr :members, type: :ndr_uint32 + ndr_uint32_conf_array_ptr :attributes, type: :ndr_uint32 + end + + class PsamprGetMembersBuffer < SamprGetMembersBuffer + extend Ndr::PointerClassPlugin + end + + # [2.1.5.8.3 SamrGetMembersInGroup (Opnum 25)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/a4adbf20-040f-4416-a960-e5b7917fdae7) + class SamrGetMembersInGroupResponse < BinData::Record + attr_reader :opnum + + endian :little + + psampr_get_members_buffer :members + ndr_uint32 :error_status + + def initialize_instance + super + @opnum = SAMR_GET_MEMBERS_IN_GROUP + end + end + end + end +end + diff --git a/lib/ruby_smb/dcerpc/samr/samr_open_group_request.rb b/lib/ruby_smb/dcerpc/samr/samr_open_group_request.rb new file mode 100755 index 00000000..cd2f8180 --- /dev/null +++ b/lib/ruby_smb/dcerpc/samr/samr_open_group_request.rb @@ -0,0 +1,26 @@ +module RubySMB + module Dcerpc + module Samr + + # [3.1.5.1.7 SamrOpenGroup (Opnum 19)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/d396e6c9-d04a-4729-b0d8-f50f2748f3c8) + class SamrOpenGroupRequest < BinData::Record + attr_reader :opnum + + endian :little + + sampr_handle :domain_handle + # Access control on a server object: bitwise OR of common ACCESS_MASK + # and user ACCESS_MASK values (see lib/ruby_smb/dcerpc/samr.rb) + ndr_uint32 :desired_access + ndr_uint32 :group_id + + def initialize_instance + super + @opnum = SAMR_OPEN_GROUP + end + end + + end + end +end + diff --git a/lib/ruby_smb/dcerpc/samr/samr_open_group_response.rb b/lib/ruby_smb/dcerpc/samr/samr_open_group_response.rb new file mode 100755 index 00000000..f2f673ed --- /dev/null +++ b/lib/ruby_smb/dcerpc/samr/samr_open_group_response.rb @@ -0,0 +1,24 @@ +module RubySMB + module Dcerpc + module Samr + + # [3.1.5.1.7 SamrOpenGroup (Opnum 19)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/d396e6c9-d04a-4729-b0d8-f50f2748f3c8) + class SamrOpenGroupResponse < BinData::Record + attr_reader :opnum + + endian :little + + sampr_handle :group_handle + ndr_uint32 :error_status + + def initialize_instance + super + @opnum = SAMR_OPEN_GROUP + end + end + + end + end +end + +