ruby_smb 1.0.0 → 1.1.0
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/.travis.yml +4 -1
- data/README.md +35 -47
- data/examples/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/pipes.rb +2 -1
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb/client/authentication.rb +43 -25
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/negotiation.rb +27 -12
- data/lib/ruby_smb/client/tree_connect.rb +20 -14
- data/lib/ruby_smb/client/utils.rb +2 -2
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/client.rb +28 -4
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- data/lib/ruby_smb/dispatcher/socket.rb +3 -1
- data/lib/ruby_smb/error.rb +40 -1
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/file.rb +67 -11
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +86 -5
- data/lib/ruby_smb/smb1/tree.rb +40 -2
- data/lib/ruby_smb/smb2/file.rb +97 -1
- data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +98 -11
- data/lib/ruby_smb/smb2/tree.rb +44 -6
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +0 -1
- data/ruby_smb.gemspec +3 -3
- data/spec/lib/ruby_smb/client_spec.rb +271 -11
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +3 -1
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +78 -0
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +322 -145
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
- data.tar.gz.sig +0 -0
- metadata +70 -11
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3fe1b1b7bdd2516bd388f86c020a9fa99b70faa0
|
|
4
|
+
data.tar.gz: aa11ed030f543c0d83b61929d10c35eea20a8455
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 92cc9708588a610104f8bacc8430fedd537f2ba283bb323b791ff45005a43417cf9570ce63f658b7a38c566570c2b651adb17b6750b3b117279552efaf138cab
|
|
7
|
+
data.tar.gz: 071db1651283d080b2adc728cd1f2225e051d52f86608f9f54dd6d79d39330127c3b5179d143ec9e5e155d132af1e128c4c9ca42744264caec8b249e0b0c86ec
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
[](https://codeclimate.com/github/rapid7/ruby_smb)
|
|
5
5
|
[](https://coveralls.io/github/rapid7/ruby_smb?branch=master)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
This is a native Ruby implementation of the SMB Protocol Family. It currently supports:
|
|
8
|
+
|
|
8
9
|
1. [[MS-SMB]](https://msdn.microsoft.com/en-us/library/cc246231.aspx)
|
|
9
10
|
1. [[MS-SMB2]](http://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
The RubySMB library provides client-level and packet-level support for the protocol. A user can parse and manipulate raw SMB packets, or use the client to perform higher-level SMB operations.
|
|
12
13
|
|
|
13
14
|
See the Wiki for more information on this project's long-term goals, style guide, and developer tips.
|
|
14
15
|
|
|
@@ -32,22 +33,17 @@ Or install it yourself as:
|
|
|
32
33
|
|
|
33
34
|
### Defining a packet
|
|
34
35
|
|
|
35
|
-
All packets are implemented in a declarative style with BinData. Nested data
|
|
36
|
-
structures are used where appropriate to give users an easy method of adjusting
|
|
37
|
-
data.
|
|
36
|
+
All packets are implemented in a declarative style with BinData. Nested data structures are used where appropriate to give users an easy method of manipulating individual fields inside of a packet.
|
|
38
37
|
|
|
39
38
|
#### SMB1
|
|
39
|
+
|
|
40
40
|
SMB1 Packets are made up of three basic components:
|
|
41
|
+
|
|
41
42
|
1. **The SMB Header** - This is a standard SMB Header. All SMB1 packets use the same SMB header.
|
|
42
|
-
1. **The Parameter Block** - This is where function parameters are passed across the wire in the packet. Parameter
|
|
43
|
-
have a '
|
|
44
|
-
1. **The Data Block** - This is the data section of the packet. the Data Block will always have a 'byte count' field that gives the size of
|
|
45
|
-
the Data block in bytes.
|
|
43
|
+
1. **The Parameter Block** - This is where function parameters are passed across the wire in the packet. Parameter blocks will always have a 'Word Count' field that gives the size of the parameter block in words (2-bytes)
|
|
44
|
+
1. **The Data Block** - This is the data section of the packet. The data block will always have a 'byte count' field that gives the size of the Data block in bytes.
|
|
46
45
|
|
|
47
|
-
The SMB Header can always just be declared as a field in the BinData DSL for the packet class, because its structure never changes.
|
|
48
|
-
For the ParameterBlock and DataBlocks, we always define subclasses for this particular packet. They inherit the 'Word Count' and
|
|
49
|
-
'Byte Count' fields, along with the auto-calculation routines for those fields, from their ancestors. Any other fields are then
|
|
50
|
-
defined in our subclass before we start the DSL declarations for the packet.
|
|
46
|
+
The SMB Header can always just be declared as a field in the BinData DSL for the packet class, because its structure never changes. For the Parameter block and data blocks, we always define subclasses for this particular packet. They inherit the 'Word Count' and 'Byte Count' fields, along with the auto-calculation routines for those fields, from their ancestors. Any other fields are then defined in our subclass before we start the DSL declarations for the packet.
|
|
51
47
|
|
|
52
48
|
Example:
|
|
53
49
|
|
|
@@ -90,8 +86,7 @@ end
|
|
|
90
86
|
|
|
91
87
|
#### SMB2
|
|
92
88
|
|
|
93
|
-
SMB2 Packets are far simpler than their older SMB1 counterparts. We still abstract out the SMB2 header since it is the same
|
|
94
|
-
structure used for every packet. Beyond that, the SMB2 packet is relatively flat in comparison to SMB1.
|
|
89
|
+
SMB2 Packets are far simpler than their older SMB1 counterparts. We still abstract out the SMB2 header since it is the same structure used for every packet. Beyond that, the SMB2 packet is relatively flat in comparison to SMB1.
|
|
95
90
|
|
|
96
91
|
Example:
|
|
97
92
|
```ruby
|
|
@@ -127,8 +122,7 @@ end
|
|
|
127
122
|
### Using a Packet class
|
|
128
123
|
|
|
129
124
|
#### Manually
|
|
130
|
-
You can
|
|
131
|
-
values in a fairly straightforward manner.
|
|
125
|
+
You can create an instance of any particular packet class, and then reach into the data structure to set or read explicit values in a fairly straightforward manner.
|
|
132
126
|
|
|
133
127
|
Example:
|
|
134
128
|
```ruby
|
|
@@ -152,8 +146,7 @@ Example:
|
|
|
152
146
|
2.3.3 :009 >
|
|
153
147
|
```
|
|
154
148
|
|
|
155
|
-
You can also pass field/value pairs into the packet constructor as arguments,
|
|
156
|
-
if you wish.
|
|
149
|
+
You can also pass field/value pairs into the packet constructor as arguments, defaulting individual fields as desired.
|
|
157
150
|
|
|
158
151
|
Example:
|
|
159
152
|
```ruby
|
|
@@ -165,9 +158,7 @@ Example:
|
|
|
165
158
|
|
|
166
159
|
#### Reading from a Binary Blob
|
|
167
160
|
|
|
168
|
-
Sometimes you need to read a binary
|
|
169
|
-
For example, when you are reading a response packet off of the wire, you will need to read the raw response
|
|
170
|
-
string into an actual packet class. This is done using the #read class method.
|
|
161
|
+
Sometimes you need to read a binary data and apply one of the packet structures to it. For example, when you are reading a response packet, you will need to read the raw response string into an actual packet class. This is done using the #read class method.
|
|
171
162
|
|
|
172
163
|
```ruby
|
|
173
164
|
2.3.3 :014 > blob = "\xFFSMB+\x00\x00\x00\x00\x98\x01`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
|
|
@@ -178,8 +169,7 @@ string into an actual packet class. This is done using the #read class method.
|
|
|
178
169
|
```
|
|
179
170
|
|
|
180
171
|
#### Outputting to a Binary Blob
|
|
181
|
-
Any structure or packet in
|
|
182
|
-
BinData's #to_binary_s method.
|
|
172
|
+
Any structure or packet in RubySMB can also be converted back into a binary blob using BinData's #to_binary_s method.
|
|
183
173
|
|
|
184
174
|
Example:
|
|
185
175
|
```ruby
|
|
@@ -190,38 +180,35 @@ Example:
|
|
|
190
180
|
```
|
|
191
181
|
### Using the Client
|
|
192
182
|
|
|
193
|
-
Sitting on top of the packet layer in RubySMB is the RubySMB::Client. This is the
|
|
194
|
-
It provides fairly simple conveience methods for performing SMB actions. It handles the creation, sending and receiving of packets
|
|
195
|
-
for the user, relying on reasonable defaults in many cases.
|
|
183
|
+
Sitting on top of the packet layer in RubySMB is the RubySMB::Client class. This is the abstraction that most users of RubySMB will interact with. It provides simple conveience methods for performing SMB actions. It handles the creation, sending and receiving of packets for the user, providing reasonable defaults in many cases.
|
|
196
184
|
|
|
197
185
|
#### Negotiation
|
|
198
186
|
|
|
199
|
-
The RubySMB
|
|
200
|
-
the client will negotiate the propper protocol and dialect behind the scenes.
|
|
187
|
+
The RubySMB client is capable of multi-protocol negotiation. The user simply specifies whether SMB1 and/or SMB2 should be supported, and the client negotiates the protocol and dialect behind the scenes.
|
|
201
188
|
|
|
202
|
-
In the
|
|
203
|
-
|
|
204
|
-
Example:
|
|
189
|
+
In the following example, we tell the client that both SMB1 and SMB2 should be supported. The client will then negotiate with the server which version should be used.
|
|
190
|
+
|
|
191
|
+
Negotiation Example:
|
|
205
192
|
```ruby
|
|
206
193
|
sock = TCPSocket.new address, 445
|
|
207
194
|
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
208
195
|
|
|
209
|
-
client = RubySMB::Client.new(dispatcher,
|
|
196
|
+
client = RubySMB::Client.new(dispatcher, username: 'msfadmin', password: 'msfadmin')
|
|
210
197
|
client.negotiate
|
|
211
198
|
```
|
|
212
199
|
|
|
213
200
|
#### Authentication
|
|
214
201
|
|
|
215
|
-
|
|
216
|
-
will not currently attempt older basic authentication on its own, it will attempt an anonymous login
|
|
217
|
-
user credentials are supplied
|
|
202
|
+
RubySMB uses the [Ruby NTLM gem](https://rubygems.org/gems/rubyntlm) for authentication. While the client
|
|
203
|
+
will not currently attempt older basic authentication on its own, it will attempt an anonymous login if no
|
|
204
|
+
user credentials are supplied.
|
|
218
205
|
|
|
219
206
|
Authenticated Example:
|
|
220
207
|
```ruby
|
|
221
208
|
sock = TCPSocket.new address, 445
|
|
222
209
|
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
223
210
|
|
|
224
|
-
client = RubySMB::Client.new(dispatcher,
|
|
211
|
+
client = RubySMB::Client.new(dispatcher, username: 'msfadmin', password: 'msfadmin')
|
|
225
212
|
client.negotiate
|
|
226
213
|
client.authenticate
|
|
227
214
|
```
|
|
@@ -231,24 +218,23 @@ Anonymous Example:
|
|
|
231
218
|
sock = TCPSocket.new address, 445
|
|
232
219
|
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
233
220
|
|
|
234
|
-
client = RubySMB::Client.new(dispatcher,
|
|
221
|
+
client = RubySMB::Client.new(dispatcher, username: '', password: '')
|
|
235
222
|
client.negotiate
|
|
236
223
|
client.authenticate
|
|
237
224
|
```
|
|
238
225
|
|
|
239
226
|
#### Connecting to a Tree
|
|
240
227
|
|
|
241
|
-
While there is one Client
|
|
242
|
-
|
|
243
|
-
|
|
228
|
+
While there is one RubySMB::Client object that supports both SMB1 and SMB2, once the library connects to an SMB tree, it returns a protocol-specific RubySMB::Tree object. This Tree object executes all subsequent file operations on the tree.
|
|
229
|
+
|
|
230
|
+
In the below example we see a simple script to connect to a remote tree, and list all files in a given sub-directory.
|
|
244
231
|
|
|
245
|
-
In the below example we see a simple script to connect to a remote Tree, and list all files in a given sub-directory.
|
|
246
232
|
Example:
|
|
247
233
|
```ruby
|
|
248
234
|
sock = TCPSocket.new address, 445
|
|
249
235
|
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
250
236
|
|
|
251
|
-
client = RubySMB::Client.new(dispatcher,
|
|
237
|
+
client = RubySMB::Client.new(dispatcher, username: 'msfadmin', password: 'msfadmin')
|
|
252
238
|
client.negotiate
|
|
253
239
|
client.authenticate
|
|
254
240
|
|
|
@@ -273,28 +259,30 @@ Example:
|
|
|
273
259
|
|
|
274
260
|
|
|
275
261
|
## Developer tips
|
|
276
|
-
|
|
262
|
+
|
|
263
|
+
It is useful to have Wireshark and a reference SMB client, such as Impacket's installed to help debug and compare output:
|
|
277
264
|
|
|
278
265
|
### Wireshark
|
|
266
|
+
|
|
267
|
+
Configure Wireshark in Debian-based systems to be able to capture traffic without root user privileges:
|
|
268
|
+
|
|
279
269
|
- `sudo apt-get install wireshark`
|
|
280
270
|
- `sudo dpkg-reconfigure wireshark-common`
|
|
281
271
|
- `sudo addgroup wireshark`
|
|
282
272
|
- `sudo usermod -a -G wireshark <USERNAME>`
|
|
283
273
|
|
|
284
274
|
### Impacket
|
|
275
|
+
|
|
285
276
|
- `sudo apt-get install python-setuptools`
|
|
286
277
|
- `sudo easy_install pyasn1 pycrypto`
|
|
287
278
|
- Download from GitHub (https://github.com/coresecurity/impacket)
|
|
288
279
|
- `sudo python setup.py install`
|
|
289
280
|
- `cd examples && python smbclient.py <USER>:<PASS>@<WINDOWS HOST IP>`
|
|
290
281
|
|
|
291
|
-
|
|
292
|
-
|
|
293
282
|
## License
|
|
294
283
|
|
|
295
284
|
`ruby_smb` is released under a 3-clause BSD license. See [LICENSE.txt](LICENSE.txt) for full text.
|
|
296
285
|
|
|
297
|
-
|
|
298
286
|
## Contributing
|
|
299
287
|
|
|
300
288
|
1. Fork it ( https://github.com/rapid7/ruby_smb/fork )
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# This example script is used for testing Winreg registry key enumeration functionality
|
|
4
|
+
# It will attempt to connect to a host and enumerate registry subkeys of a specified registry key.
|
|
5
|
+
# Example usage: ruby enum_registry_key.rb 192.168.172.138 msfadmin msfadmin HKLM\\My\\Key
|
|
6
|
+
# This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and enumerate HKLM\\My\\Key subkeys.
|
|
7
|
+
|
|
8
|
+
require 'bundler/setup'
|
|
9
|
+
require 'ruby_smb'
|
|
10
|
+
|
|
11
|
+
address = ARGV[0]
|
|
12
|
+
username = ARGV[1]
|
|
13
|
+
password = ARGV[2]
|
|
14
|
+
registry_key = ARGV[3]
|
|
15
|
+
|
|
16
|
+
sock = TCPSocket.new address, 445
|
|
17
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60)
|
|
18
|
+
|
|
19
|
+
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
|
|
20
|
+
protocol = client.negotiate
|
|
21
|
+
status = client.authenticate
|
|
22
|
+
|
|
23
|
+
puts "#{protocol} : #{status}"
|
|
24
|
+
|
|
25
|
+
enum_result = client.enum_registry_key(address, registry_key)
|
|
26
|
+
puts enum_result
|
|
27
|
+
|
|
28
|
+
client.disconnect!
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# This example script is used for testing values enumeration of a specific Winreg registry.
|
|
4
|
+
# It will attempt to connect to a host and enumerate values of a specified registry key.
|
|
5
|
+
# Example usage: ruby enum_registry_values.rb 192.168.172.138 msfadmin msfadmin HKLM\\My\\Key
|
|
6
|
+
# This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and enumerate HKLM\\My\\Key values.
|
|
7
|
+
|
|
8
|
+
require 'bundler/setup'
|
|
9
|
+
require 'ruby_smb'
|
|
10
|
+
|
|
11
|
+
address = ARGV[0]
|
|
12
|
+
username = ARGV[1]
|
|
13
|
+
password = ARGV[2]
|
|
14
|
+
registry_key = ARGV[3]
|
|
15
|
+
|
|
16
|
+
sock = TCPSocket.new address, 445
|
|
17
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60)
|
|
18
|
+
|
|
19
|
+
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
|
|
20
|
+
protocol = client.negotiate
|
|
21
|
+
status = client.authenticate
|
|
22
|
+
|
|
23
|
+
puts "#{protocol} : #{status}"
|
|
24
|
+
|
|
25
|
+
enum_result = client.enum_registry_values(address, registry_key)
|
|
26
|
+
puts enum_result
|
|
27
|
+
|
|
28
|
+
client.disconnect!
|
|
29
|
+
|
|
30
|
+
|
data/examples/pipes.rb
CHANGED
|
@@ -33,7 +33,8 @@ end
|
|
|
33
33
|
|
|
34
34
|
client.authenticate
|
|
35
35
|
client.tree_connect("\\\\#{address}\\IPC$")
|
|
36
|
-
|
|
36
|
+
client.create_pipe(pipename)
|
|
37
|
+
pipe = client.last_file
|
|
37
38
|
|
|
38
39
|
puts "Available: #{pipe.peek_available}"
|
|
39
40
|
puts "PipeState: #{pipe.peek_state}" # 3 == OK
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# This example script is used for testing the Winreg registry key value read functionality.
|
|
4
|
+
# It will attempt to connect to a host and reads the value of a specified registry key.
|
|
5
|
+
# Example usage: ruby enum_registry_key.rb 192.168.172.138 msfadmin msfadmin HKLM\\My\\Key ValueName
|
|
6
|
+
# This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and reads the ValueName data corresponding to the HKLM\\My\\Key registry key.
|
|
7
|
+
|
|
8
|
+
require 'bundler/setup'
|
|
9
|
+
require 'ruby_smb'
|
|
10
|
+
|
|
11
|
+
address = ARGV[0]
|
|
12
|
+
username = ARGV[1]
|
|
13
|
+
password = ARGV[2]
|
|
14
|
+
registry_key = ARGV[3]
|
|
15
|
+
value_name = ARGV[4]
|
|
16
|
+
|
|
17
|
+
sock = TCPSocket.new address, 445
|
|
18
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60)
|
|
19
|
+
|
|
20
|
+
client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
|
|
21
|
+
protocol = client.negotiate
|
|
22
|
+
status = client.authenticate
|
|
23
|
+
|
|
24
|
+
puts "#{protocol}: #{status}"
|
|
25
|
+
puts "Key: #{registry_key}"
|
|
26
|
+
puts "Value: #{value_name}"
|
|
27
|
+
|
|
28
|
+
key_value = client.read_registry_key_value(address, registry_key, value_name)
|
|
29
|
+
puts key_value
|
|
30
|
+
|
|
31
|
+
client.disconnect!
|
|
32
|
+
|
|
@@ -54,14 +54,15 @@ module RubySMB
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def smb1_anonymous_auth_response(raw_response)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
packet = RubySMB::SMB1::Packet::SessionSetupLegacyResponse.read(raw_response)
|
|
58
|
+
|
|
59
|
+
unless packet.valid?
|
|
60
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
61
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
62
|
+
expected_cmd: RubySMB::SMB1::Packet::SessionSetupLegacyResponse::COMMAND,
|
|
63
|
+
received_proto: packet.smb_header.protocol,
|
|
64
|
+
received_cmd: packet.smb_header.command
|
|
65
|
+
)
|
|
65
66
|
end
|
|
66
67
|
packet
|
|
67
68
|
end
|
|
@@ -147,14 +148,15 @@ module RubySMB
|
|
|
147
148
|
|
|
148
149
|
# Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
|
149
150
|
def smb1_ntlmssp_final_packet(raw_response)
|
|
150
|
-
|
|
151
|
-
packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
|
|
152
|
-
rescue
|
|
153
|
-
packet = RubySMB::SMB1::Packet::EmptyPacket.read(raw_response)
|
|
154
|
-
end
|
|
151
|
+
packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
|
|
155
152
|
|
|
156
|
-
unless packet.
|
|
157
|
-
raise RubySMB::Error::InvalidPacket
|
|
153
|
+
unless packet.valid?
|
|
154
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
155
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
156
|
+
expected_cmd: RubySMB::SMB1::Packet::SessionSetupResponse::COMMAND,
|
|
157
|
+
received_proto: packet.smb_header.protocol,
|
|
158
|
+
received_cmd: packet.smb_header.command
|
|
159
|
+
)
|
|
158
160
|
end
|
|
159
161
|
packet
|
|
160
162
|
end
|
|
@@ -162,15 +164,20 @@ module RubySMB
|
|
|
162
164
|
# Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
|
163
165
|
def smb1_ntlmssp_challenge_packet(raw_response)
|
|
164
166
|
packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
|
|
165
|
-
|
|
167
|
+
unless packet.valid?
|
|
168
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
169
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
170
|
+
expected_cmd: RubySMB::SMB1::Packet::SessionSetupResponse::COMMAND,
|
|
171
|
+
received_proto: packet.smb_header.protocol,
|
|
172
|
+
received_cmd: packet.smb_header.command
|
|
173
|
+
)
|
|
174
|
+
end
|
|
166
175
|
|
|
176
|
+
status_code = packet.status_code
|
|
167
177
|
unless status_code.name == 'STATUS_MORE_PROCESSING_REQUIRED'
|
|
168
178
|
raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
|
|
169
179
|
end
|
|
170
180
|
|
|
171
|
-
unless packet.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
|
|
172
|
-
raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb_header.command} and not #{RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP}"
|
|
173
|
-
end
|
|
174
181
|
packet
|
|
175
182
|
end
|
|
176
183
|
|
|
@@ -212,23 +219,34 @@ module RubySMB
|
|
|
212
219
|
# Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
|
213
220
|
def smb2_ntlmssp_final_packet(raw_response)
|
|
214
221
|
packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
|
|
215
|
-
unless packet.
|
|
216
|
-
raise RubySMB::Error::InvalidPacket
|
|
222
|
+
unless packet.valid?
|
|
223
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
224
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
|
225
|
+
expected_cmd: RubySMB::SMB2::Packet::SessionSetupResponse::COMMAND,
|
|
226
|
+
received_proto: packet.smb2_header.protocol,
|
|
227
|
+
received_cmd: packet.smb2_header.command
|
|
228
|
+
)
|
|
217
229
|
end
|
|
230
|
+
|
|
218
231
|
packet
|
|
219
232
|
end
|
|
220
233
|
|
|
221
234
|
# Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
|
222
235
|
def smb2_ntlmssp_challenge_packet(raw_response)
|
|
223
236
|
packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
|
|
237
|
+
unless packet.valid?
|
|
238
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
239
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
|
240
|
+
expected_cmd: RubySMB::SMB2::Packet::SessionSetupResponse::COMMAND,
|
|
241
|
+
received_proto: packet.smb2_header.protocol,
|
|
242
|
+
received_cmd: packet.smb2_header.command
|
|
243
|
+
)
|
|
244
|
+
end
|
|
245
|
+
|
|
224
246
|
status_code = packet.status_code
|
|
225
247
|
unless status_code.name == 'STATUS_MORE_PROCESSING_REQUIRED'
|
|
226
248
|
raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
|
|
227
249
|
end
|
|
228
|
-
|
|
229
|
-
unless packet.smb2_header.command == RubySMB::SMB2::Commands::SESSION_SETUP
|
|
230
|
-
raise RubySMB::Error::InvalidPacket, "Command was #{packet.smb2_header.command} and not #{RubySMB::SMB2::Commands::SESSION_SETUP}"
|
|
231
|
-
end
|
|
232
250
|
packet
|
|
233
251
|
end
|
|
234
252
|
|
data/lib/ruby_smb/client/echo.rb
CHANGED
|
@@ -16,7 +16,16 @@ module RubySMB
|
|
|
16
16
|
(count - 1).times do
|
|
17
17
|
raw_response = dispatcher.recv_packet
|
|
18
18
|
end
|
|
19
|
-
RubySMB::SMB1::Packet::EchoResponse.read(raw_response)
|
|
19
|
+
response = RubySMB::SMB1::Packet::EchoResponse.read(raw_response)
|
|
20
|
+
unless response.valid?
|
|
21
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
22
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
23
|
+
expected_cmd: RubySMB::SMB1::Packet::EchoResponse::COMMAND,
|
|
24
|
+
received_proto: response.smb_header.protocol,
|
|
25
|
+
received_cmd: response.smb_header.command
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
response
|
|
20
29
|
end
|
|
21
30
|
|
|
22
31
|
# Sends an ECHO request packet and returns the
|
|
@@ -26,7 +35,16 @@ module RubySMB
|
|
|
26
35
|
def smb2_echo
|
|
27
36
|
request = RubySMB::SMB2::Packet::EchoRequest.new
|
|
28
37
|
raw_response = send_recv(request)
|
|
29
|
-
RubySMB::SMB2::Packet::EchoResponse.read(raw_response)
|
|
38
|
+
response = RubySMB::SMB2::Packet::EchoResponse.read(raw_response)
|
|
39
|
+
unless response.valid?
|
|
40
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
41
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
|
42
|
+
expected_cmd: RubySMB::SMB2::Packet::EchoResponse::COMMAND,
|
|
43
|
+
received_proto: response.smb2_header.protocol,
|
|
44
|
+
received_cmd: response.smb2_header.command
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
response
|
|
30
48
|
end
|
|
31
49
|
end
|
|
32
50
|
end
|
|
@@ -47,23 +47,38 @@ module RubySMB
|
|
|
47
47
|
def negotiate_response(raw_data)
|
|
48
48
|
response = nil
|
|
49
49
|
if smb1
|
|
50
|
-
|
|
51
|
-
packet = RubySMB::SMB1::Packet::NegotiateResponseExtended.read raw_data
|
|
52
|
-
rescue StandardError => e
|
|
53
|
-
raise RubySMB::Error::InvalidPacket, "Not a Valid SMB1 Negoitate Response #{e.message}"
|
|
54
|
-
end
|
|
50
|
+
packet = RubySMB::SMB1::Packet::NegotiateResponseExtended.read raw_data
|
|
55
51
|
response = packet if packet.valid?
|
|
56
52
|
end
|
|
57
53
|
if smb2 && response.nil?
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
rescue StandardError => e
|
|
61
|
-
raise RubySMB::Error::InvalidPacket, "Not a Valid SMB2 Negoitate Response #{e.message}"
|
|
62
|
-
end
|
|
63
|
-
response = packet
|
|
54
|
+
packet = RubySMB::SMB2::Packet::NegotiateResponse.read raw_data
|
|
55
|
+
response = packet if packet.valid?
|
|
64
56
|
end
|
|
65
57
|
if response.nil?
|
|
66
|
-
|
|
58
|
+
if packet.packet_smb_version == 'SMB1'
|
|
59
|
+
extended_security = if packet.is_a? RubySMB::SMB1::Packet::NegotiateResponseExtended
|
|
60
|
+
packet.parameter_block.capabilities.extended_security
|
|
61
|
+
else
|
|
62
|
+
"n/a"
|
|
63
|
+
end
|
|
64
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
65
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
66
|
+
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
|
67
|
+
expected_custom: "extended_security=1",
|
|
68
|
+
received_proto: packet.smb_header.protocol,
|
|
69
|
+
received_cmd: packet.smb_header.command,
|
|
70
|
+
received_custom: "extended_security=#{extended_security}"
|
|
71
|
+
)
|
|
72
|
+
elsif packet.packet_smb_version == 'SMB2'
|
|
73
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
74
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
|
75
|
+
expected_cmd: RubySMB::SMB2::Packet::NegotiateResponse::COMMAND,
|
|
76
|
+
received_proto: packet.smb2_header.protocol,
|
|
77
|
+
received_cmd: packet.smb2_header.command
|
|
78
|
+
)
|
|
79
|
+
else
|
|
80
|
+
raise RubySMB::Error::InvalidPacket, 'Unknown SMB protocol version'
|
|
81
|
+
end
|
|
67
82
|
end
|
|
68
83
|
response
|
|
69
84
|
end
|
|
@@ -17,11 +17,7 @@ module RubySMB
|
|
|
17
17
|
request.smb_header.tid = 65_535
|
|
18
18
|
request.data_block.path = share
|
|
19
19
|
raw_response = send_recv(request)
|
|
20
|
-
|
|
21
|
-
response = RubySMB::SMB1::Packet::TreeConnectResponse.read(raw_response)
|
|
22
|
-
rescue EOFError
|
|
23
|
-
response = RubySMB::SMB1::Packet::EmptyPacket.read(raw_response)
|
|
24
|
-
end
|
|
20
|
+
response = RubySMB::SMB1::Packet::TreeConnectResponse.read(raw_response)
|
|
25
21
|
smb1_tree_from_response(share, response)
|
|
26
22
|
end
|
|
27
23
|
|
|
@@ -30,9 +26,16 @@ module RubySMB
|
|
|
30
26
|
# @param share [String] the share path to connect to
|
|
31
27
|
# @param response [RubySMB::SMB1::Packet::TreeConnectResponse] the response packet to parse into our Tree
|
|
32
28
|
# @return [RubySMB::SMB1::Tree]
|
|
29
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response command is not a TreeConnectResponse packet
|
|
30
|
+
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response status code is not STATUS_SUCCESS
|
|
33
31
|
def smb1_tree_from_response(share, response)
|
|
34
|
-
unless response.
|
|
35
|
-
raise RubySMB::Error::InvalidPacket
|
|
32
|
+
unless response.valid?
|
|
33
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
34
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
35
|
+
expected_cmd: RubySMB::SMB1::Packet::TreeConnectResponse::COMMAND,
|
|
36
|
+
received_proto: response.smb_header.protocol,
|
|
37
|
+
received_cmd: response.smb_header.command
|
|
38
|
+
)
|
|
36
39
|
end
|
|
37
40
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
38
41
|
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
|
@@ -54,11 +57,7 @@ module RubySMB
|
|
|
54
57
|
request.smb2_header.tree_id = 65_535
|
|
55
58
|
request.encode_path(share)
|
|
56
59
|
raw_response = send_recv(request)
|
|
57
|
-
|
|
58
|
-
response = RubySMB::SMB2::Packet::TreeConnectResponse.read(raw_response)
|
|
59
|
-
rescue EOFError
|
|
60
|
-
response = RubySMB::SMB2::Packet::ErrorPacket.read(raw_response)
|
|
61
|
-
end
|
|
60
|
+
response = RubySMB::SMB2::Packet::TreeConnectResponse.read(raw_response)
|
|
62
61
|
smb2_tree_from_response(share, response)
|
|
63
62
|
end
|
|
64
63
|
|
|
@@ -67,9 +66,16 @@ module RubySMB
|
|
|
67
66
|
# @param share [String] the share path to connect to
|
|
68
67
|
# @param response [RubySMB::SMB2::Packet::TreeConnectResponse] the response packet to parse into our Tree
|
|
69
68
|
# @return [RubySMB::SMB2::Tree]
|
|
69
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response command is not a TreeConnectResponse packet
|
|
70
|
+
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response status code is not STATUS_SUCCESS
|
|
70
71
|
def smb2_tree_from_response(share, response)
|
|
71
|
-
unless response.
|
|
72
|
-
raise RubySMB::Error::InvalidPacket
|
|
72
|
+
unless response.valid?
|
|
73
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
74
|
+
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
|
75
|
+
expected_cmd: RubySMB::SMB2::Packet::TreeConnectResponse::COMMAND,
|
|
76
|
+
received_proto: response.smb2_header.protocol,
|
|
77
|
+
received_cmd: response.smb2_header.command
|
|
78
|
+
)
|
|
73
79
|
end
|
|
74
80
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
75
81
|
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
|
@@ -25,7 +25,7 @@ module RubySMB
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def open(path, disposition=RubySMB::Dispositions::FILE_OPEN, write: false, read: true)
|
|
28
|
-
file = last_tree.open_file(filename: path.
|
|
28
|
+
file = last_tree.open_file(filename: path.sub(/^\\/, ''), write: write, read: read, disposition: disposition)
|
|
29
29
|
@last_file_id = if file.respond_to?(:guid)
|
|
30
30
|
file.guid.to_binary_s
|
|
31
31
|
elsif file.respond_to?(:fid)
|
|
@@ -50,7 +50,7 @@ module RubySMB
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def delete(path)
|
|
53
|
-
file = last_tree.open_file(filename: path.
|
|
53
|
+
file = last_tree.open_file(filename: path.sub(/^\\/, ''), delete: true)
|
|
54
54
|
file.delete
|
|
55
55
|
file.close
|
|
56
56
|
end
|