ruby_smb 1.0.5 → 1.1.0
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.tar.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.rb +0 -1
- data/lib/ruby_smb/client.rb +2 -0
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- 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.rb +10 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -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/smb1/file.rb +2 -0
- data/lib/ruby_smb/smb1/pipe.rb +78 -2
- data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
- data/lib/ruby_smb/smb2/pipe.rb +89 -2
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +3 -3
- data/spec/lib/ruby_smb/client_spec.rb +148 -0
- 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/smb1/file_spec.rb +9 -1
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +210 -148
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +3 -24
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +256 -145
- metadata +66 -9
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
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.tar.gz.sig
CHANGED
Binary file
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,11 +4,12 @@
|
|
4
4
|
[![Code Climate](https://codeclimate.com/github/rapid7/ruby_smb.png)](https://codeclimate.com/github/rapid7/ruby_smb)
|
5
5
|
[![Coverage Status](https://coveralls.io/repos/github/rapid7/ruby_smb/badge.svg?branch=master)](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
|
+
|
data/lib/ruby_smb.rb
CHANGED
data/lib/ruby_smb/client.rb
CHANGED
@@ -8,6 +8,7 @@ module RubySMB
|
|
8
8
|
require 'ruby_smb/client/tree_connect'
|
9
9
|
require 'ruby_smb/client/echo'
|
10
10
|
require 'ruby_smb/client/utils'
|
11
|
+
require 'ruby_smb/client/winreg'
|
11
12
|
|
12
13
|
include RubySMB::Client::Negotiation
|
13
14
|
include RubySMB::Client::Authentication
|
@@ -15,6 +16,7 @@ module RubySMB
|
|
15
16
|
include RubySMB::Client::TreeConnect
|
16
17
|
include RubySMB::Client::Echo
|
17
18
|
include RubySMB::Client::Utils
|
19
|
+
include RubySMB::Client::Winreg
|
18
20
|
|
19
21
|
# The Default SMB1 Dialect string used in an SMB1 Negotiate Request
|
20
22
|
SMB1_DIALECT_SMB1_DEFAULT = 'NT LM 0.12'.freeze
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RubySMB
|
2
|
+
class Client
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
def connect_to_winreg(host)
|
6
|
+
share = "\\\\#{host}\\IPC$"
|
7
|
+
tree = @tree_connects.find {|tree| tree.share == share}
|
8
|
+
tree = tree_connect(share) unless tree
|
9
|
+
named_pipe = tree.open_file(filename: "winreg", write: true, read: true)
|
10
|
+
if block_given?
|
11
|
+
res = yield named_pipe
|
12
|
+
named_pipe.close
|
13
|
+
res
|
14
|
+
else
|
15
|
+
named_pipe
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_registry_key?(host, key)
|
20
|
+
connect_to_winreg(host) do |named_pipe|
|
21
|
+
named_pipe.has_registry_key?(key)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def read_registry_key_value(host, key, value_name)
|
26
|
+
connect_to_winreg(host) do |named_pipe|
|
27
|
+
named_pipe.read_registry_key_value(key, value_name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def enum_registry_key(host, key)
|
32
|
+
connect_to_winreg(host) do |named_pipe|
|
33
|
+
named_pipe.enum_registry_key(key)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def enum_registry_values(host, key)
|
38
|
+
connect_to_winreg(host) do |named_pipe|
|
39
|
+
named_pipe.enum_registry_values(key)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/lib/ruby_smb/dcerpc.rb
CHANGED
@@ -1,15 +1,53 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module Dcerpc
|
3
|
+
MAX_XMIT_FRAG = 4280
|
4
|
+
MAX_RECV_FRAG = 4280
|
5
|
+
|
6
|
+
require 'windows_error/win32'
|
3
7
|
require 'ruby_smb/dcerpc/error'
|
4
8
|
require 'ruby_smb/dcerpc/uuid'
|
5
9
|
require 'ruby_smb/dcerpc/ndr'
|
6
10
|
require 'ruby_smb/dcerpc/ptypes'
|
7
11
|
require 'ruby_smb/dcerpc/p_syntax_id_t'
|
12
|
+
require 'ruby_smb/dcerpc/rrp_unicode_string'
|
8
13
|
require 'ruby_smb/dcerpc/pdu_header'
|
9
14
|
require 'ruby_smb/dcerpc/srvsvc'
|
15
|
+
require 'ruby_smb/dcerpc/winreg'
|
10
16
|
require 'ruby_smb/dcerpc/request'
|
11
17
|
require 'ruby_smb/dcerpc/response'
|
12
18
|
require 'ruby_smb/dcerpc/bind'
|
13
19
|
require 'ruby_smb/dcerpc/bind_ack'
|
20
|
+
|
21
|
+
|
22
|
+
# Bind to the remote server interface endpoint.
|
23
|
+
#
|
24
|
+
# @param options [Hash] the options to pass to the Bind request packet. At least, :endpoint must but provided with an existing Dcerpc class
|
25
|
+
# @return [RubySMB::Dcerpc::BindAck] the BindAck response packet
|
26
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if an invalid packet is received
|
27
|
+
# @raise [RubySMB::Dcerpc::Error::BindError] if the response is not a BindAck packet or if the Bind result code is not ACCEPTANCE
|
28
|
+
def bind(options={})
|
29
|
+
bind_req = RubySMB::Dcerpc::Bind.new(options)
|
30
|
+
write(data: bind_req.to_binary_s)
|
31
|
+
@size = 1024
|
32
|
+
dcerpc_raw_response = read()
|
33
|
+
begin
|
34
|
+
dcerpc_response = RubySMB::Dcerpc::BindAck.read(dcerpc_raw_response)
|
35
|
+
rescue IOError
|
36
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
|
37
|
+
end
|
38
|
+
unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::BIND_ACK
|
39
|
+
raise RubySMB::Dcerpc::Error::BindError, "Not a BindAck packet"
|
40
|
+
end
|
41
|
+
|
42
|
+
res_list = dcerpc_response.p_result_list
|
43
|
+
if res_list.n_results == 0 ||
|
44
|
+
res_list.p_results[0].result != RubySMB::Dcerpc::BindAck::ACCEPTANCE
|
45
|
+
raise RubySMB::Dcerpc::Error::BindError,
|
46
|
+
"Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
|
47
|
+
end
|
48
|
+
@tree.client.max_buffer_size = dcerpc_response.max_xmit_frag
|
49
|
+
dcerpc_response
|
50
|
+
end
|
51
|
+
|
14
52
|
end
|
15
53
|
end
|