ruby_smb 3.3.9 → 3.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/metasploit-framework_acceptance.yml +47 -0
- data/lib/ruby_smb/client.rb +5 -5
- data/lib/ruby_smb/dcerpc/client.rb +2 -4
- data/lib/ruby_smb/dcerpc/icpr.rb +2 -2
- data/lib/ruby_smb/dcerpc/request.rb +4 -1
- data/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb +34 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_group_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_group_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr.rb +71 -1
- data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request.rb +0 -3
- data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/wkssvc.rb +118 -3
- data/lib/ruby_smb/gss/provider/ntlm.rb +5 -9
- data/lib/ruby_smb/ntlm/client.rb +3 -74
- data/lib/ruby_smb/ntlm.rb +0 -37
- data/lib/ruby_smb/server/server_client/tree_connect.rb +2 -2
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +0 -2
- data/ruby_smb.gemspec +9 -2
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb +0 -8
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_identity_handle.rb +7 -0
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_request_spec.rb +71 -0
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_response_spec.rb +65 -0
- data/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb +58 -1
- data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +119 -4
- data/spec/lib/ruby_smb/ntlm/client/session_spec.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +19 -7
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/ntlm/custom/string_encoder.rb +0 -22
- data/lib/ruby_smb/utils.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 200e26ef444f49e42d6671ae291c557dbaa6d0b7ab5424df4b7c973fa990dbe5
|
4
|
+
data.tar.gz: 27ec24e3cd852a0634c1ef11067776a887ea06ad10e2752fc0acb2e6473d8d9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 84922acc15245aee475e8d8b3db354be2b389ef68fd9988ee2e14f850e9173b03220b51152a18bdcf097aaabbac08b78aeea7dc6e2be5ee3994e5894c5c7bc60
|
7
|
+
data.tar.gz: 1bc3d330a3c241a2e2e2b877d8b932830621fc6f12dd66cf718536a43971ab8c15bb4bcba498da72b891233a68d87d02a28396ee959652382f74d02d274bb2b0
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -0,0 +1,47 @@
|
|
1
|
+
name: Metasploit Framework Acceptance
|
2
|
+
|
3
|
+
# Optional, enabling concurrency limits: https://docs.github.com/en/actions/using-jobs/using-concurrency
|
4
|
+
#concurrency:
|
5
|
+
# group: ${{ github.ref }}-${{ github.workflow }}
|
6
|
+
# cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
7
|
+
|
8
|
+
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
|
9
|
+
permissions:
|
10
|
+
actions: none
|
11
|
+
checks: none
|
12
|
+
contents: none
|
13
|
+
deployments: none
|
14
|
+
id-token: none
|
15
|
+
issues: none
|
16
|
+
discussions: none
|
17
|
+
packages: none
|
18
|
+
pages: none
|
19
|
+
pull-requests: none
|
20
|
+
repository-projects: none
|
21
|
+
security-events: none
|
22
|
+
statuses: none
|
23
|
+
|
24
|
+
on:
|
25
|
+
workflow_dispatch:
|
26
|
+
inputs:
|
27
|
+
metasploitFrameworkCommit:
|
28
|
+
description: 'metasploit-framework branch would like to test'
|
29
|
+
required: true
|
30
|
+
default: 'master'
|
31
|
+
push:
|
32
|
+
branches-ignore:
|
33
|
+
- gh-pages
|
34
|
+
- metakitty
|
35
|
+
pull_request:
|
36
|
+
branches:
|
37
|
+
- '*'
|
38
|
+
# Example of running as a cron, to weed out flaky tests
|
39
|
+
# schedule:
|
40
|
+
# - cron: '*/15 * * * *'
|
41
|
+
|
42
|
+
jobs:
|
43
|
+
build:
|
44
|
+
uses: rapid7/metasploit-framework/.github/workflows/shared_smb_acceptance.yml@master
|
45
|
+
with:
|
46
|
+
metasploit_framework_commit: ${{ github.event.inputs.metasploitFrameworkCommit }}
|
47
|
+
build_smb: true
|
data/lib/ruby_smb/client.rb
CHANGED
@@ -4,7 +4,6 @@ module RubySMB
|
|
4
4
|
class Client
|
5
5
|
require 'ruby_smb/ntlm'
|
6
6
|
require 'ruby_smb/signing'
|
7
|
-
require 'ruby_smb/utils'
|
8
7
|
require 'ruby_smb/client/negotiation'
|
9
8
|
require 'ruby_smb/client/authentication'
|
10
9
|
require 'ruby_smb/client/tree_connect'
|
@@ -320,11 +319,12 @@ module RubySMB
|
|
320
319
|
if smb1 == false && smb2 == false && smb3 == false
|
321
320
|
raise ArgumentError, 'You must enable at least one Protocol'
|
322
321
|
end
|
322
|
+
|
323
323
|
@dispatcher = dispatcher
|
324
324
|
@pid = rand(0xFFFF)
|
325
325
|
@domain = domain
|
326
326
|
@local_workstation = local_workstation
|
327
|
-
@password =
|
327
|
+
@password = (password || '')
|
328
328
|
@sequence_counter = 0
|
329
329
|
@session_id = 0x00
|
330
330
|
@session_key = ''
|
@@ -334,7 +334,7 @@ module RubySMB
|
|
334
334
|
@smb1 = smb1
|
335
335
|
@smb2 = smb2
|
336
336
|
@smb3 = smb3
|
337
|
-
@username =
|
337
|
+
@username = (username || '')
|
338
338
|
@max_buffer_size = MAX_BUFFER_SIZE
|
339
339
|
# These sizes will be modified during negotiation
|
340
340
|
@server_max_buffer_size = SERVER_MAX_BUFFER_SIZE
|
@@ -417,8 +417,8 @@ module RubySMB
|
|
417
417
|
local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS)
|
418
418
|
@domain = domain
|
419
419
|
@local_workstation = local_workstation
|
420
|
-
@password =
|
421
|
-
@username =
|
420
|
+
@password = (pass || '')
|
421
|
+
@username = (user || '')
|
422
422
|
|
423
423
|
@ntlm_client = RubySMB::NTLM::Client.new(
|
424
424
|
@username,
|
@@ -9,12 +9,10 @@ module RubySMB
|
|
9
9
|
require 'ruby_smb/dcerpc'
|
10
10
|
require 'ruby_smb/gss'
|
11
11
|
require 'ruby_smb/peer_info'
|
12
|
-
require 'ruby_smb/utils'
|
13
12
|
|
14
13
|
include Dcerpc
|
15
14
|
include Epm
|
16
15
|
include PeerInfo
|
17
|
-
include Utils
|
18
16
|
|
19
17
|
# The default maximum size of a RPC message that the Client accepts (in bytes)
|
20
18
|
MAX_BUFFER_SIZE = 64512
|
@@ -120,8 +118,8 @@ module RubySMB
|
|
120
118
|
@read_timeout = read_timeout
|
121
119
|
@domain = domain
|
122
120
|
@local_workstation = local_workstation
|
123
|
-
@username =
|
124
|
-
@password =
|
121
|
+
@username = username
|
122
|
+
@password = password
|
125
123
|
@max_buffer_size = MAX_BUFFER_SIZE
|
126
124
|
@call_id = 1
|
127
125
|
@ctx_id = 0
|
data/lib/ruby_smb/dcerpc/icpr.rb
CHANGED
@@ -35,7 +35,7 @@ module RubySMB
|
|
35
35
|
def cert_server_request(attributes:, authority:, csr:)
|
36
36
|
cert_server_request_request = CertServerRequestRequest.new(
|
37
37
|
pwsz_authority: authority,
|
38
|
-
pctb_attribs: { pb: (
|
38
|
+
pctb_attribs: { pb: (attributes.map { |k,v| "#{k}:#{v}" }.join("\n").encode('UTF-16LE').force_encoding('ASCII-8BIT') + "\x00\x00".b) },
|
39
39
|
pctb_request: { pb: csr.to_der }
|
40
40
|
)
|
41
41
|
|
@@ -53,7 +53,7 @@ module RubySMB
|
|
53
53
|
ret = {
|
54
54
|
certificate: nil,
|
55
55
|
disposition: cert_server_request_response.pdw_disposition.value,
|
56
|
-
disposition_message: cert_server_request_response.pctb_disposition_message.buffer.chomp("\x00\x00").force_encoding('
|
56
|
+
disposition_message: cert_server_request_response.pctb_disposition_message.buffer.chomp("\x00\x00").force_encoding('UTF-16LE').encode,
|
57
57
|
status: {
|
58
58
|
CR_DISP_ISSUED => :issued,
|
59
59
|
CR_DISP_UNDER_SUBMISSION => :submitted,
|
@@ -70,6 +70,8 @@ module RubySMB
|
|
70
70
|
samr_close_handle_request Samr::SAMR_CLOSE_HANDLE
|
71
71
|
samr_get_alias_membership_request Samr::SAMR_GET_ALIAS_MEMBERSHIP
|
72
72
|
samr_open_user_request Samr::SAMR_OPEN_USER
|
73
|
+
samr_open_group_request Samr::SAMR_OPEN_GROUP
|
74
|
+
samr_get_members_in_group_request Samr::SAMR_GET_MEMBERS_IN_GROUP
|
73
75
|
samr_get_groups_for_user_request Samr::SAMR_GET_GROUPS_FOR_USER
|
74
76
|
samr_enumerate_domains_in_sam_server_request Samr::SAMR_ENUMERATE_DOMAINS_IN_SAM_SERVER
|
75
77
|
samr_lookup_names_in_domain_request Samr::SAMR_LOOKUP_NAMES_IN_DOMAIN
|
@@ -80,7 +82,8 @@ module RubySMB
|
|
80
82
|
string :default
|
81
83
|
end
|
82
84
|
choice 'Wkssvc', selection: -> { opnum } do
|
83
|
-
netr_wksta_get_info_request
|
85
|
+
netr_wksta_get_info_request Wkssvc::NETR_WKSTA_GET_INFO
|
86
|
+
netr_wksta_user_enum_request Wkssvc::NETR_WKSTA_USER_ENUM
|
84
87
|
string :default
|
85
88
|
end
|
86
89
|
choice 'Epm', selection: -> { opnum } do
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.8.3 SamrGetMembersInGroup (Opnum 25)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/3ed5030d-88a3-42ca-a6e0-8c12aa2fdfbd)
|
6
|
+
class SamrGetMembersInGroupRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sampr_handle :group_handle
|
12
|
+
|
13
|
+
def initialize_instance
|
14
|
+
super
|
15
|
+
@opnum = SAMR_GET_MEMBERS_IN_GROUP
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
# [2.2.7.14 SAMPR_GET_MEMBERS_BUFFER](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/225147b1-45b7-4fde-a5bf-bf420e18fa08)
|
5
|
+
class SamprGetMembersBuffer < Ndr::NdrStruct
|
6
|
+
default_parameter byte_align: 4
|
7
|
+
|
8
|
+
ndr_uint32 :member_count
|
9
|
+
ndr_uint32_conf_array_ptr :members, type: :ndr_uint32
|
10
|
+
ndr_uint32_conf_array_ptr :attributes, type: :ndr_uint32
|
11
|
+
end
|
12
|
+
|
13
|
+
class PsamprGetMembersBuffer < SamprGetMembersBuffer
|
14
|
+
extend Ndr::PointerClassPlugin
|
15
|
+
end
|
16
|
+
|
17
|
+
# [2.1.5.8.3 SamrGetMembersInGroup (Opnum 25)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/a4adbf20-040f-4416-a960-e5b7917fdae7)
|
18
|
+
class SamrGetMembersInGroupResponse < BinData::Record
|
19
|
+
attr_reader :opnum
|
20
|
+
|
21
|
+
endian :little
|
22
|
+
|
23
|
+
psampr_get_members_buffer :members
|
24
|
+
ndr_uint32 :error_status
|
25
|
+
|
26
|
+
def initialize_instance
|
27
|
+
super
|
28
|
+
@opnum = SAMR_GET_MEMBERS_IN_GROUP
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.1.7 SamrOpenGroup (Opnum 19)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/d396e6c9-d04a-4729-b0d8-f50f2748f3c8)
|
6
|
+
class SamrOpenGroupRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sampr_handle :domain_handle
|
12
|
+
# Access control on a server object: bitwise OR of common ACCESS_MASK
|
13
|
+
# and user ACCESS_MASK values (see lib/ruby_smb/dcerpc/samr.rb)
|
14
|
+
ndr_uint32 :desired_access
|
15
|
+
ndr_uint32 :group_id
|
16
|
+
|
17
|
+
def initialize_instance
|
18
|
+
super
|
19
|
+
@opnum = SAMR_OPEN_GROUP
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.1.7 SamrOpenGroup (Opnum 19)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/d396e6c9-d04a-4729-b0d8-f50f2748f3c8)
|
6
|
+
class SamrOpenGroupResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sampr_handle :group_handle
|
12
|
+
ndr_uint32 :error_status
|
13
|
+
|
14
|
+
def initialize_instance
|
15
|
+
super
|
16
|
+
@opnum = SAMR_OPEN_GROUP
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
data/lib/ruby_smb/dcerpc/samr.rb
CHANGED
@@ -20,6 +20,8 @@ module RubySMB
|
|
20
20
|
SAMR_ENUMERATE_USERS_IN_DOMAIN = 0x000D
|
21
21
|
SAMR_GET_ALIAS_MEMBERSHIP = 0x0010
|
22
22
|
SAMR_LOOKUP_NAMES_IN_DOMAIN = 0x0011
|
23
|
+
SAMR_OPEN_GROUP = 0x0013
|
24
|
+
SAMR_GET_MEMBERS_IN_GROUP = 0x0019
|
23
25
|
SAMR_OPEN_USER = 0x0022
|
24
26
|
SAMR_DELETE_USER = 0x0023
|
25
27
|
SAMR_GET_GROUPS_FOR_USER = 0x0027
|
@@ -337,7 +339,7 @@ module RubySMB
|
|
337
339
|
|
338
340
|
def self.encrypt_password(password, key)
|
339
341
|
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5fe3c4c4-e71b-440d-b2fd-8448bfaf6e04
|
340
|
-
password =
|
342
|
+
password = password.encode('UTF-16LE').force_encoding('ASCII-8BIT')
|
341
343
|
buffer = password.rjust(512, "\x00") + [ password.length ].pack('V')
|
342
344
|
salt = SecureRandom.random_bytes(16)
|
343
345
|
key = OpenSSL::Digest::MD5.new(salt + key).digest
|
@@ -509,8 +511,12 @@ module RubySMB
|
|
509
511
|
require 'ruby_smb/dcerpc/samr/samr_rid_to_sid_response'
|
510
512
|
require 'ruby_smb/dcerpc/samr/samr_close_handle_request'
|
511
513
|
require 'ruby_smb/dcerpc/samr/samr_close_handle_response'
|
514
|
+
require 'ruby_smb/dcerpc/samr/samr_get_members_in_group_request'
|
515
|
+
require 'ruby_smb/dcerpc/samr/samr_get_members_in_group_response'
|
512
516
|
require 'ruby_smb/dcerpc/samr/samr_get_alias_membership_request'
|
513
517
|
require 'ruby_smb/dcerpc/samr/samr_get_alias_membership_response'
|
518
|
+
require 'ruby_smb/dcerpc/samr/samr_open_group_request'
|
519
|
+
require 'ruby_smb/dcerpc/samr/samr_open_group_response'
|
514
520
|
require 'ruby_smb/dcerpc/samr/samr_open_user_request'
|
515
521
|
require 'ruby_smb/dcerpc/samr/samr_open_user_response'
|
516
522
|
require 'ruby_smb/dcerpc/samr/samr_get_groups_for_user_request'
|
@@ -935,6 +941,40 @@ module RubySMB
|
|
935
941
|
samr_get_alias_membership_reponse.membership.elements.to_ary
|
936
942
|
end
|
937
943
|
|
944
|
+
# Returns a handle to a group, given a RID
|
945
|
+
#
|
946
|
+
# @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context
|
947
|
+
# representing a domain object
|
948
|
+
# @param access [Integer] An access control that indicates the requested
|
949
|
+
# access for the returned handle. It is a bitwise OR of common
|
950
|
+
# ACCESS_MASK and user ACCESS_MASK values (see
|
951
|
+
# lib/ruby_smb/dcerpc/samr.rb)
|
952
|
+
# @param group_id [Integer] RID of a group
|
953
|
+
# @return [RubySMB::Dcerpc::Samr::SamprHandle] The group handle
|
954
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
955
|
+
# SamrOpenGroup packet
|
956
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
957
|
+
# is not STATUS_SUCCESS
|
958
|
+
def samr_open_group(domain_handle:, access: MAXIMUM_ALLOWED, group_id:)
|
959
|
+
samr_open_group_request = SamrOpenGroupRequest.new(
|
960
|
+
domain_handle: domain_handle,
|
961
|
+
desired_access: access,
|
962
|
+
group_id: group_id
|
963
|
+
)
|
964
|
+
response = dcerpc_request(samr_open_group_request)
|
965
|
+
begin
|
966
|
+
samr_open_group_response = SamrOpenGroupResponse.read(response)
|
967
|
+
rescue IOError
|
968
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrOpenGroupResponse'
|
969
|
+
end
|
970
|
+
unless samr_open_group_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
971
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
972
|
+
"Error returned when getting a handle to group #{group_id}: "\
|
973
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_open_grou_response.error_status.value).join(',')}"
|
974
|
+
end
|
975
|
+
samr_open_group_response.group_handle
|
976
|
+
end
|
977
|
+
|
938
978
|
# Returns a handle to a user, given a RID
|
939
979
|
#
|
940
980
|
# @param domain_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context
|
@@ -969,6 +1009,36 @@ module RubySMB
|
|
969
1009
|
samr_open_user_response.user_handle
|
970
1010
|
end
|
971
1011
|
|
1012
|
+
# Returns a listing of members of the given group
|
1013
|
+
#
|
1014
|
+
# @param group_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context
|
1015
|
+
# representing a group object.
|
1016
|
+
# @return [Array<Array<String,String>>] Array of RID and Attributes
|
1017
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
1018
|
+
# SamrGetMembersInGroup packet
|
1019
|
+
# @raise [RubySMB::Dcerpc::Error::SamrError] if the response error status
|
1020
|
+
# is not STATUS_SUCCESS
|
1021
|
+
def samr_get_members_in_group(group_handle:)
|
1022
|
+
samr_get_members_in_group_request = SamrGetMembersInGroupRequest.new(
|
1023
|
+
group_handle: group_handle
|
1024
|
+
)
|
1025
|
+
response = dcerpc_request(samr_get_members_in_group_request)
|
1026
|
+
begin
|
1027
|
+
samr_get_members_in_group_response = SamrGetMembersInGroupResponse.read(response)
|
1028
|
+
rescue IOError
|
1029
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading SamrGetMembersInGroupResponse'
|
1030
|
+
end
|
1031
|
+
unless samr_get_members_in_group_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
1032
|
+
raise RubySMB::Dcerpc::Error::SamrError,
|
1033
|
+
"Error returned while getting group membership: "\
|
1034
|
+
"#{WindowsError::NTStatus.find_by_retval(samr_get_members_in_group_response.error_status.value).join(',')}"
|
1035
|
+
end
|
1036
|
+
members = samr_get_members_in_group_response.members.members.to_ary
|
1037
|
+
attributes = samr_get_members_in_group_response.members.attributes.to_ary
|
1038
|
+
|
1039
|
+
members.zip(attributes)
|
1040
|
+
end
|
1041
|
+
|
972
1042
|
# Returns a listing of groups that a user is a member of
|
973
1043
|
#
|
974
1044
|
# @param user_handle [RubySMB::Dcerpc::Samr::SamprHandle] An RPC context
|
@@ -2,9 +2,6 @@ module RubySMB
|
|
2
2
|
module Dcerpc
|
3
3
|
module Wkssvc
|
4
4
|
|
5
|
-
# [2.2.2.1 WKSSVC_IDENTIFY_HANDLE](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/9ef94a11-0e5c-49d7-9ac7-68d6f03565de)
|
6
|
-
class WkssvcIdentifyHandle < Ndr::NdrWideStringPtr; end
|
7
|
-
|
8
5
|
# [3.2.4.1 NetrWkstaGetInfo (Opnum 0)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/4af41d6f-b800-4de1-af5b-0b15a85f8e04)
|
9
6
|
class NetrWkstaGetInfoRequest < BinData::Record
|
10
7
|
attr_reader :opnum
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Wkssvc
|
4
|
+
|
5
|
+
# [3.2.4.3 NetrWkstaUserEnum (Opnum 2)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/4af41d6f-b800-4de1-af5b-0b15a85f8e04)
|
6
|
+
class NetrWkstaUserEnumRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
wkssvc_identify_handle :server_name
|
12
|
+
wksta_user_enum_structure :user_info
|
13
|
+
ndr_uint32 :preferred_max_length, initial_value: 0xFFFFFFFF
|
14
|
+
ndr_uint32_ptr :result_handle, initial_value: 0
|
15
|
+
|
16
|
+
def initialize_instance
|
17
|
+
super
|
18
|
+
@opnum = NETR_WKSTA_USER_ENUM
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Wkssvc
|
4
|
+
|
5
|
+
# [3.2.4.3 NetrWkstaUserEnum (Opnum 2)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/4af41d6f-b800-4de1-af5b-0b15a85f8e04)
|
6
|
+
class NetrWkstaUserEnumResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
wksta_user_enum_structure :user_info
|
12
|
+
ndr_uint32_ptr :total_entries
|
13
|
+
ndr_uint32_ptr :result_handle
|
14
|
+
ndr_uint32 :error_status
|
15
|
+
|
16
|
+
def initialize_instance
|
17
|
+
super
|
18
|
+
@opnum = NETR_WKSTA_USER_ENUM
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -7,7 +7,8 @@ module RubySMB
|
|
7
7
|
VER_MINOR = 0
|
8
8
|
|
9
9
|
# Operation numbers
|
10
|
-
NETR_WKSTA_GET_INFO
|
10
|
+
NETR_WKSTA_GET_INFO = 0x0000
|
11
|
+
NETR_WKSTA_USER_ENUM = 0x0002
|
11
12
|
|
12
13
|
PLATFORM_ID = {
|
13
14
|
0x0000012C => "DOS",
|
@@ -23,9 +24,85 @@ module RubySMB
|
|
23
24
|
WKSTA_INFO_102 = 0x00000066
|
24
25
|
#TODO: WKSTA_INFO_502 = 0x000001F6
|
25
26
|
|
27
|
+
# User Enum Information Level
|
28
|
+
WKSTA_USER_INFO_0 = 0x00000000
|
29
|
+
WKSTA_USER_INFO_1 = 0x00000001
|
30
|
+
|
31
|
+
# [2.2.2.1 WKSSVC_IDENTIFY_HANDLE](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/9ef94a11-0e5c-49d7-9ac7-68d6f03565de)
|
32
|
+
class WkssvcIdentifyHandle < Ndr::NdrWideStringzPtr; end
|
33
|
+
|
34
|
+
# [2.2.5.9 WKSTA_USER_INFO_0](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/b7c53c6f-8b92-4e5d-9a2e-6462cb4ef1ac)
|
35
|
+
class WkstaUserInfo0 < Ndr::NdrStruct
|
36
|
+
default_parameter byte_align: 4
|
37
|
+
endian :little
|
38
|
+
|
39
|
+
ndr_wide_stringz_ptr :wkui0_username
|
40
|
+
end
|
41
|
+
|
42
|
+
class WkstaUserInfo0ArrayPtr < Ndr::NdrConfArray
|
43
|
+
default_parameter type: :wksta_user_info0
|
44
|
+
extend Ndr::PointerClassPlugin
|
45
|
+
end
|
46
|
+
|
47
|
+
# [2.2.5.12 WKSTA_USER_INFO_0_CONTAINER](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/0b0cff8f-09bc-43a8-b0d3-88f0bf7e3664)
|
48
|
+
class WkstaUserInfo0Container < Ndr::NdrStruct
|
49
|
+
default_parameter byte_align: 4
|
50
|
+
endian :little
|
51
|
+
|
52
|
+
ndr_uint32 :wkui0_entries_read
|
53
|
+
wksta_user_info0_array_ptr :wkui0_buffer
|
54
|
+
end
|
55
|
+
|
56
|
+
class PwkstaUserInfo0Container < WkstaUserInfo0Container
|
57
|
+
extend Ndr::PointerClassPlugin
|
58
|
+
end
|
59
|
+
|
60
|
+
# [2.2.5.10 WKSTA_USER_INFO_1](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/c37b9606-866f-40ac-9490-57b8334968e2)
|
61
|
+
class WkstaUserInfo1 < Ndr::NdrStruct
|
62
|
+
default_parameter byte_align: 4
|
63
|
+
endian :little
|
64
|
+
|
65
|
+
ndr_wide_stringz_ptr :wkui1_username
|
66
|
+
ndr_wide_stringz_ptr :wkui1_logon_domain
|
67
|
+
ndr_wide_stringz_ptr :wkui1_oth_domains
|
68
|
+
ndr_wide_stringz_ptr :wkui1_logon_server
|
69
|
+
end
|
70
|
+
|
71
|
+
class WkstaUserInfo1ArrayPtr < Ndr::NdrConfArray
|
72
|
+
default_parameter type: :wksta_user_info1
|
73
|
+
extend Ndr::PointerClassPlugin
|
74
|
+
end
|
75
|
+
|
76
|
+
# [2.2.5.13 WKSTA_USER_INFO_1_CONTAINER](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/22a813e4-fc7d-4fe3-a6d6-78debfd2c0c9)
|
77
|
+
class WkstaUserInfo1Container < Ndr::NdrStruct
|
78
|
+
default_parameter byte_align: 4
|
79
|
+
endian :little
|
80
|
+
|
81
|
+
ndr_uint32 :wkui1_entries_read
|
82
|
+
wksta_user_info1_array_ptr :wkui1_buffer
|
83
|
+
end
|
84
|
+
|
85
|
+
class PwkstaUserInfo1Container < WkstaUserInfo1Container
|
86
|
+
extend Ndr::PointerClassPlugin
|
87
|
+
end
|
88
|
+
|
89
|
+
# [2.2.5.14 WKSTA_USER_ENUM_STRUCT](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wkst/4041455a-52be-4389-a4fc-82fea3cb3160)
|
90
|
+
class WkstaUserEnumStructure < Ndr::NdrStruct
|
91
|
+
default_parameter byte_align: 4
|
92
|
+
endian :little
|
93
|
+
|
94
|
+
ndr_uint32 :level
|
95
|
+
ndr_uint32 :tag, value: -> { self.level }
|
96
|
+
choice :info, selection: :level, byte_align: 4 do
|
97
|
+
pwksta_user_info0_container WKSTA_USER_INFO_0
|
98
|
+
pwksta_user_info1_container WKSTA_USER_INFO_1
|
99
|
+
end
|
100
|
+
end
|
26
101
|
|
27
102
|
require 'ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request'
|
28
103
|
require 'ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response'
|
104
|
+
require 'ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_request'
|
105
|
+
require 'ruby_smb/dcerpc/wkssvc/netr_wksta_user_enum_response'
|
29
106
|
|
30
107
|
# Returns details about a computer environment, including
|
31
108
|
# platform-specific information, the names of the domain and local
|
@@ -33,14 +110,14 @@ module RubySMB
|
|
33
110
|
#
|
34
111
|
# @param server_name [optional, String] String that identifies the server (optional
|
35
112
|
# since it is ignored by the server)
|
36
|
-
# @param
|
113
|
+
# @param level [optional, Integer] The information level of the data (default: WKSTA_INFO_100)
|
37
114
|
# @return [RubySMB::Dcerpc::Wkssvc::WkstaInfo100, RubySMB::Dcerpc::Wkssvc::WkstaInfo101,
|
38
115
|
# RubySMB::Dcerpc::Wkssvc::WkstaInfo102] The structure containing the requested information
|
39
116
|
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
40
117
|
# NetrWkstaGetInfoResponse packet
|
41
118
|
# @raise [RubySMB::Dcerpc::Error::WkssvcError] if the response error status
|
42
119
|
# is not STATUS_SUCCESS
|
43
|
-
def netr_wksta_get_info(server_name:
|
120
|
+
def netr_wksta_get_info(server_name: '', level: WKSTA_INFO_100)
|
44
121
|
wkst_netr_wksta_get_info_request = NetrWkstaGetInfoRequest.new(
|
45
122
|
server_name: server_name,
|
46
123
|
level: level
|
@@ -59,6 +136,44 @@ module RubySMB
|
|
59
136
|
wkst_netr_wksta_get_info_response.wksta_info.info
|
60
137
|
end
|
61
138
|
|
139
|
+
# Returns details about users who are currently active on a remote computer.
|
140
|
+
#
|
141
|
+
# @param server_name [optional, String] String that identifies the server (optional
|
142
|
+
# since it is ignored by the server)
|
143
|
+
# @param level [optional, Integer] The information level of the data (default: WKSTA_USER_INFO_0)
|
144
|
+
# @return [RubySMB::Dcerpc::Wkssvc::WkstaUserInfo0, RubySMB::Dcerpc::Wkssvc::WkstaUserInfo1]
|
145
|
+
# The structure containing the requested information
|
146
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
|
147
|
+
# NetrWkstaGetInfoResponse packet
|
148
|
+
# @raise [RubySMB::Dcerpc::Error::WkssvcError] if the response error status
|
149
|
+
# is not STATUS_SUCCESS
|
150
|
+
def netr_wksta_user_enum(server_name: '', level: WKSTA_USER_INFO_0)
|
151
|
+
wkst_netr_wksta_enum_user_request = NetrWkstaUserEnumRequest.new(
|
152
|
+
server_name: server_name,
|
153
|
+
user_info: {
|
154
|
+
level: level,
|
155
|
+
tag: level,
|
156
|
+
info: {
|
157
|
+
wkui0_entries_read: 0,
|
158
|
+
},
|
159
|
+
},
|
160
|
+
preferred_max_length: 0xFFFFFFFF,
|
161
|
+
result_handle: 0
|
162
|
+
)
|
163
|
+
response = dcerpc_request(wkst_netr_wksta_enum_user_request)
|
164
|
+
begin
|
165
|
+
wkst_netr_wksta_enum_user_response = NetrWkstaUserEnumResponse.read(response)
|
166
|
+
rescue IOError
|
167
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading WkstNetrWkstaUserEnumResponse'
|
168
|
+
end
|
169
|
+
unless wkst_netr_wksta_enum_user_response.error_status == WindowsError::NTStatus::STATUS_SUCCESS
|
170
|
+
raise RubySMB::Dcerpc::Error::WkssvcError,
|
171
|
+
"Error returned with netr_wksta_enum_user: #{wkst_netr_wksta_enum_user_response.error_status.value} - "\
|
172
|
+
"#{WindowsError::NTStatus.find_by_retval(wkst_netr_wksta_enum_user_response.error_status.value).join(',')}"
|
173
|
+
end
|
174
|
+
wkst_netr_wksta_enum_user_response.user_info.info
|
175
|
+
end
|
176
|
+
|
62
177
|
end
|
63
178
|
end
|
64
179
|
end
|
@@ -142,10 +142,7 @@ module RubySMB
|
|
142
142
|
case type3_msg.ntlm_version
|
143
143
|
when :ntlmv1
|
144
144
|
my_ntlm_response = Net::NTLM::ntlm_response(
|
145
|
-
ntlm_hash: Net::NTLM::ntlm_hash(
|
146
|
-
RubySMB::Utils.safe_encode(account.password, 'UTF-16LE'),
|
147
|
-
unicode: true
|
148
|
-
),
|
145
|
+
ntlm_hash: Net::NTLM::ntlm_hash(account.password),
|
149
146
|
challenge: @server_challenge
|
150
147
|
)
|
151
148
|
matches = my_ntlm_response == type3_msg.ntlm_response
|
@@ -155,9 +152,9 @@ module RubySMB
|
|
155
152
|
their_blob = type3_msg.ntlm_response[digest.digest_length..-1]
|
156
153
|
|
157
154
|
ntlmv2_hash = Net::NTLM.ntlmv2_hash(
|
158
|
-
|
159
|
-
|
160
|
-
|
155
|
+
Net::NTLM::EncodeUtil.encode_utf16le(account.username),
|
156
|
+
Net::NTLM::EncodeUtil.encode_utf16le(account.password),
|
157
|
+
type3_msg.domain.dup.force_encoding('ASCII-8BIT'), # don't use the account domain because of the special '.' value
|
161
158
|
{client_challenge: their_blob[16...24], unicode: true}
|
162
159
|
)
|
163
160
|
|
@@ -310,8 +307,7 @@ module RubySMB
|
|
310
307
|
domain = @default_domain if domain.nil? || domain == '.'.encode(domain.encoding)
|
311
308
|
domain = domain.downcase
|
312
309
|
@accounts.find do |account|
|
313
|
-
|
314
|
-
RubySMB::Utils.safe_encode(account.domain, domain.encoding).downcase == domain
|
310
|
+
account.username.encode(username.encoding).downcase == username && account.domain.encode(domain.encoding).downcase == domain
|
315
311
|
end
|
316
312
|
end
|
317
313
|
|