ruby_smb 2.0.1 → 2.0.6
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.tar.gz.sig +2 -1
- data/examples/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/enum_registry_key.rb +5 -4
- data/examples/enum_registry_values.rb +5 -4
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +11 -12
- data/examples/query_service_status.rb +64 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_registry_key_value.rb +6 -5
- data/examples/rename_file.rb +9 -7
- data/examples/tree_connect.rb +7 -5
- data/examples/write_file.rb +9 -7
- data/lib/ruby_smb/client.rb +81 -48
- data/lib/ruby_smb/client/authentication.rb +5 -10
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/negotiation.rb +21 -14
- data/lib/ruby_smb/client/tree_connect.rb +2 -4
- data/lib/ruby_smb/client/utils.rb +16 -10
- data/lib/ruby_smb/client/winreg.rb +1 -1
- data/lib/ruby_smb/dcerpc.rb +4 -0
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +306 -44
- data/lib/ruby_smb/dcerpc/netlogon.rb +101 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +28 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/request.rb +19 -0
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
- data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
- data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
- data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +1 -1
- data/lib/ruby_smb/error.rb +21 -5
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/generic_packet.rb +11 -1
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/smb1/file.rb +10 -25
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
- data/lib/ruby_smb/smb1/pipe.rb +8 -6
- data/lib/ruby_smb/smb1/tree.rb +13 -9
- data/lib/ruby_smb/smb2/file.rb +33 -33
- data/lib/ruby_smb/smb2/pipe.rb +9 -6
- data/lib/ruby_smb/smb2/tree.rb +21 -11
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +195 -101
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
- data/spec/lib/ruby_smb/error_spec.rb +34 -5
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
- metadata +91 -2
- metadata.gz.sig +0 -0
@@ -6,7 +6,7 @@ module RubySMB
|
|
6
6
|
share = "\\\\#{host}\\IPC$"
|
7
7
|
tree = @tree_connects.find {|tree| tree.share == share}
|
8
8
|
tree = tree_connect(share) unless tree
|
9
|
-
named_pipe = tree.
|
9
|
+
named_pipe = tree.open_pipe(filename: "winreg", write: true, read: true)
|
10
10
|
if block_given?
|
11
11
|
res = yield named_pipe
|
12
12
|
named_pipe.close
|
data/lib/ruby_smb/dcerpc.rb
CHANGED
@@ -10,15 +10,19 @@ module RubySMB
|
|
10
10
|
require 'ruby_smb/dcerpc/ptypes'
|
11
11
|
require 'ruby_smb/dcerpc/p_syntax_id_t'
|
12
12
|
require 'ruby_smb/dcerpc/rrp_unicode_string'
|
13
|
+
require 'ruby_smb/dcerpc/rpc_security_attributes'
|
13
14
|
require 'ruby_smb/dcerpc/pdu_header'
|
14
15
|
require 'ruby_smb/dcerpc/srvsvc'
|
16
|
+
require 'ruby_smb/dcerpc/svcctl'
|
15
17
|
require 'ruby_smb/dcerpc/winreg'
|
18
|
+
require 'ruby_smb/dcerpc/netlogon'
|
16
19
|
require 'ruby_smb/dcerpc/request'
|
17
20
|
require 'ruby_smb/dcerpc/response'
|
18
21
|
require 'ruby_smb/dcerpc/bind'
|
19
22
|
require 'ruby_smb/dcerpc/bind_ack'
|
20
23
|
|
21
24
|
|
25
|
+
|
22
26
|
# Bind to the remote server interface endpoint.
|
23
27
|
#
|
24
28
|
# @param options [Hash] the options to pass to the Bind request packet. At least, :endpoint must but provided with an existing Dcerpc class
|
data/lib/ruby_smb/dcerpc/ndr.rb
CHANGED
@@ -7,64 +7,185 @@ module RubySMB
|
|
7
7
|
VER_MAJOR = 2
|
8
8
|
VER_MINOR = 0
|
9
9
|
|
10
|
-
# An NDR
|
11
|
-
# [Transfer Syntax NDR -
|
12
|
-
|
13
|
-
|
10
|
+
# An NDR Enum type as defined in
|
11
|
+
# [Transfer Syntax NDR - Enumerated Types](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_02_05_01)
|
12
|
+
class NdrEnum < BinData::Int16le; end
|
13
|
+
|
14
|
+
# An NDR Conformant and Varying String representation as defined in
|
15
|
+
# [Transfer Syntax NDR - Conformant and Varying Strings](http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_04_02)
|
16
|
+
# The string elements are Stringz16 (unicode)
|
17
|
+
class NdrString < BinData::Primitive
|
14
18
|
endian :little
|
15
19
|
|
16
|
-
uint32
|
20
|
+
uint32 :max_count
|
21
|
+
uint32 :offset, initial_value: 0
|
22
|
+
uint32 :actual_count
|
23
|
+
stringz16 :str, max_length: -> { actual_count * 2 }, onlyif: -> { actual_count > 0 }
|
17
24
|
|
18
25
|
def get
|
19
|
-
|
26
|
+
self.actual_count == 0 ? 0 : self.str
|
20
27
|
end
|
21
28
|
|
22
29
|
def set(v)
|
23
|
-
if v
|
24
|
-
self.
|
30
|
+
if v == 0
|
31
|
+
self.str.clear
|
32
|
+
self.actual_count = 0
|
25
33
|
else
|
26
|
-
|
34
|
+
v = v.str if v.is_a?(self.class)
|
35
|
+
unless self.str.equal?(v)
|
36
|
+
if v.empty?
|
37
|
+
self.actual_count = 0
|
38
|
+
else
|
39
|
+
self.actual_count = v.to_s.size + 1
|
40
|
+
self.max_count = self.actual_count
|
41
|
+
end
|
42
|
+
end
|
43
|
+
self.str = v.to_s
|
27
44
|
end
|
28
45
|
end
|
29
46
|
|
30
|
-
def
|
31
|
-
|
47
|
+
def clear
|
48
|
+
# Make sure #max_count and #offset are not cleared out
|
49
|
+
self.str.clear
|
50
|
+
self.actual_count.clear
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
self.str.to_s
|
32
55
|
end
|
33
56
|
end
|
34
57
|
|
35
|
-
# An NDR Conformant
|
36
|
-
# [Transfer Syntax NDR - Conformant
|
37
|
-
|
38
|
-
class NdrString < BinData::Primitive
|
58
|
+
# An NDR Uni-dimensional Conformant Array of Bytes representation as defined in
|
59
|
+
# [Transfer Syntax NDR - Uni-dimensional Conformant Arrays](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_02)
|
60
|
+
class NdrLpByte < BinData::Primitive
|
39
61
|
endian :little
|
40
62
|
|
41
|
-
uint32
|
42
|
-
|
43
|
-
uint32 :actual_count
|
44
|
-
stringz16 :str, read_length: -> { actual_count }, onlyif: -> { actual_count > 0 }
|
63
|
+
uint32 :max_count, initial_value: -> { self.elements.size }
|
64
|
+
array :elements, type: :uint8, read_until: -> { index == self.max_count - 1 }, onlyif: -> { self.max_count > 0 }
|
45
65
|
|
46
66
|
def get
|
47
|
-
self.
|
67
|
+
self.elements
|
48
68
|
end
|
49
69
|
|
50
70
|
def set(v)
|
51
|
-
if v.is_a?(
|
52
|
-
|
53
|
-
|
54
|
-
self.str = v
|
55
|
-
self.max_count = self.actual_count = str.to_binary_s.size / 2
|
56
|
-
end
|
71
|
+
v = v.elements if v.is_a?(self.class)
|
72
|
+
self.elements = v.to_ary
|
73
|
+
self.max_count = self.elements.size unless self.elements.equal?(v)
|
57
74
|
end
|
58
75
|
end
|
59
76
|
|
60
|
-
#
|
61
|
-
|
77
|
+
# An NDR Uni-dimensional Conformant-varying Arrays of bytes representation as defined in:
|
78
|
+
# [Transfer Syntax NDR - NDR Constructed Types](http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_04)
|
79
|
+
class NdrByteArray < BinData::Primitive
|
62
80
|
endian :little
|
63
81
|
|
64
|
-
|
82
|
+
uint32 :max_count, initial_value: -> { self.actual_count }
|
83
|
+
uint32 :offset, initial_value: 0
|
84
|
+
uint32 :actual_count, initial_value: -> { self.bytes.size }
|
85
|
+
array :bytes, :type => :uint8, initial_length: -> { self.actual_count }
|
65
86
|
|
66
|
-
def
|
67
|
-
|
87
|
+
def get
|
88
|
+
self.bytes
|
89
|
+
end
|
90
|
+
|
91
|
+
def set(v)
|
92
|
+
v = v.bytes if v.is_a?(self.class)
|
93
|
+
self.bytes = v.to_ary
|
94
|
+
self.max_count = self.bytes.size unless self.bytes.equal?(v)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# An NDR Uni-dimensional Fixed Array of bytes representation as defined in:
|
99
|
+
# [Transfer Syntax NDR - NDR Constructed Types](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_03_01)
|
100
|
+
class NdrFixedByteArray < BinData::BasePrimitive
|
101
|
+
optional_parameters :read_length, :length, :pad_byte, :pad_front
|
102
|
+
default_parameters pad_byte: 0
|
103
|
+
mutually_exclusive_parameters :length, :value
|
104
|
+
|
105
|
+
def initialize_shared_instance
|
106
|
+
if (has_parameter?(:value) || has_parameter?(:asserted_value)) && !has_parameter?(:read_length)
|
107
|
+
extend WarnNoReadLengthPlugin
|
108
|
+
end
|
109
|
+
super
|
110
|
+
end
|
111
|
+
|
112
|
+
def assign(val)
|
113
|
+
super(fixed_byte_array(val))
|
114
|
+
end
|
115
|
+
|
116
|
+
def snapshot
|
117
|
+
clamp_to_length(super)
|
118
|
+
end
|
119
|
+
|
120
|
+
class << self
|
121
|
+
def arg_processor
|
122
|
+
NdrFixedByteArrayArgProcessor.new
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def clamp_to_length(val)
|
129
|
+
val = fixed_byte_array(val)
|
130
|
+
len = eval_parameter(:length) || val.length
|
131
|
+
if val.length > len
|
132
|
+
val = val.first(len)
|
133
|
+
elsif val.length < len
|
134
|
+
pad = eval_parameter(:pad_byte)
|
135
|
+
if get_parameter(:pad_front)
|
136
|
+
val = val.insert(0, *Array.new(len - val.length, pad))
|
137
|
+
else
|
138
|
+
val = val.fill(pad, val.length...len)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
val
|
143
|
+
end
|
144
|
+
|
145
|
+
def fixed_byte_array(val)
|
146
|
+
val = val.bytes if val.is_a? String
|
147
|
+
val.to_ary
|
148
|
+
end
|
149
|
+
|
150
|
+
def read_and_return_value(io)
|
151
|
+
len = eval_parameter(:read_length) || eval_parameter(:length) || 0
|
152
|
+
io.readbytes(len)
|
153
|
+
end
|
154
|
+
|
155
|
+
def sensible_default
|
156
|
+
[ ]
|
157
|
+
end
|
158
|
+
|
159
|
+
def value_to_binary_string(val)
|
160
|
+
clamp_to_length(val).pack('C*')
|
161
|
+
end
|
162
|
+
|
163
|
+
class NdrFixedByteArrayArgProcessor < BinData::BaseArgProcessor
|
164
|
+
def sanitize_parameters!(obj_class, obj_params)
|
165
|
+
obj_params.must_be_integer(:length, :pad_byte)
|
166
|
+
obj_params.sanitize(:pad_byte) { |byte| sanitized_pad_byte(byte) }
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def sanitized_pad_byte(byte)
|
172
|
+
if byte.is_a?(String)
|
173
|
+
raise ArgumentError, ':pad_byte must not contain more than 1 byte' if byte.bytesize > 1
|
174
|
+
|
175
|
+
byte = byte.ord
|
176
|
+
end
|
177
|
+
raise ArgumentError, ':pad_byte must be within the range of 0 - 255' unless ((byte >= 0) && (byte <= 255))
|
178
|
+
|
179
|
+
byte
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Warns when reading if :value && no :read_length
|
184
|
+
module WarnNoReadLengthPlugin
|
185
|
+
def read_and_return_value(io)
|
186
|
+
warn "#{debug_name} does not have a :read_length parameter - returning empty array"
|
187
|
+
""
|
188
|
+
end
|
68
189
|
end
|
69
190
|
end
|
70
191
|
|
@@ -72,6 +193,7 @@ module RubySMB
|
|
72
193
|
# [IDL Data Type Declarations - Basic Type Declarations](http://pubs.opengroup.org/onlinepubs/9629399/apdxn.htm#tagcjh_34_01)
|
73
194
|
class NdrContextHandle < BinData::Primitive
|
74
195
|
endian :little
|
196
|
+
|
75
197
|
uint32 :context_handle_attributes
|
76
198
|
uuid :context_handle_uuid
|
77
199
|
|
@@ -91,30 +213,170 @@ module RubySMB
|
|
91
213
|
end
|
92
214
|
end
|
93
215
|
|
94
|
-
#
|
95
|
-
|
216
|
+
# An NDR Top-level Full Pointers representation as defined in
|
217
|
+
# [Transfer Syntax NDR - Top-level Full Pointers](http://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_11_01)
|
218
|
+
# This class must be inherited and the subclass must have a #referent property
|
219
|
+
class NdrPointer < BinData::Primitive
|
96
220
|
endian :little
|
97
221
|
|
98
|
-
uint32 :
|
222
|
+
uint32 :referent_id, initial_value: 0
|
223
|
+
|
224
|
+
def do_read(io)
|
225
|
+
self.referent_id.do_read(io)
|
226
|
+
if process_referent?
|
227
|
+
self.referent.do_read(io) unless self.referent_id == 0
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def do_write(io)
|
232
|
+
self.referent_id.do_write(io)
|
233
|
+
if process_referent?
|
234
|
+
self.referent.do_write(io) unless self.referent_id == 0
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def set(v)
|
239
|
+
if v == :null
|
240
|
+
self.referent.clear
|
241
|
+
self.referent_id = 0
|
242
|
+
else
|
243
|
+
if self.referent.respond_to?(:set)
|
244
|
+
self.referent.set(v)
|
245
|
+
else
|
246
|
+
self.referent = v
|
247
|
+
end
|
248
|
+
self.referent_id = rand(0xFFFFFFFF) if self.referent_id == 0
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def get
|
253
|
+
if self.referent_id == 0
|
254
|
+
:null
|
255
|
+
else
|
256
|
+
self.referent
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def process_referent?
|
261
|
+
current_parent = parent
|
262
|
+
loop do
|
263
|
+
return true unless current_parent
|
264
|
+
return false if current_parent.is_a?(NdrStruct)
|
265
|
+
current_parent = current_parent.parent
|
266
|
+
end
|
267
|
+
end
|
99
268
|
end
|
100
269
|
|
101
|
-
#
|
102
|
-
|
103
|
-
class NdrLpByte < BinData::Record
|
270
|
+
# A pointer to a NdrString structure
|
271
|
+
class NdrLpStr < NdrPointer
|
104
272
|
endian :little
|
105
273
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
274
|
+
ndr_string :referent, onlyif: -> { self.referent_id != 0 }
|
275
|
+
end
|
276
|
+
|
277
|
+
class NdrLpDword < NdrPointer
|
278
|
+
endian :little
|
279
|
+
|
280
|
+
uint32 :referent, onlyif: -> { self.referent_id != 0 }
|
281
|
+
end
|
282
|
+
|
283
|
+
# A pointer to an NDR Uni-dimensional Conformant-varying Arrays of bytes
|
284
|
+
class NdrLpByteArray < NdrPointer
|
285
|
+
endian :little
|
286
|
+
|
287
|
+
ndr_byte_array :referent, onlyif: -> { self.referent_id != 0 }
|
288
|
+
|
289
|
+
def set(v)
|
290
|
+
if v != :null && v.is_a?(NdrLpByteArray)
|
291
|
+
super(v.referent)
|
292
|
+
else
|
293
|
+
super(v)
|
294
|
+
end
|
295
|
+
end
|
111
296
|
end
|
112
297
|
|
113
298
|
# A pointer to a Windows FILETIME structure
|
114
|
-
class NdrLpFileTime <
|
299
|
+
class NdrLpFileTime < NdrPointer
|
300
|
+
endian :little
|
301
|
+
|
302
|
+
file_time :referent, onlyif: -> { self.referent_id != 0 }
|
303
|
+
end
|
304
|
+
|
305
|
+
# A generic NDR structure that implements logic to #read and #write
|
306
|
+
# (#to_binary_s) in case the structure contains BinData::Array or
|
307
|
+
# NdrPointer fields. This class must be inherited.
|
308
|
+
class NdrStruct < BinData::Record
|
309
|
+
|
310
|
+
def do_read(io)
|
311
|
+
super(io)
|
312
|
+
each_pair do |_name, field|
|
313
|
+
case field
|
314
|
+
when BinData::Array
|
315
|
+
field.each do |element|
|
316
|
+
next unless element.is_a?(NdrPointer)
|
317
|
+
next if element.referent_id == 0
|
318
|
+
pad = (4 - io.offset % 4) % 4
|
319
|
+
io.seekbytes(pad) if pad > 0
|
320
|
+
element.referent.do_read(io)
|
321
|
+
end
|
322
|
+
when NdrPointer
|
323
|
+
next if field.referent_id == 0
|
324
|
+
pad = (4 - io.offset % 4) % 4
|
325
|
+
io.seekbytes(pad) if pad > 0
|
326
|
+
field.referent.do_read(io)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def do_write(io)
|
332
|
+
super(io)
|
333
|
+
each_pair do |_name, field|
|
334
|
+
case field
|
335
|
+
when BinData::Array
|
336
|
+
field.each do |element|
|
337
|
+
next unless element.is_a?(NdrPointer)
|
338
|
+
next if element.referent_id == 0
|
339
|
+
pad = (4 - io.offset % 4) % 4
|
340
|
+
io.writebytes("\x00" * pad + element.referent.to_binary_s)
|
341
|
+
end
|
342
|
+
when NdrPointer
|
343
|
+
next if field.referent_id == 0
|
344
|
+
pad = (4 - io.offset % 4) % 4
|
345
|
+
io.writebytes("\x00" * pad + field.referent.to_binary_s)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
class NdrStringPtrsw < NdrStruct
|
352
|
+
endian :little
|
353
|
+
|
354
|
+
uint32 :max_count, initial_value: -> { self.elements.size }
|
355
|
+
array :elements, type: :ndr_lp_str, read_until: -> { index == self.max_count - 1 }, onlyif: -> { self.max_count > 0 }
|
356
|
+
|
357
|
+
def get
|
358
|
+
self.elements
|
359
|
+
end
|
360
|
+
|
361
|
+
def set(v)
|
362
|
+
v = v.elements if v.is_a?(self.class)
|
363
|
+
self.elements = v.to_ary
|
364
|
+
self.max_count = self.elements.size unless self.elements.equal?(v)
|
365
|
+
end
|
366
|
+
|
367
|
+
def do_num_bytes
|
368
|
+
to_binary_s.size
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class NdrLpStringPtrsw < NdrPointer
|
115
373
|
endian :little
|
116
374
|
|
117
|
-
|
375
|
+
ndr_string_ptrsw :referent, onlyif: -> { self.referent_id != 0 }
|
376
|
+
|
377
|
+
def set(v)
|
378
|
+
super(v.respond_to?(:to_ary) ? v.to_ary : v)
|
379
|
+
end
|
118
380
|
end
|
119
381
|
end
|
120
382
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Netlogon
|
4
|
+
|
5
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/592edbc8-f6f1-40c0-9ab3-fe6725ac6d7e
|
6
|
+
UUID = '12345678-1234-abcd-ef00-01234567cffb'
|
7
|
+
VER_MAJOR = 1
|
8
|
+
VER_MINOR = 0
|
9
|
+
|
10
|
+
# Operation numbers
|
11
|
+
NETR_SERVER_REQ_CHALLENGE = 4
|
12
|
+
NETR_SERVER_AUTHENTICATE3 = 26
|
13
|
+
NETR_SERVER_PASSWORD_SET2 = 30
|
14
|
+
|
15
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/3b224201-b531-43e2-8c79-b61f6dea8640
|
16
|
+
class LogonsrvHandle < Ndr::NdrLpStr; end
|
17
|
+
|
18
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/d55e2632-7163-4f6c-b662-4b870e8cc1cd
|
19
|
+
class NetlogonCredential < Ndr::NdrFixedByteArray
|
20
|
+
default_parameters length: 8
|
21
|
+
end
|
22
|
+
|
23
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/76c93227-942a-4687-ab9d-9d972ffabdab
|
24
|
+
class NetlogonAuthenticator < BinData::Record
|
25
|
+
endian :little
|
26
|
+
|
27
|
+
netlogon_credential :credential
|
28
|
+
uint32 :timestamp
|
29
|
+
end
|
30
|
+
|
31
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/4d1235e3-2c96-4e9f-a147-3cb338a0d09f
|
32
|
+
class NetlogonSecureChannelType < Ndr::NdrEnum
|
33
|
+
# enum example from dmendel/bindata#38 https://github.com/dmendel/bindata/issues/38#issuecomment-46397163
|
34
|
+
ALL = {
|
35
|
+
0 => :NullSecureChannel,
|
36
|
+
1 => :MsvApSecureChannel,
|
37
|
+
2 => :WorkstationSecureChannel,
|
38
|
+
3 => :TrustedDnsDomainSecureChannel,
|
39
|
+
4 => :TrustedDomainSecureChannel,
|
40
|
+
5 => :UasServerSecureChannel,
|
41
|
+
6 => :ServerSecureChannel,
|
42
|
+
7 => :CdcServerSecureChannel
|
43
|
+
}
|
44
|
+
ALL.each_pair { |val,sym| const_set(sym.to_s.gsub(/([a-z])([A-Z])/, '\1_\2').upcase, val) }
|
45
|
+
default_parameter assert: -> { ALL.keys.include? value }
|
46
|
+
|
47
|
+
def as_enum
|
48
|
+
ALL[value]
|
49
|
+
end
|
50
|
+
|
51
|
+
def assign(val)
|
52
|
+
if val.is_a? Symbol
|
53
|
+
val = ALL.key(val)
|
54
|
+
raise ArgumentError, 'invalid value name' if val.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
require 'ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request'
|
62
|
+
require 'ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response'
|
63
|
+
require 'ruby_smb/dcerpc/netlogon/netr_server_password_set2_request'
|
64
|
+
require 'ruby_smb/dcerpc/netlogon/netr_server_password_set2_response'
|
65
|
+
require 'ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request'
|
66
|
+
require 'ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response'
|
67
|
+
|
68
|
+
# Calculate the netlogon session key from the provided shared secret and
|
69
|
+
# challenges. The shared secret is an NTLM hash.
|
70
|
+
#
|
71
|
+
# @param shared_secret [String] the share secret between the client and the server
|
72
|
+
# @param client_challenge [String] the client challenge portion of the negotiation
|
73
|
+
# @param server_challenge [String] the server challenge portion of the negotiation
|
74
|
+
# @return [String] the session key for encryption
|
75
|
+
def self.calculate_session_key(shared_secret, client_challenge, server_challenge)
|
76
|
+
client_challenge = client_challenge.to_binary_s if client_challenge.is_a? NetlogonCredential
|
77
|
+
server_challenge = server_challenge.to_binary_s if server_challenge.is_a? NetlogonCredential
|
78
|
+
|
79
|
+
hmac = OpenSSL::HMAC.new(shared_secret, OpenSSL::Digest::SHA256.new)
|
80
|
+
hmac << client_challenge
|
81
|
+
hmac << server_challenge
|
82
|
+
hmac.digest.first(16)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Encrypt the input data using the specified session key. This is used for
|
86
|
+
# certain Netlogon service operations including the authentication
|
87
|
+
# process. Per the specification, this uses AES-128-CFB8 with an all zero
|
88
|
+
# initialization vector.
|
89
|
+
#
|
90
|
+
# @param session_key [String] the session key to use for encryption (must be 16 bytes long)
|
91
|
+
# @param input_data [String] the data to encrypt
|
92
|
+
# @return [String] the encrypted data
|
93
|
+
def self.encrypt_credential(session_key, input_data)
|
94
|
+
cipher = OpenSSL::Cipher.new('AES-128-CFB8').encrypt
|
95
|
+
cipher.iv = "\x00" * 16
|
96
|
+
cipher.key = session_key
|
97
|
+
cipher.update(input_data) + cipher.final
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|