ruby_smb 3.3.10 → 3.3.12
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 +2 -0
- 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 +73 -3
- data/lib/ruby_smb/gss/provider/ntlm.rb +3 -7
- 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/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 +11 -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: d9ee813b67da3f28bf15f24cd60e6ff6be3c931490f97fe95786537d191a171b
|
4
|
+
data.tar.gz: 0d36cfa0892d145bf40d1ad43ba8e0d35185357c50d35ce8e7bc64a586041bcf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b52b91a93e363be0ed1578a6b67c94409e831a848da346cf1e985e1686804bbf444e1ba15d3a6f350cb77bba9a8a035b06c4c066b96665399805da8bc0193011
|
7
|
+
data.tar.gz: 17d2c3bc2bb46204538a827aac81a9f46317518cbf24abdade18fd60460b57db131ed3d6d8db3cce8accadd752256c7fb8fc53b74a435a1226048166d93c0020
|
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
|
@@ -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
|
@@ -441,8 +443,8 @@ module RubySMB
|
|
441
443
|
uint16 :reserved3
|
442
444
|
string :reserved4, length: 96
|
443
445
|
uint16 :property_signature, initial_value: 0x50
|
444
|
-
uint16 :property_count, initial_value: -> { user_properties.size }
|
445
|
-
array :user_properties, type: :user_property, initial_length: :property_count
|
446
|
+
uint16 :property_count, initial_value: -> { user_properties.size }, onlyif: -> { struct_length > 111 }
|
447
|
+
array :user_properties, type: :user_property, initial_length: :property_count, onlyif: :property_count?
|
446
448
|
uint8 :reserved5
|
447
449
|
end
|
448
450
|
|
@@ -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
|
@@ -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
|
@@ -157,7 +154,7 @@ module RubySMB
|
|
157
154
|
ntlmv2_hash = Net::NTLM.ntlmv2_hash(
|
158
155
|
Net::NTLM::EncodeUtil.encode_utf16le(account.username),
|
159
156
|
Net::NTLM::EncodeUtil.encode_utf16le(account.password),
|
160
|
-
type3_msg.domain.force_encoding('ASCII-8BIT'), # don't use the account domain because of the special '.' value
|
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
|
|
data/lib/ruby_smb/ntlm/client.rb
CHANGED
@@ -1,78 +1,7 @@
|
|
1
1
|
module RubySMB::NTLM
|
2
|
-
module Message
|
3
|
-
def deflag
|
4
|
-
security_buffers.inject(head_size) do |cur, a|
|
5
|
-
a[1].offset = cur
|
6
|
-
cur += a[1].data_size
|
7
|
-
has_flag?(:UNICODE) ? cur + cur % 2 : cur
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def serialize
|
12
|
-
deflag
|
13
|
-
@alist.map { |n, f| f.serialize }.join + security_buffers.map { |n, f| f.value + (has_flag?(:UNICODE) ? "\x00".b * (f.value.length % 2) : '') }.join
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
2
|
class Client < Net::NTLM::Client
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
type3_opts = {
|
22
|
-
:lm_response => is_anonymous? ? "\x00".b : lmv2_resp,
|
23
|
-
:ntlm_response => is_anonymous? ? '' : ntlmv2_resp,
|
24
|
-
:domain => domain,
|
25
|
-
:user => username,
|
26
|
-
:workstation => workstation,
|
27
|
-
:flag => (challenge_message.flag & client.flags)
|
28
|
-
}
|
29
|
-
t3 = Net::NTLM::Message::Type3.create type3_opts
|
30
|
-
t3.extend(Message)
|
31
|
-
if negotiate_key_exchange?
|
32
|
-
t3.enable(:session_key)
|
33
|
-
rc4 = OpenSSL::Cipher.new("rc4")
|
34
|
-
rc4.encrypt
|
35
|
-
rc4.key = user_session_key
|
36
|
-
sk = rc4.update exported_session_key
|
37
|
-
sk << rc4.final
|
38
|
-
t3.session_key = sk
|
39
|
-
end
|
40
|
-
t3
|
41
|
-
end
|
42
|
-
|
43
|
-
def is_anonymous?
|
44
|
-
username == '' && password == ''
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def use_oem_strings?
|
50
|
-
# @see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832
|
51
|
-
!challenge_message.has_flag?(:UNICODE) && challenge_message.has_flag?(:OEM)
|
52
|
-
end
|
53
|
-
|
54
|
-
def ntlmv2_hash
|
55
|
-
@ntlmv2_hash ||= RubySMB::NTLM.ntlmv2_hash(username, password, domain, {:client_challenge => client_challenge, :unicode => !use_oem_strings?})
|
56
|
-
end
|
57
|
-
|
58
|
-
def calculate_user_session_key!
|
59
|
-
if is_anonymous?
|
60
|
-
# see MS-NLMP section 3.4
|
61
|
-
@user_session_key = "\x00".b * 16
|
62
|
-
else
|
63
|
-
@user_session_key = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, nt_proof_str)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def init_context(resp = nil, channel_binding = nil)
|
69
|
-
if resp.nil?
|
70
|
-
@session = nil
|
71
|
-
type1_message
|
72
|
-
else
|
73
|
-
@session = Client::Session.new(self, Net::NTLM::Message.decode64(resp), channel_binding)
|
74
|
-
@session.authenticate!
|
75
|
-
end
|
76
|
-
end
|
3
|
+
# There was a bunch of code in here that was necessary in versions up to and including rubyntlm version 0.6.3.
|
4
|
+
# The class is kept because there are references to it that should be kept in place in case future alterations to
|
5
|
+
# rubyntlm are required.
|
77
6
|
end
|
78
7
|
end
|
data/lib/ruby_smb/ntlm.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'ruby_smb/ntlm/custom/string_encoder'
|
2
|
-
|
3
1
|
module RubySMB
|
4
2
|
module NTLM
|
5
3
|
# [[MS-NLMP] 2.2.2.5](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832)
|
@@ -58,41 +56,6 @@ module RubySMB
|
|
58
56
|
"Version #{major}.#{minor} (Build #{build}); NTLM Current Revision #{ntlm_revision}"
|
59
57
|
end
|
60
58
|
end
|
61
|
-
|
62
|
-
class << self
|
63
|
-
|
64
|
-
# Generate a NTLMv2 Hash
|
65
|
-
# @param [String] user The username
|
66
|
-
# @param [String] password The password
|
67
|
-
# @param [String] target The domain or workstation to authenticate to
|
68
|
-
# @option opt :unicode (false) Unicode encode the domain
|
69
|
-
def ntlmv2_hash(user, password, target, opt={})
|
70
|
-
if Net::NTLM.is_ntlm_hash? password
|
71
|
-
decoded_password = Net::NTLM::EncodeUtil.decode_utf16le(password)
|
72
|
-
ntlmhash = [decoded_password.upcase[33,65]].pack('H32')
|
73
|
-
else
|
74
|
-
ntlmhash = Net::NTLM.ntlm_hash(password, opt)
|
75
|
-
end
|
76
|
-
|
77
|
-
if opt[:unicode]
|
78
|
-
# Uppercase operation on username containing non-ASCII characters
|
79
|
-
# after being unicode encoded with `EncodeUtil.encode_utf16le`
|
80
|
-
# doesn't play well. Upcase should be done before encoding.
|
81
|
-
user_upcase = Net::NTLM::EncodeUtil.decode_utf16le(user).upcase
|
82
|
-
user_upcase = Net::NTLM::EncodeUtil.encode_utf16le(user_upcase)
|
83
|
-
else
|
84
|
-
user_upcase = user.upcase
|
85
|
-
end
|
86
|
-
userdomain = user_upcase + target
|
87
|
-
|
88
|
-
unless opt[:unicode]
|
89
|
-
userdomain = Net::NTLM::EncodeUtil.encode_utf16le(userdomain)
|
90
|
-
end
|
91
|
-
OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain)
|
92
|
-
end
|
93
|
-
|
94
|
-
end
|
95
|
-
|
96
59
|
end
|
97
60
|
end
|
98
61
|
|
@@ -7,7 +7,7 @@ module RubySMB
|
|
7
7
|
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/b062f3e3-1b65-4a9a-854a-0ee432499d8f
|
8
8
|
response = RubySMB::SMB1::Packet::TreeConnectResponse.new
|
9
9
|
|
10
|
-
share_name =
|
10
|
+
share_name = request.data_block.path.split('\\', 4).last
|
11
11
|
share_provider = @server.shares.transform_keys(&:downcase)[share_name.downcase]
|
12
12
|
if share_provider.nil?
|
13
13
|
logger.warn("Received TREE_CONNECT request for non-existent share: #{share_name}")
|
@@ -51,7 +51,7 @@ module RubySMB
|
|
51
51
|
return response
|
52
52
|
end
|
53
53
|
|
54
|
-
share_name =
|
54
|
+
share_name = request.path.encode.split('\\', 4).last
|
55
55
|
share_provider = @server.shares.transform_keys(&:downcase)[share_name.downcase]
|
56
56
|
|
57
57
|
if share_provider.nil?
|
data/lib/ruby_smb/version.rb
CHANGED
data/lib/ruby_smb.rb
CHANGED
@@ -6,13 +6,11 @@ require 'openssl/ccm'
|
|
6
6
|
require 'openssl/cmac'
|
7
7
|
require 'windows_error'
|
8
8
|
require 'windows_error/nt_status'
|
9
|
-
require 'ruby_smb/ntlm/custom/string_encoder'
|
10
9
|
# A packet parsing and manipulation library for the SMB1 and SMB2 protocols
|
11
10
|
#
|
12
11
|
# [[MS-SMB] Server Message Block (SMB) Protocol Version 1](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
13
12
|
# [[MS-SMB2] Server Message Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
14
13
|
module RubySMB
|
15
|
-
require 'ruby_smb/utils'
|
16
14
|
require 'ruby_smb/error'
|
17
15
|
require 'ruby_smb/create_actions'
|
18
16
|
require 'ruby_smb/dispositions'
|
data/ruby_smb.gemspec
CHANGED
@@ -6,7 +6,14 @@ require 'ruby_smb/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'ruby_smb'
|
8
8
|
spec.version = RubySMB::VERSION
|
9
|
-
spec.authors = [
|
9
|
+
spec.authors = [
|
10
|
+
'Metasploit Hackers',
|
11
|
+
'David Maloney',
|
12
|
+
'James Lee',
|
13
|
+
'Dev Mohanty',
|
14
|
+
'Christophe De La Fuente',
|
15
|
+
'Spencer McIntyre'
|
16
|
+
]
|
10
17
|
spec.email = ['msfdev@metasploit.com']
|
11
18
|
spec.summary = 'A pure Ruby implementation of the SMB Protocol Family'
|
12
19
|
spec.description = ''
|
@@ -33,7 +40,7 @@ Gem::Specification.new do |spec|
|
|
33
40
|
spec.add_development_dependency 'rake'
|
34
41
|
spec.add_development_dependency 'yard'
|
35
42
|
|
36
|
-
spec.add_runtime_dependency 'rubyntlm'
|
43
|
+
spec.add_runtime_dependency 'rubyntlm', '>= 0.6.5'
|
37
44
|
spec.add_runtime_dependency 'windows_error', '>= 0.1.4'
|
38
45
|
spec.add_runtime_dependency 'bindata', '2.4.15'
|
39
46
|
spec.add_runtime_dependency 'openssl-ccm'
|
@@ -9,8 +9,11 @@ RSpec.describe RubySMB::Gss::Provider::NTLM::Authenticator do
|
|
9
9
|
msg.domain = domain
|
10
10
|
end
|
11
11
|
end
|
12
|
+
let(:type2_msg) do
|
13
|
+
Net::NTLM::Message::Type2.new
|
14
|
+
end
|
12
15
|
let(:type3_msg) do
|
13
|
-
|
16
|
+
type2_msg.response({user: username, password: password, domain: domain}, {ntlmv2: true})
|
14
17
|
end
|
15
18
|
|
16
19
|
before(:each) do
|
@@ -65,9 +68,121 @@ RSpec.describe RubySMB::Gss::Provider::NTLM::Authenticator do
|
|
65
68
|
end
|
66
69
|
|
67
70
|
describe '#process_ntlm_type3' do
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
+
context 'when the message is anonymous' do
|
72
|
+
let(:type3_msg) do
|
73
|
+
type2_msg.response({user: '', password: ''}, {ntlmv2: true})
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when anonymous access is disabled' do
|
77
|
+
before(:each) do
|
78
|
+
expect(provider).to_not receive(:allow_guests)
|
79
|
+
expect(provider).to receive(:allow_anonymous).and_return(false)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should process a NTLM type 3 message and return STATUS_LOGON_FAILURE' do
|
83
|
+
status = authenticator.process_ntlm_type3(type3_msg)
|
84
|
+
expect(status).to be_a WindowsError::ErrorCode
|
85
|
+
expect(status).to eq WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
86
|
+
end
|
87
|
+
|
88
|
+
after(:each) do
|
89
|
+
expect(authenticator.session_key).to be_nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when anonymous access is enabled' do
|
94
|
+
before(:each) do
|
95
|
+
expect(provider).to_not receive(:allow_guests)
|
96
|
+
expect(provider).to receive(:allow_anonymous).and_return(true)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should process a NTLM type 3 message and return STATUS_SUCCESS' do
|
100
|
+
status = authenticator.process_ntlm_type3(type3_msg)
|
101
|
+
expect(status).to be_a WindowsError::ErrorCode
|
102
|
+
expect(status).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
103
|
+
end
|
104
|
+
|
105
|
+
after(:each) do
|
106
|
+
expect(authenticator.session_key).to eq "\x00".b * 16
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when the message is a guest' do
|
112
|
+
let(:type3_msg) do
|
113
|
+
type2_msg.response({user: 'Spencer', password: password}, {ntlmv2: true})
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when guest access is disabled' do
|
117
|
+
before(:each) do
|
118
|
+
expect(provider).to_not receive(:allow_anonymous)
|
119
|
+
expect(provider).to receive(:allow_guests).and_return(false)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should process a NTLM type 3 message and return STATUS_LOGON_FAILURE' do
|
123
|
+
status = authenticator.process_ntlm_type3(type3_msg)
|
124
|
+
expect(status).to be_a WindowsError::ErrorCode
|
125
|
+
expect(status).to eq WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
126
|
+
end
|
127
|
+
|
128
|
+
after(:each) do
|
129
|
+
expect(authenticator.session_key).to be_nil
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'when guest access is enabled' do
|
134
|
+
before(:each) do
|
135
|
+
expect(provider).to_not receive(:allow_anonymous)
|
136
|
+
expect(provider).to receive(:allow_guests).and_return(true)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should process a NTLM type 3 message and return STATUS_SUCCESS' do
|
140
|
+
status = authenticator.process_ntlm_type3(type3_msg)
|
141
|
+
expect(status).to be_a WindowsError::ErrorCode
|
142
|
+
expect(status).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
143
|
+
end
|
144
|
+
|
145
|
+
after(:each) do
|
146
|
+
expect(authenticator.session_key).to eq "\x00".b * 16
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when the message is a known user' do
|
152
|
+
before(:each) do
|
153
|
+
authenticator.instance_variable_set(:@server_challenge, type2_msg[:challenge].serialize)
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'when the password is correct' do
|
157
|
+
it 'should process a NTLM type 3 message and return STATUS_SUCCESS' do
|
158
|
+
type3_msg.user.force_encoding('UTF-16LE')
|
159
|
+
type3_msg.domain.force_encoding('UTF-16LE')
|
160
|
+
status = authenticator.process_ntlm_type3(type3_msg)
|
161
|
+
expect(status).to be_a WindowsError::ErrorCode
|
162
|
+
expect(status).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
163
|
+
end
|
164
|
+
|
165
|
+
after(:each) do
|
166
|
+
expect(authenticator.session_key).to be_a String
|
167
|
+
expect(authenticator.session_key.length).to eq 16
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'when the password is wrong' do
|
172
|
+
let(:type3_msg) do
|
173
|
+
type2_msg.response({user: username, password: 'Wrong' + password, domain: domain}, {ntlmv2: true})
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'should process a NTLM type 3 message and return STATUS_LOGON_FAILURE' do
|
177
|
+
status = authenticator.process_ntlm_type3(type3_msg)
|
178
|
+
expect(status).to be_a WindowsError::ErrorCode
|
179
|
+
expect(status).to eq WindowsError::NTStatus::STATUS_LOGON_FAILURE
|
180
|
+
end
|
181
|
+
|
182
|
+
after(:each) do
|
183
|
+
expect(authenticator.session_key).to be nil
|
184
|
+
end
|
185
|
+
end
|
71
186
|
end
|
72
187
|
end
|
73
188
|
|
@@ -24,7 +24,7 @@ RSpec.describe RubySMB::NTLM::Client::Session do
|
|
24
24
|
|
25
25
|
it 'returns a Type3 message' do
|
26
26
|
expect(session.authenticate!).to be_a Net::NTLM::Message::Type3
|
27
|
-
expect(session.authenticate!).to be_a
|
27
|
+
expect(session.authenticate!).to be_a Net::NTLM::Message
|
28
28
|
end
|
29
29
|
|
30
30
|
context 'when it is anonymous' do
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_smb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Metasploit Hackers
|
@@ -9,6 +9,7 @@ authors:
|
|
9
9
|
- James Lee
|
10
10
|
- Dev Mohanty
|
11
11
|
- Christophe De La Fuente
|
12
|
+
- Spencer McIntyre
|
12
13
|
autorequire:
|
13
14
|
bindir: bin
|
14
15
|
cert_chain:
|
@@ -38,7 +39,7 @@ cert_chain:
|
|
38
39
|
DgscAao7wB3xW2BWEp1KnaDWkf1x9ttgoBEYyuYwU7uatB67kBQG1PKvLt79wHvz
|
39
40
|
Dxs+KOjGbBRfMnPgVGYkORKVrZIwlaboHbDKxcVW5xv+oZc7KYXWGg==
|
40
41
|
-----END CERTIFICATE-----
|
41
|
-
date: 2024-
|
42
|
+
date: 2024-11-22 00:00:00.000000000 Z
|
42
43
|
dependencies:
|
43
44
|
- !ruby/object:Gem::Dependency
|
44
45
|
name: redcarpet
|
@@ -116,14 +117,14 @@ dependencies:
|
|
116
117
|
requirements:
|
117
118
|
- - ">="
|
118
119
|
- !ruby/object:Gem::Version
|
119
|
-
version:
|
120
|
+
version: 0.6.5
|
120
121
|
type: :runtime
|
121
122
|
prerelease: false
|
122
123
|
version_requirements: !ruby/object:Gem::Requirement
|
123
124
|
requirements:
|
124
125
|
- - ">="
|
125
126
|
- !ruby/object:Gem::Version
|
126
|
-
version:
|
127
|
+
version: 0.6.5
|
127
128
|
- !ruby/object:Gem::Dependency
|
128
129
|
name: windows_error
|
129
130
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,6 +188,7 @@ executables: []
|
|
187
188
|
extensions: []
|
188
189
|
extra_rdoc_files: []
|
189
190
|
files:
|
191
|
+
- ".github/workflows/metasploit-framework_acceptance.yml"
|
190
192
|
- ".github/workflows/verify.yml"
|
191
193
|
- ".gitignore"
|
192
194
|
- ".rspec"
|
@@ -342,12 +344,16 @@ files:
|
|
342
344
|
- lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb
|
343
345
|
- lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_request.rb
|
344
346
|
- lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_response.rb
|
347
|
+
- lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_request.rb
|
348
|
+
- lib/ruby_smb/dcerpc/samr/samr_get_members_in_group_response.rb
|
345
349
|
- lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request.rb
|
346
350
|
- lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response.rb
|
347
351
|
- lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request.rb
|
348
352
|
- lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response.rb
|
349
353
|
- lib/ruby_smb/dcerpc/samr/samr_open_domain_request.rb
|
350
354
|
- lib/ruby_smb/dcerpc/samr/samr_open_domain_response.rb
|
355
|
+
- lib/ruby_smb/dcerpc/samr/samr_open_group_request.rb
|
356
|
+
- lib/ruby_smb/dcerpc/samr/samr_open_group_response.rb
|
351
357
|
- lib/ruby_smb/dcerpc/samr/samr_open_user_request.rb
|
352
358
|
- lib/ruby_smb/dcerpc/samr/samr_open_user_response.rb
|
353
359
|
- lib/ruby_smb/dcerpc/samr/samr_query_information_domain_request.rb
|
@@ -473,7 +479,6 @@ files:
|
|
473
479
|
- lib/ruby_smb/nbss/session_request.rb
|
474
480
|
- lib/ruby_smb/ntlm.rb
|
475
481
|
- lib/ruby_smb/ntlm/client.rb
|
476
|
-
- lib/ruby_smb/ntlm/custom/string_encoder.rb
|
477
482
|
- lib/ruby_smb/peer_info.rb
|
478
483
|
- lib/ruby_smb/server.rb
|
479
484
|
- lib/ruby_smb/server/cli.rb
|
@@ -654,7 +659,6 @@ files:
|
|
654
659
|
- lib/ruby_smb/smb2/smb2_header.rb
|
655
660
|
- lib/ruby_smb/smb2/tree.rb
|
656
661
|
- lib/ruby_smb/smb_error.rb
|
657
|
-
- lib/ruby_smb/utils.rb
|
658
662
|
- lib/ruby_smb/version.rb
|
659
663
|
- ruby_smb.gemspec
|
660
664
|
- spec/lib/ruby_smb/client_spec.rb
|
@@ -996,7 +1000,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
996
1000
|
- !ruby/object:Gem::Version
|
997
1001
|
version: '0'
|
998
1002
|
requirements: []
|
999
|
-
rubygems_version: 3.
|
1003
|
+
rubygems_version: 3.5.22
|
1000
1004
|
signing_key:
|
1001
1005
|
specification_version: 4
|
1002
1006
|
summary: A pure Ruby implementation of the SMB Protocol Family
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'net/ntlm'
|
2
|
-
|
3
|
-
module RubySMB
|
4
|
-
module NTLM
|
5
|
-
module Custom
|
6
|
-
module StringEncoder
|
7
|
-
|
8
|
-
def self.prepended(base)
|
9
|
-
base.singleton_class.send(:prepend, ClassMethods)
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def encode_utf16le(str)
|
14
|
-
str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('ASCII-8BIT')
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
Net::NTLM::EncodeUtil.send(:prepend, RubySMB::NTLM::Custom::StringEncoder)
|
data/lib/ruby_smb/utils.rb
DELETED