ruby_smb 3.3.10 → 3.3.11
Sign up to get free protection for your applications and to get access to all the features.
- 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 +71 -1
- 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: 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
|
@@ -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
|
@@ -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.11
|
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-15 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