Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to query group memberships #278

Merged
merged 3 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/ruby_smb/dcerpc/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions lib/ruby_smb/dcerpc/samr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<String,String>>] 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
Expand Down
23 changes: 23 additions & 0 deletions lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_request.rb
Original file line number Diff line number Diff line change
@@ -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


34 changes: 34 additions & 0 deletions lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb
Original file line number Diff line number Diff line change
@@ -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_GROUPS_FOR_USER
smashery marked this conversation as resolved.
Show resolved Hide resolved
end
end
end
end
end

26 changes: 26 additions & 0 deletions lib/ruby_smb/dcerpc/samr/samr_open_group_request.rb
Original file line number Diff line number Diff line change
@@ -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

24 changes: 24 additions & 0 deletions lib/ruby_smb/dcerpc/samr/samr_open_group_response.rb
Original file line number Diff line number Diff line change
@@ -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


Loading