ruby_smb 3.0.3 → 3.0.6
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/verify.yml +1 -1
- data/.simplecov +1 -1
- data/CONTRIBUTING.md +28 -3
- data/README.md +8 -0
- data/examples/pwsh_service.rb +112 -0
- data/lib/ruby_smb/client/negotiation.rb +1 -1
- data/lib/ruby_smb/client.rb +23 -2
- data/lib/ruby_smb/dcerpc/request.rb +2 -0
- data/lib/ruby_smb/dcerpc/svcctl/create_service_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/create_service_w_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/svcctl/delete_service_request.rb +21 -0
- data/lib/ruby_smb/dcerpc/svcctl/delete_service_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/svcctl.rb +66 -5
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg.rb +1 -1
- data/lib/ruby_smb/server/session.rb +6 -0
- data/lib/ruby_smb/smb1/bit_field/directory_access_mask.rb +1 -1
- data/lib/ruby_smb/smb1/bit_field/file_access_mask.rb +1 -1
- data/lib/ruby_smb/smb2/bit_field/directory_access_mask.rb +1 -1
- data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +1 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +11 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +10 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_request_spec.rb +143 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_response_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_request_spec.rb +29 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_response_spec.rb +29 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +8 -8
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +1 -1
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +5 -0
- data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +4 -4
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +6 -1
- data/spec/spec_helper.rb +2 -3
- data.tar.gz.sig +0 -0
- metadata +17 -4
- metadata.gz.sig +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz: '
|
3
|
+
metadata.gz: 4dd0be012c18ad4e243cbfa2948fc620448766612b2f33be278583981fa2cf90
|
4
|
+
data.tar.gz: '07309ce54e701f2c3654a9cdbc8b3eff9d42d54451321e6e17a49d46ae4ce162'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee506f05e67f8fa1a61b0d0f05470b41e20c5972c9c9584e8fe8069352a2cd09704b66d42856fb1330a93def276525b0d50047e93b981479c064c36f35f8298a
|
7
|
+
data.tar.gz: 78c37f1157393e17c51a6de7ff55fb25206e84f68740c958c406c36432ca90bc572716670640b9153a3ff66247dfcbeae8f4305f3c17cd91af64e8a4fc092894
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.simplecov
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# controlled by running with coverage, so don't explicitly start coverage (and
|
3
3
|
# therefore generate a report) when in Rubymine. This _will_ generate a report
|
4
4
|
# whenever `rake spec` is run.
|
5
|
-
unless ENV['RM_INFO']
|
5
|
+
unless ENV['RM_INFO'] || SimpleCov.running
|
6
6
|
SimpleCov.start
|
7
7
|
end
|
8
8
|
|
data/CONTRIBUTING.md
CHANGED
@@ -1,8 +1,33 @@
|
|
1
1
|
# Contributing
|
2
2
|
|
3
|
+
## Versioning
|
4
|
+
|
5
|
+
RubySMB attempts to follow [the Semantic Versioning 2.0.0](https://semver.org/) standard, however due to certain key architectural qualities, some reservations are made regarding what will trigger major and minor version bumps. A large component of RubySMB are the data definitions written using [BinData](https://github.com/dmendel/bindata). These definitions are implemented in an incremental fashion, causing some to be missing while others are only partially implemented (particularly in cases where fields are dependent on other types that may or may not be defined). Because of this, the RubySMB project reserves the right to update these definitions without incrementing the major version. In most cases, the definitions and their fields do not need to be used to perform standard operations such as connecting to, authenticating to and reading a file from a remote SMB server. The API provided by non-BinData objects will remain stable across minor versions, with backwards incompatible changes triggering a major version bump. Backwards incompatible changes to data structure definitions in BinData will cause the RubySMB maintianers to perform a minor version bump. These changes include but are not limited to:
|
6
|
+
|
7
|
+
* Changes to the class name due to how BinData's internal registration works
|
8
|
+
* Their field names which may be updated to avoid conflicts
|
9
|
+
* Their field types which may be extended with more functionality or switched from integers to full-flag based definitions
|
10
|
+
|
11
|
+
### Usage Examples
|
12
|
+
The following two examples show dangerous operations that may not be stable across minor version bumps, and safe operations.
|
13
|
+
|
14
|
+
```
|
15
|
+
# dangerous operation, the BinData object name (TransformHeader) may change in the future
|
16
|
+
header = RubySMB::SMB2::Packet::TransformHeader.read(raw_request)
|
17
|
+
# also dangerous operation, the field name may change in the future
|
18
|
+
header.flags = 0
|
19
|
+
```
|
20
|
+
|
21
|
+
```
|
22
|
+
# safe operation, the API exposed on the Client won't change without a major version bump
|
23
|
+
client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
|
24
|
+
# safe operation, methods on non-BinData objects won't change without a major version bump
|
25
|
+
protocol = client.negotiate
|
26
|
+
```
|
27
|
+
|
3
28
|
## Forking
|
4
29
|
|
5
|
-
[Fork this repository](https://github.com/rapid7/
|
30
|
+
[Fork this repository](https://github.com/rapid7/ruby_smb/fork)
|
6
31
|
|
7
32
|
## Branching
|
8
33
|
|
@@ -14,7 +39,7 @@ Branch names follow the format `TYPE/ISSUE/SUMMARY`. You can create it with `gi
|
|
14
39
|
|
15
40
|
### `ISSUE`
|
16
41
|
|
17
|
-
`ISSUE` is either a [Github issue](https://github.com/rapid7/
|
42
|
+
`ISSUE` is either a [Github issue](https://github.com/rapid7/ruby_smb/issues) or an issue from some other
|
18
43
|
issue tracking software.
|
19
44
|
|
20
45
|
### `SUMMARY`
|
@@ -49,7 +74,7 @@ Push your branch to your fork on gitub: `git push TYPE/ISSUE/SUMMARY`
|
|
49
74
|
|
50
75
|
### Pull Request
|
51
76
|
|
52
|
-
* [Create new Pull Request](https://github.com/rapid7/
|
77
|
+
* [Create new Pull Request](https://github.com/rapid7/ruby_smb/compare/)
|
53
78
|
* Add a Verification Steps to the description comment
|
54
79
|
|
55
80
|
```
|
data/README.md
CHANGED
@@ -12,6 +12,12 @@ The RubySMB library provides client-level and packet-level support for the proto
|
|
12
12
|
|
13
13
|
See the Wiki for more information on this project's long-term goals, style guide, and developer tips.
|
14
14
|
|
15
|
+
|
16
|
+
## Versioning
|
17
|
+
RubySMB attempts to follow [the Semantic Versioning 2.0.0](https://semver.org/) standard, however due to certain key architectural qualities, some reservations are made regarding what will trigger major and minor version bumps. Upstream consumers utilizing higher-level SMB operations can lock to minor (`~= 3.0`) versions however consumers utilizing raw SMB packet manipulation are recommended to set restrictions for compatibility to allow update resolution for patch versions (`~= 3.0.0`).
|
18
|
+
|
19
|
+
|
20
|
+
|
15
21
|
## Installation
|
16
22
|
|
17
23
|
Add this line to your application's Gemfile:
|
@@ -34,6 +40,8 @@ Or install it yourself as:
|
|
34
40
|
|
35
41
|
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.
|
36
42
|
|
43
|
+
Note that these packets are defined using [BinData](https://github.com/dmendel/bindata) and that their struction is subject to change across minor version bumps. See [CONTRIBUTING.md](https://github.com/rapid7/ruby_smb/blob/master/CONTRIBUTING.md#versioning) for more information.
|
44
|
+
|
37
45
|
#### SMB1
|
38
46
|
|
39
47
|
SMB1 Packets are made up of three basic components:
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# This example script is used for launching a powershell command as a service on a host.
|
4
|
+
# It will attempt to connect to a host and create a new service to launch the command using powershell.exe.
|
5
|
+
# Example usage: ruby pwsh_service.rb --username msfadmin --password msfadmin 192.168.172.138 "echo test > C:\\Users\\User\\Desktop\\test.txt"
|
6
|
+
# This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentials and create a new service to run the powershell command.
|
7
|
+
|
8
|
+
def random_string(length)
|
9
|
+
return (1..length).map { (('a'..'z').to_a + ('A'..'Z').to_a)[rand(26*2)] }.join
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'bundler/setup'
|
13
|
+
require 'optparse'
|
14
|
+
require 'ruby_smb'
|
15
|
+
|
16
|
+
args = ARGV.dup
|
17
|
+
options = {
|
18
|
+
domain: '.',
|
19
|
+
username: '',
|
20
|
+
password: '',
|
21
|
+
command: nil,
|
22
|
+
smbv1: true,
|
23
|
+
smbv2: true,
|
24
|
+
smbv3: true,
|
25
|
+
target: nil
|
26
|
+
}
|
27
|
+
options[:command] = args.pop
|
28
|
+
options[:target] = args.pop
|
29
|
+
optparser = OptionParser.new do |opts|
|
30
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] target command"
|
31
|
+
opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
32
|
+
options[:smbv1] = smbv1
|
33
|
+
end
|
34
|
+
opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
35
|
+
options[:smbv2] = smbv2
|
36
|
+
end
|
37
|
+
opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
38
|
+
options[:smbv3] = smbv3
|
39
|
+
end
|
40
|
+
opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
|
41
|
+
if username.include?('\\')
|
42
|
+
options[:domain], options[:username] = username.split('\\', 2)
|
43
|
+
else
|
44
|
+
options[:username] = username
|
45
|
+
end
|
46
|
+
end
|
47
|
+
opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
|
48
|
+
options[:password] = password
|
49
|
+
end
|
50
|
+
end
|
51
|
+
optparser.parse!(args)
|
52
|
+
|
53
|
+
if options[:target].nil? || options[:command].nil?
|
54
|
+
abort(optparser.help)
|
55
|
+
end
|
56
|
+
|
57
|
+
sock = TCPSocket.new options[:target], 445
|
58
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60)
|
59
|
+
|
60
|
+
client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
|
61
|
+
protocol = client.negotiate
|
62
|
+
status = client.authenticate
|
63
|
+
|
64
|
+
puts "#{protocol} : #{status}"
|
65
|
+
|
66
|
+
tree = client.tree_connect("\\\\#{options[:target]}\\IPC$")
|
67
|
+
svcctl = tree.open_file(filename: 'svcctl', write: true, read: true)
|
68
|
+
|
69
|
+
puts('Binding to \\svcctl...')
|
70
|
+
svcctl.bind(endpoint: RubySMB::Dcerpc::Svcctl)
|
71
|
+
puts('Bound to \\svcctl')
|
72
|
+
|
73
|
+
puts('Opening Service Control Manager')
|
74
|
+
scm_handle = svcctl.open_sc_manager_w(options[:target])
|
75
|
+
|
76
|
+
service_name = random_string(8)
|
77
|
+
display_name = random_string(8)
|
78
|
+
binary_path_name = "%COMSPEC% /c start /b /min powershell.exe -nop -win hid -noni -en #{[options[:command].encode("UTF-16LE")].pack("m0")}"
|
79
|
+
puts "Full Command: #{binary_path_name}"
|
80
|
+
svc_handle = svcctl.create_service_w(scm_handle, service_name, display_name, binary_path_name)
|
81
|
+
|
82
|
+
puts('Created new service')
|
83
|
+
|
84
|
+
svcctl.close_service_handle(svc_handle)
|
85
|
+
|
86
|
+
puts('Opening the service')
|
87
|
+
|
88
|
+
svc_handle = svcctl.open_service_w(scm_handle, service_name)
|
89
|
+
|
90
|
+
puts('Starting the service')
|
91
|
+
|
92
|
+
begin
|
93
|
+
svcctl.start_service_w(svc_handle)
|
94
|
+
rescue RubySMB::Dcerpc::Error::SvcctlError => e
|
95
|
+
if e.message.include?('ERROR_SERVICE_REQUEST_TIMEOUT')
|
96
|
+
puts "Service start timed out, OK if running a command or non-service executable..."
|
97
|
+
else
|
98
|
+
puts "Service start error: #{e}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
puts('Deleting the service')
|
103
|
+
|
104
|
+
svcctl.delete_service(svc_handle)
|
105
|
+
|
106
|
+
puts('Closing Service Control Manager')
|
107
|
+
|
108
|
+
svcctl.close_service_handle(scm_handle)
|
109
|
+
|
110
|
+
puts('Done')
|
111
|
+
|
112
|
+
client.disconnect!
|
@@ -251,7 +251,7 @@ module RubySMB
|
|
251
251
|
raise ArgumentError, 'Must be an array of strings' unless dialect.is_a? String
|
252
252
|
packet.add_dialect(dialect.to_i(16))
|
253
253
|
end
|
254
|
-
packet.capabilities.encryption = 1
|
254
|
+
packet.capabilities.encryption = @session_encrypt_data ? 1 : 0
|
255
255
|
|
256
256
|
if packet.dialects.include?(0x0311)
|
257
257
|
nc = RubySMB::SMB2::NegotiateContext.new(
|
data/lib/ruby_smb/client.rb
CHANGED
@@ -29,10 +29,26 @@ module RubySMB
|
|
29
29
|
# It indicates that the server implements SMB 2.1 or future dialect revisions
|
30
30
|
# Note that this must be used for SMB3
|
31
31
|
SMB1_DIALECT_SMB2_WILDCARD = 'SMB 2.???'.freeze
|
32
|
+
|
33
|
+
SMB2_DIALECT_0202 = '0x0202'.freeze
|
34
|
+
SMB2_DIALECT_0210 = '0x0210'.freeze
|
35
|
+
SMB2_DIALECT_0300 = '0x0300'.freeze
|
36
|
+
SMB2_DIALECT_0302 = '0x0302'.freeze
|
37
|
+
SMB2_DIALECT_0311 = '0x0311'.freeze
|
38
|
+
|
32
39
|
# Dialect values for SMB2
|
33
|
-
SMB2_DIALECT_DEFAULT = [
|
40
|
+
SMB2_DIALECT_DEFAULT = [
|
41
|
+
SMB2_DIALECT_0202,
|
42
|
+
SMB2_DIALECT_0210,
|
43
|
+
].freeze
|
44
|
+
|
34
45
|
# Dialect values for SMB3
|
35
|
-
SMB3_DIALECT_DEFAULT = [
|
46
|
+
SMB3_DIALECT_DEFAULT = [
|
47
|
+
SMB2_DIALECT_0300,
|
48
|
+
SMB2_DIALECT_0302,
|
49
|
+
SMB2_DIALECT_0311
|
50
|
+
].freeze
|
51
|
+
|
36
52
|
# The default maximum size of a SMB message that the Client accepts (in bytes)
|
37
53
|
MAX_BUFFER_SIZE = 64512
|
38
54
|
# The default maximum size of a SMB message that the Server accepts (in bytes)
|
@@ -129,6 +145,11 @@ module RubySMB
|
|
129
145
|
# @return [Integer]
|
130
146
|
attr_accessor :session_id
|
131
147
|
|
148
|
+
# Whether or not the current session has the guest flag set
|
149
|
+
# @!attribute [rw] session_is_guest
|
150
|
+
# @return [Boolean]
|
151
|
+
attr_accessor :session_is_guest
|
152
|
+
|
132
153
|
# Whether or not the Server requires signing
|
133
154
|
# @!attribute [rw] signing_enabled
|
134
155
|
# @return [Boolean]
|
@@ -48,6 +48,7 @@ module RubySMB
|
|
48
48
|
end
|
49
49
|
choice 'Svcctl', selection: -> { opnum } do
|
50
50
|
open_sc_manager_w_request Svcctl::OPEN_SC_MANAGER_W
|
51
|
+
create_service_w_request Svcctl::CREATE_SERVICE_W
|
51
52
|
open_service_w_request Svcctl::OPEN_SERVICE_W
|
52
53
|
query_service_status_request Svcctl::QUERY_SERVICE_STATUS
|
53
54
|
query_service_config_w_request Svcctl::QUERY_SERVICE_CONFIG_W
|
@@ -55,6 +56,7 @@ module RubySMB
|
|
55
56
|
start_service_w_request Svcctl::START_SERVICE_W
|
56
57
|
control_service_request Svcctl::CONTROL_SERVICE
|
57
58
|
close_service_handle_request Svcctl::CLOSE_SERVICE_HANDLE
|
59
|
+
delete_service_request Svcctl::DELETE_SERVICE
|
58
60
|
string :default
|
59
61
|
end
|
60
62
|
choice 'Samr', selection: -> { opnum } do
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Svcctl
|
4
|
+
|
5
|
+
# [3.1.4.12 RCreateServiceW (Opnum 12)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6a8ca926-9477-4dd4-b766-692fab07227e)
|
6
|
+
class CreateServiceWRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sc_rpc_handle :h_sc_object
|
12
|
+
ndr_conf_var_wide_stringz :lp_service_name
|
13
|
+
ndr_wide_stringz_ptr :lp_display_name
|
14
|
+
ndr_uint32 :dw_desired_access
|
15
|
+
ndr_uint32 :dw_service_type
|
16
|
+
ndr_uint32 :dw_start_type
|
17
|
+
ndr_uint32 :dw_error_control
|
18
|
+
ndr_conf_var_wide_stringz :lp_binary_path_name
|
19
|
+
ndr_wide_stringz_ptr :lp_load_order_group
|
20
|
+
ndr_uint32_ptr :lp_dw_tag_id
|
21
|
+
svcctl_byte_array_ptr :lp_dependencies, type: :ndr_uint8
|
22
|
+
ndr_uint32 :dw_depend_size, initial_value: -> { lp_dependencies.size }
|
23
|
+
ndr_wide_stringz_ptr :lp_service_start_name
|
24
|
+
svcctl_byte_array_ptr :lp_password, type: :ndr_uint8
|
25
|
+
ndr_uint32 :dw_pw_size, initial_value: -> { lp_password.size }
|
26
|
+
|
27
|
+
def initialize_instance
|
28
|
+
super
|
29
|
+
@opnum = CREATE_SERVICE_W
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Svcctl
|
4
|
+
|
5
|
+
# [3.1.4.12 RCreateServiceW (Opnum 12)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6a8ca926-9477-4dd4-b766-692fab07227e)
|
6
|
+
class CreateServiceWResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
ndr_uint32_ptr :lp_dw_tag_id
|
12
|
+
sc_rpc_handle :lp_sc_handle
|
13
|
+
ndr_uint32 :error_status
|
14
|
+
|
15
|
+
def initialize_instance
|
16
|
+
super
|
17
|
+
@opnum = CREATE_SERVICE_W
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Svcctl
|
4
|
+
|
5
|
+
# [3.1.4.2 RDeleteService (Opnum 2)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6744cdb8-f162-4be0-bb31-98996b6495be)
|
6
|
+
class DeleteServiceRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sc_rpc_handle :lp_sc_handle
|
12
|
+
|
13
|
+
def initialize_instance
|
14
|
+
super
|
15
|
+
@opnum = DELETE_SERVICE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Svcctl
|
4
|
+
|
5
|
+
# [3.1.4.2 RDeleteService (Opnum 2)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/6744cdb8-f162-4be0-bb31-98996b6495be)
|
6
|
+
class DeleteServiceResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
ndr_uint32 :error_status
|
12
|
+
|
13
|
+
def initialize_instance
|
14
|
+
super
|
15
|
+
@opnum = DELETE_SERVICE
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -9,8 +9,10 @@ module RubySMB
|
|
9
9
|
# Operation numbers
|
10
10
|
CLOSE_SERVICE_HANDLE = 0x0000
|
11
11
|
CONTROL_SERVICE = 0x0001
|
12
|
+
DELETE_SERVICE = 0x0002
|
12
13
|
QUERY_SERVICE_STATUS = 0x0006
|
13
14
|
CHANGE_SERVICE_CONFIG_W = 0x000B
|
15
|
+
CREATE_SERVICE_W = 0x000C
|
14
16
|
OPEN_SC_MANAGER_W = 0x000F
|
15
17
|
OPEN_SERVICE_W = 0x0010
|
16
18
|
QUERY_SERVICE_CONFIG_W = 0x0011
|
@@ -19,6 +21,10 @@ module RubySMB
|
|
19
21
|
|
20
22
|
class ScRpcHandle < Ndr::NdrContextHandle; end
|
21
23
|
|
24
|
+
class SvcctlByteArrayPtr < Ndr::NdrConfArray
|
25
|
+
default_parameters type: :ndr_uint8
|
26
|
+
extend Ndr::PointerClassPlugin
|
27
|
+
end
|
22
28
|
|
23
29
|
#################################
|
24
30
|
# Constants #
|
@@ -254,10 +260,14 @@ module RubySMB
|
|
254
260
|
require 'ruby_smb/dcerpc/svcctl/open_service_w_response'
|
255
261
|
require 'ruby_smb/dcerpc/svcctl/query_service_status_request'
|
256
262
|
require 'ruby_smb/dcerpc/svcctl/query_service_status_response'
|
263
|
+
require 'ruby_smb/dcerpc/svcctl/delete_service_request'
|
264
|
+
require 'ruby_smb/dcerpc/svcctl/delete_service_response'
|
257
265
|
require 'ruby_smb/dcerpc/svcctl/query_service_config_w_request'
|
258
266
|
require 'ruby_smb/dcerpc/svcctl/query_service_config_w_response'
|
259
267
|
require 'ruby_smb/dcerpc/svcctl/change_service_config_w_request'
|
260
268
|
require 'ruby_smb/dcerpc/svcctl/change_service_config_w_response'
|
269
|
+
require 'ruby_smb/dcerpc/svcctl/create_service_w_request'
|
270
|
+
require 'ruby_smb/dcerpc/svcctl/create_service_w_response'
|
261
271
|
require 'ruby_smb/dcerpc/svcctl/start_service_w_request'
|
262
272
|
require 'ruby_smb/dcerpc/svcctl/start_service_w_response'
|
263
273
|
require 'ruby_smb/dcerpc/svcctl/control_service_request'
|
@@ -289,10 +299,41 @@ module RubySMB
|
|
289
299
|
open_sc_manager_w_response.lp_sc_handle
|
290
300
|
end
|
291
301
|
|
302
|
+
# Creates an RPC context handle to a new service record.
|
303
|
+
#
|
304
|
+
# @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the SCM database
|
305
|
+
# @param service_name [String] the ServiceName of the service record
|
306
|
+
# @param display_name [String] the DisplayName of the service record
|
307
|
+
# @param binary_path_name [String] the BinaryPathName of the service record
|
308
|
+
# @return [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the created service record
|
309
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CreateServiceWResponse packet
|
310
|
+
# @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
|
311
|
+
def create_service_w(scm_handle, service_name, display_name, binary_path_name)
|
312
|
+
create_service_w_request = CreateServiceWRequest.new(dw_desired_access: SERVICE_ALL_ACCESS)
|
313
|
+
create_service_w_request.dw_service_type = SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS
|
314
|
+
create_service_w_request.dw_start_type = SERVICE_DEMAND_START
|
315
|
+
create_service_w_request.h_sc_object = scm_handle
|
316
|
+
create_service_w_request.lp_service_name = service_name
|
317
|
+
create_service_w_request.lp_display_name = display_name
|
318
|
+
create_service_w_request.lp_binary_path_name = binary_path_name
|
319
|
+
response = dcerpc_request(create_service_w_request)
|
320
|
+
begin
|
321
|
+
create_service_w_response = CreateServiceWResponse.read(response)
|
322
|
+
rescue IOError
|
323
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading CreateServiceWResponse'
|
324
|
+
end
|
325
|
+
unless create_service_w_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
326
|
+
raise RubySMB::Dcerpc::Error::SvcctlError,
|
327
|
+
"Error returned when creating #{service_name} service: "\
|
328
|
+
"#{WindowsError::Win32.find_by_retval(create_service_w_response.error_status.value).join(',')}"
|
329
|
+
end
|
330
|
+
create_service_w_response.lp_sc_handle
|
331
|
+
end
|
332
|
+
|
292
333
|
# Creates an RPC context handle to an existing service record.
|
293
334
|
#
|
294
335
|
# @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the SCM database
|
295
|
-
# @param service_name [
|
336
|
+
# @param service_name [String] the ServiceName of the service record
|
296
337
|
# @param access [Integer] access right
|
297
338
|
# @return [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the found service record
|
298
339
|
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenServiceWResponse packet
|
@@ -303,16 +344,16 @@ module RubySMB
|
|
303
344
|
open_service_w_request.lp_service_name = service_name
|
304
345
|
response = dcerpc_request(open_service_w_request)
|
305
346
|
begin
|
306
|
-
|
347
|
+
open_service_w_response = OpenServiceWResponse.read(response)
|
307
348
|
rescue IOError
|
308
349
|
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading OpenServiceWResponse'
|
309
350
|
end
|
310
|
-
unless
|
351
|
+
unless open_service_w_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
311
352
|
raise RubySMB::Dcerpc::Error::SvcctlError,
|
312
353
|
"Error returned when opening #{service_name} service: "\
|
313
|
-
"#{WindowsError::Win32.find_by_retval(
|
354
|
+
"#{WindowsError::Win32.find_by_retval(open_service_w_response.error_status.value).join(',')}"
|
314
355
|
end
|
315
|
-
|
356
|
+
open_service_w_response.lp_sc_handle
|
316
357
|
end
|
317
358
|
|
318
359
|
# Returns the current status of the specified service
|
@@ -472,6 +513,26 @@ module RubySMB
|
|
472
513
|
"#{WindowsError::Win32.find_by_retval(csh_response.error_status.value).join(',')}"
|
473
514
|
end
|
474
515
|
end
|
516
|
+
|
517
|
+
# Deletes the specified service
|
518
|
+
#
|
519
|
+
# @param scm_handle [RubySMB::Dcerpc::Svcctl::ScRpcHandle] handle to the service record
|
520
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a DeleteServiceResponse packet
|
521
|
+
# @raise [RubySMB::Dcerpc::Error::SvcctlError] if the response error status is not ERROR_SUCCESS
|
522
|
+
def delete_service(svc_handle)
|
523
|
+
ds_request = DeleteServiceRequest.new(lp_sc_handle: svc_handle)
|
524
|
+
response = dcerpc_request(ds_request)
|
525
|
+
begin
|
526
|
+
ds_response = DeleteServiceResponse.read(response)
|
527
|
+
rescue IOError
|
528
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading DeleteServiceResponse'
|
529
|
+
end
|
530
|
+
unless ds_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
531
|
+
raise RubySMB::Dcerpc::Error::SvcctlError,
|
532
|
+
"Error returned when deleting the service: "\
|
533
|
+
"#{WindowsError::Win32.find_by_retval(ds_response.error_status.value).join(',')}"
|
534
|
+
end
|
535
|
+
end
|
475
536
|
end
|
476
537
|
end
|
477
538
|
end
|
@@ -33,7 +33,7 @@ module RubySMB
|
|
33
33
|
super
|
34
34
|
@opnum = get_parameter(:opnum) if has_parameter?(:opnum)
|
35
35
|
self.server_name = :null
|
36
|
-
self.sam_desired.
|
36
|
+
self.sam_desired.maximum_allowed = 1 unless [OPEN_HKPD, OPEN_HKPT, OPEN_HKPN].include?(@opnum)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -33,7 +33,7 @@ module RubySMB
|
|
33
33
|
bit1 :generic_execute, label: 'Generic Execute'
|
34
34
|
bit1 :generic_all, label: 'Generic All'
|
35
35
|
bit2 :reserved4, label: 'Reserved Space'
|
36
|
-
bit1 :
|
36
|
+
bit1 :maximum_allowed, label: 'Maximum Allowed'
|
37
37
|
bit1 :system_security, label: 'System Security'
|
38
38
|
end
|
39
39
|
|
@@ -274,7 +274,7 @@ module RubySMB
|
|
274
274
|
lp_sub_key: sub_key,
|
275
275
|
lp_class: opts[:lp_class] || :null,
|
276
276
|
dw_options: opts[:dw_options] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
|
277
|
-
sam_desired: opts[:sam_desired] || RubySMB::Dcerpc::Winreg::Regsam.new(
|
277
|
+
sam_desired: opts[:sam_desired] || RubySMB::Dcerpc::Winreg::Regsam.new(maximum_allowed: 1),
|
278
278
|
lp_security_attributes: opts[:lp_security_attributes] || RubySMB::Dcerpc::RpcSecurityAttributes.new,
|
279
279
|
lpdw_disposition: opts[:lpdw_disposition] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY,
|
280
280
|
}
|
@@ -13,6 +13,7 @@ module RubySMB
|
|
13
13
|
@user_id = user_id
|
14
14
|
@state = state
|
15
15
|
@signing_required = false
|
16
|
+
@metadata = {}
|
16
17
|
# tree id => provider processor instance
|
17
18
|
@tree_connect_table = {}
|
18
19
|
@creation_time = Time.now
|
@@ -62,6 +63,11 @@ module RubySMB
|
|
62
63
|
# @return [Hash]
|
63
64
|
attr_accessor :tree_connect_table
|
64
65
|
|
66
|
+
# Untyped hash for storing additional arbitrary metadata about the current session
|
67
|
+
# @!attribute [rw] metadaa
|
68
|
+
# @return [Hash]
|
69
|
+
attr_accessor :metadata
|
70
|
+
|
65
71
|
# The time at which this session was created.
|
66
72
|
# @!attribute [r] creation_time
|
67
73
|
# @return [Time]
|
@@ -30,7 +30,7 @@ module RubySMB
|
|
30
30
|
bit1 :generic_execute, label: 'Generic Execute'
|
31
31
|
bit1 :generic_all, label: 'Generic All'
|
32
32
|
bit2 :reserved3
|
33
|
-
bit1 :
|
33
|
+
bit1 :maximum_allowed, label: 'Maximum Allowed'
|
34
34
|
bit1 :system_security, label: 'System Security'
|
35
35
|
end
|
36
36
|
end
|
@@ -30,7 +30,7 @@ module RubySMB
|
|
30
30
|
bit1 :generic_execute, label: 'Generic Execute'
|
31
31
|
bit1 :generic_all, label: 'Generic All'
|
32
32
|
bit2 :reserved3
|
33
|
-
bit1 :
|
33
|
+
bit1 :maximum_allowed, label: 'Maximum Allowed'
|
34
34
|
bit1 :system_security, label: 'System Security'
|
35
35
|
end
|
36
36
|
end
|
@@ -30,7 +30,7 @@ module RubySMB
|
|
30
30
|
bit1 :generic_execute, label: 'Generic Execute'
|
31
31
|
bit1 :generic_all, label: 'Generic All'
|
32
32
|
bit2 :reserved3
|
33
|
-
bit1 :
|
33
|
+
bit1 :maximum_allowed, label: 'Maximum Allowed'
|
34
34
|
bit1 :system_security, label: 'System Security'
|
35
35
|
end
|
36
36
|
end
|
@@ -30,7 +30,7 @@ module RubySMB
|
|
30
30
|
bit1 :generic_execute, label: 'Generic Execute'
|
31
31
|
bit1 :generic_all, label: 'Generic All'
|
32
32
|
bit2 :reserved3
|
33
|
-
bit1 :
|
33
|
+
bit1 :maximum_allowed, label: 'Maximum Allowed'
|
34
34
|
bit1 :system_security, label: 'System Security'
|
35
35
|
end
|
36
36
|
end
|
@@ -18,6 +18,17 @@ module RubySMB
|
|
18
18
|
uint64 :previous_session_id, label: 'Previous Session ID'
|
19
19
|
string :buffer, label: 'Security Buffer', length: -> { security_buffer_length }
|
20
20
|
|
21
|
+
# Takes the specified security buffer string and inserts it into the {RubySMB::SMB2::Packet::SessionSetupRequest#buffer}
|
22
|
+
# as well as updating the {RubySMB::SMB2::Packet::SessionSetupRequest#security_buffer_length}
|
23
|
+
# This method DOES NOT wrap the security buffer in any way.
|
24
|
+
#
|
25
|
+
# @param buffer [String] the security buffer
|
26
|
+
# @return [void]
|
27
|
+
def set_security_buffer(buffer)
|
28
|
+
self.security_buffer_length = buffer.length
|
29
|
+
self.buffer = buffer
|
30
|
+
end
|
31
|
+
|
21
32
|
# Takes a serialized NTLM Type 1 message and wraps it in the GSS ASN1 encoding
|
22
33
|
# and inserts it into the {RubySMB::SMB2::Packet::SessionSetupRequest#buffer}
|
23
34
|
# as well as updating the {RubySMB::SMB2::Packet::SessionSetupRequest#security_buffer_length}
|
data/lib/ruby_smb/version.rb
CHANGED
data/ruby_smb.gemspec
CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_development_dependency 'yard'
|
35
35
|
|
36
36
|
spec.add_runtime_dependency 'rubyntlm'
|
37
|
-
spec.add_runtime_dependency 'windows_error', '>= 0.1.
|
37
|
+
spec.add_runtime_dependency 'windows_error', '>= 0.1.4'
|
38
38
|
spec.add_runtime_dependency 'bindata'
|
39
39
|
spec.add_runtime_dependency 'openssl-ccm'
|
40
40
|
spec.add_runtime_dependency 'openssl-cmac'
|
@@ -557,6 +557,16 @@ RSpec.describe RubySMB::Client do
|
|
557
557
|
end
|
558
558
|
end
|
559
559
|
|
560
|
+
describe '#wipe_state!' do
|
561
|
+
context 'with SMB1' do
|
562
|
+
it { expect { smb1_client.wipe_state! }.to_not raise_error }
|
563
|
+
end
|
564
|
+
|
565
|
+
context 'with SMB2' do
|
566
|
+
it { expect { smb2_client.wipe_state! }.to_not raise_error }
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
560
570
|
describe '#logoff!' do
|
561
571
|
context 'with SMB1' do
|
562
572
|
let(:raw_response) { double('Raw response') }
|
@@ -0,0 +1,143 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::CreateServiceWRequest do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :h_sc_object }
|
5
|
+
it { is_expected.to respond_to :lp_service_name }
|
6
|
+
it { is_expected.to respond_to :lp_display_name }
|
7
|
+
it { is_expected.to respond_to :dw_desired_access }
|
8
|
+
it { is_expected.to respond_to :dw_service_type }
|
9
|
+
it { is_expected.to respond_to :dw_start_type }
|
10
|
+
it { is_expected.to respond_to :dw_error_control }
|
11
|
+
it { is_expected.to respond_to :lp_binary_path_name }
|
12
|
+
it { is_expected.to respond_to :lp_load_order_group }
|
13
|
+
it { is_expected.to respond_to :lp_dw_tag_id }
|
14
|
+
it { is_expected.to respond_to :lp_dependencies }
|
15
|
+
it { is_expected.to respond_to :dw_depend_size }
|
16
|
+
it { is_expected.to respond_to :lp_service_start_name }
|
17
|
+
it { is_expected.to respond_to :lp_password }
|
18
|
+
it { is_expected.to respond_to :dw_pw_size }
|
19
|
+
|
20
|
+
it 'is little endian' do
|
21
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
describe '#h_sc_object' do
|
26
|
+
it 'is a ScRpcHandle structure' do
|
27
|
+
expect(packet.h_sc_object).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#lp_service_name' do
|
32
|
+
it 'is a NdrConfVarWideStringz structure' do
|
33
|
+
expect(packet.lp_service_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#lp_display_name' do
|
38
|
+
it 'is a NdrWideStringzPtr structure' do
|
39
|
+
expect(packet.lp_display_name).to be_a RubySMB::Dcerpc::Ndr::NdrWideStringzPtr
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#dw_desired_access' do
|
44
|
+
it 'is a NdrUint32' do
|
45
|
+
expect(packet.dw_desired_access).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#dw_service_type' do
|
50
|
+
it 'is a NdrUint32' do
|
51
|
+
expect(packet.dw_service_type).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#dw_start_type' do
|
56
|
+
it 'is a NdrUint32' do
|
57
|
+
expect(packet.dw_start_type).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#dw_error_control' do
|
62
|
+
it 'is a NdrUint32' do
|
63
|
+
expect(packet.dw_error_control).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#lp_binary_path_name' do
|
68
|
+
it 'is a NdrConfVarWideStringz structure' do
|
69
|
+
expect(packet.lp_binary_path_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#lp_load_order_group' do
|
74
|
+
it 'is a NdrWideStringzPtr structure' do
|
75
|
+
expect(packet.lp_load_order_group).to be_a RubySMB::Dcerpc::Ndr::NdrWideStringzPtr
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#lp_dw_tag_id' do
|
80
|
+
it 'is a NdrUint32Ptr' do
|
81
|
+
expect(packet.lp_dw_tag_id).to be_a RubySMB::Dcerpc::Ndr::NdrUint32Ptr
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#lp_dependencies' do
|
86
|
+
it 'is a SvcctlByteArrayPtr structure' do
|
87
|
+
expect(packet.lp_dependencies).to be_a RubySMB::Dcerpc::Svcctl::SvcctlByteArrayPtr
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe '#dw_depend_size' do
|
92
|
+
it 'is a NdrUint32' do
|
93
|
+
expect(packet.dw_depend_size).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#lp_service_start_name' do
|
98
|
+
it 'is a NdrWideStringzPtr structure' do
|
99
|
+
expect(packet.lp_service_start_name).to be_a RubySMB::Dcerpc::Ndr::NdrWideStringzPtr
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#lp_password' do
|
104
|
+
it 'is a SvcctlByteArrayPtr structure' do
|
105
|
+
expect(packet.lp_password).to be_a RubySMB::Dcerpc::Svcctl::SvcctlByteArrayPtr
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#dw_pw_size' do
|
110
|
+
it 'is a NdrUint32' do
|
111
|
+
expect(packet.dw_pw_size).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should keep #dw_desired_access 4-byte aligned' do
|
116
|
+
5.times do |i1|
|
117
|
+
5.times do |i2|
|
118
|
+
packet.lp_service_name = "A" * i1
|
119
|
+
packet.lp_display_name = "B" * i2
|
120
|
+
expect(packet.dw_desired_access.abs_offset % 4).to eq 0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#initialize_instance' do
|
126
|
+
it 'sets #opnum to CREATE_SERVICE_W constant' do
|
127
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::CREATE_SERVICE_W)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'reads its own binary representation and outputs the same packet' do
|
132
|
+
packet = described_class.new(
|
133
|
+
h_sc_object: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'},
|
134
|
+
lp_service_name: 'test',
|
135
|
+
lp_display_name: 'Test',
|
136
|
+
dw_desired_access: 3,
|
137
|
+
lp_binary_path_name: 'test',
|
138
|
+
lp_password: 'test'.bytes
|
139
|
+
)
|
140
|
+
binary = packet.to_binary_s
|
141
|
+
expect(described_class.read(binary)).to eq(packet)
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::CreateServiceWResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :lp_dw_tag_id }
|
5
|
+
it { is_expected.to respond_to :lp_sc_handle }
|
6
|
+
it { is_expected.to respond_to :error_status }
|
7
|
+
|
8
|
+
it 'is little endian' do
|
9
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#lp_dw_tag_id' do
|
13
|
+
it 'is a NdrUint32Ptr' do
|
14
|
+
expect(packet.lp_dw_tag_id).to be_a RubySMB::Dcerpc::Ndr::NdrUint32Ptr
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#lp_sc_handle' do
|
19
|
+
it 'is a ScRpcHandle structure' do
|
20
|
+
expect(packet.lp_sc_handle).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#error_status' do
|
25
|
+
it 'is a NdrUint32' do
|
26
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#initialize_instance' do
|
31
|
+
it 'sets #opnum to CREATE_SERVICE_W constant' do
|
32
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::CREATE_SERVICE_W)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'reads its own binary representation and outputs the same packet' do
|
37
|
+
packet = described_class.new(
|
38
|
+
lp_dw_tag_id: 3,
|
39
|
+
lp_sc_handle: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'},
|
40
|
+
error_status: 3
|
41
|
+
)
|
42
|
+
binary = packet.to_binary_s
|
43
|
+
expect(described_class.read(binary)).to eq(packet)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::DeleteServiceRequest do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :lp_sc_handle }
|
5
|
+
|
6
|
+
it 'is little endian' do
|
7
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#lp_sc_handle' do
|
11
|
+
it 'is a ScRpcHandle structure' do
|
12
|
+
expect(packet.lp_sc_handle).to be_a RubySMB::Dcerpc::Svcctl::ScRpcHandle
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#initialize_instance' do
|
17
|
+
it 'sets #opnum to DELETE_SERVICE constant' do
|
18
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::DELETE_SERVICE)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'reads its own binary representation and outputs the same packet' do
|
23
|
+
packet = described_class.new(
|
24
|
+
lp_sc_handle: {context_handle_attributes: 0, context_handle_uuid: '367abb81-9844-35f1-ad32-98f038001003'}
|
25
|
+
)
|
26
|
+
binary = packet.to_binary_s
|
27
|
+
expect(described_class.read(binary)).to eq(packet)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::Svcctl::DeleteServiceResponse do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :error_status }
|
5
|
+
|
6
|
+
it 'is little endian' do
|
7
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#error_status' do
|
11
|
+
it 'is a NdrUint32' do
|
12
|
+
expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#initialize_instance' do
|
17
|
+
it 'sets #opnum to DELETE_SERVICE constant' do
|
18
|
+
expect(packet.opnum).to eq(RubySMB::Dcerpc::Svcctl::DELETE_SERVICE)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'reads its own binary representation and outputs the same packet' do
|
23
|
+
packet = described_class.new(
|
24
|
+
error_status: 3
|
25
|
+
)
|
26
|
+
binary = packet.to_binary_s
|
27
|
+
expect(described_class.read(binary)).to eq(packet)
|
28
|
+
end
|
29
|
+
end
|
@@ -57,30 +57,30 @@ RSpec.describe RubySMB::Dcerpc::Winreg::OpenRootKeyRequest do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
context 'when #opnum is not OPEN_HKPD, OPEN_HKPT or OPEN_HKPN' do
|
60
|
-
it 'sets the #sam_desired.
|
60
|
+
it 'sets the #sam_desired.maximum_allowed flag' do
|
61
61
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKCR)
|
62
|
-
expect(packet.sam_desired.
|
62
|
+
expect(packet.sam_desired.maximum_allowed).to eq(1)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
66
|
context 'when #opnum is OPEN_HKPD' do
|
67
|
-
it 'does not set the #sam_desired.
|
67
|
+
it 'does not set the #sam_desired.maximum_allowed flag' do
|
68
68
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKPD)
|
69
|
-
expect(packet.sam_desired.
|
69
|
+
expect(packet.sam_desired.maximum_allowed).to eq(0)
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
context 'when #opnum is OPEN_HKPT' do
|
74
|
-
it 'does not set the #sam_desired.
|
74
|
+
it 'does not set the #sam_desired.maximum_allowed flag' do
|
75
75
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKPT)
|
76
|
-
expect(packet.sam_desired.
|
76
|
+
expect(packet.sam_desired.maximum_allowed).to eq(0)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
80
|
context 'when #opnum is OPEN_HKPN' do
|
81
|
-
it 'does not set the #sam_desired.
|
81
|
+
it 'does not set the #sam_desired.maximum_allowed flag' do
|
82
82
|
packet = described_class.new(opnum: RubySMB::Dcerpc::Winreg::OPEN_HKPN)
|
83
|
-
expect(packet.sam_desired.
|
83
|
+
expect(packet.sam_desired.maximum_allowed).to eq(0)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
@@ -22,7 +22,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg::Regsam do
|
|
22
22
|
it { is_expected.to respond_to :generic_execute }
|
23
23
|
it { is_expected.to respond_to :generic_all }
|
24
24
|
it { is_expected.to respond_to :reserved4 }
|
25
|
-
it { is_expected.to respond_to :
|
25
|
+
it { is_expected.to respond_to :maximum_allowed }
|
26
26
|
it { is_expected.to respond_to :system_security }
|
27
27
|
|
28
28
|
|
@@ -755,7 +755,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
|
|
755
755
|
lp_sub_key: sub_key,
|
756
756
|
lp_class: :null,
|
757
757
|
dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
|
758
|
-
sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(
|
758
|
+
sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(maximum_allowed: 1),
|
759
759
|
lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
|
760
760
|
lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY
|
761
761
|
}
|
@@ -19,7 +19,7 @@ RSpec.describe RubySMB::SMB1::BitField::DirectoryAccessMask do
|
|
19
19
|
it { is_expected.to respond_to :generic_write }
|
20
20
|
it { is_expected.to respond_to :generic_execute }
|
21
21
|
it { is_expected.to respond_to :generic_all }
|
22
|
-
it { is_expected.to respond_to :
|
22
|
+
it { is_expected.to respond_to :maximum_allowed }
|
23
23
|
it { is_expected.to respond_to :system_security }
|
24
24
|
|
25
25
|
it 'is little endian' do
|
@@ -146,12 +146,12 @@ RSpec.describe RubySMB::SMB1::BitField::DirectoryAccessMask do
|
|
146
146
|
it_behaves_like 'bit field with one flag set', :system_security, 'V', 0x01000000
|
147
147
|
end
|
148
148
|
|
149
|
-
describe '#
|
149
|
+
describe '#maximum_allowed' do
|
150
150
|
it 'should be a 1-bit field per the SMB spec' do
|
151
|
-
expect(flags.
|
151
|
+
expect(flags.maximum_allowed).to be_a BinData::Bit1
|
152
152
|
end
|
153
153
|
|
154
|
-
it_behaves_like 'bit field with one flag set', :
|
154
|
+
it_behaves_like 'bit field with one flag set', :maximum_allowed, 'V', 0x02000000
|
155
155
|
end
|
156
156
|
|
157
157
|
describe '#generic_all' do
|
@@ -19,7 +19,7 @@ RSpec.describe RubySMB::SMB1::BitField::FileAccessMask do
|
|
19
19
|
it { is_expected.to respond_to :generic_write }
|
20
20
|
it { is_expected.to respond_to :generic_execute }
|
21
21
|
it { is_expected.to respond_to :generic_all }
|
22
|
-
it { is_expected.to respond_to :
|
22
|
+
it { is_expected.to respond_to :maximum_allowed }
|
23
23
|
it { is_expected.to respond_to :system_security }
|
24
24
|
|
25
25
|
it 'is little endian' do
|
@@ -146,12 +146,12 @@ RSpec.describe RubySMB::SMB1::BitField::FileAccessMask do
|
|
146
146
|
it_behaves_like 'bit field with one flag set', :system_security, 'V', 0x01000000
|
147
147
|
end
|
148
148
|
|
149
|
-
describe '#
|
149
|
+
describe '#maximum_allowed' do
|
150
150
|
it 'should be a 1-bit field per the SMB spec' do
|
151
|
-
expect(flags.
|
151
|
+
expect(flags.maximum_allowed).to be_a BinData::Bit1
|
152
152
|
end
|
153
153
|
|
154
|
-
it_behaves_like 'bit field with one flag set', :
|
154
|
+
it_behaves_like 'bit field with one flag set', :maximum_allowed, 'V', 0x02000000
|
155
155
|
end
|
156
156
|
|
157
157
|
describe '#generic_all' do
|
@@ -118,6 +118,11 @@ RSpec.describe RubySMB::SMB1::Tree do
|
|
118
118
|
end
|
119
119
|
tree.open_file(filename: unicode_filename.chop)
|
120
120
|
end
|
121
|
+
|
122
|
+
it 'removes the leading \\ from the filename if needed' do
|
123
|
+
expect(tree).to receive(:_open).with(filename: filename)
|
124
|
+
tree.open_file(filename: '\\' + filename)
|
125
|
+
end
|
121
126
|
end
|
122
127
|
|
123
128
|
describe 'flags' do
|
@@ -19,7 +19,7 @@ RSpec.describe RubySMB::SMB2::BitField::DirectoryAccessMask do
|
|
19
19
|
it { is_expected.to respond_to :generic_write }
|
20
20
|
it { is_expected.to respond_to :generic_execute }
|
21
21
|
it { is_expected.to respond_to :generic_all }
|
22
|
-
it { is_expected.to respond_to :
|
22
|
+
it { is_expected.to respond_to :maximum_allowed }
|
23
23
|
it { is_expected.to respond_to :system_security }
|
24
24
|
|
25
25
|
it 'is little endian' do
|
@@ -146,12 +146,12 @@ RSpec.describe RubySMB::SMB2::BitField::DirectoryAccessMask do
|
|
146
146
|
it_behaves_like 'bit field with one flag set', :system_security, 'V', 0x01000000
|
147
147
|
end
|
148
148
|
|
149
|
-
describe '#
|
149
|
+
describe '#maximum_allowed' do
|
150
150
|
it 'should be a 1-bit field per the SMB spec' do
|
151
|
-
expect(flags.
|
151
|
+
expect(flags.maximum_allowed).to be_a BinData::Bit1
|
152
152
|
end
|
153
153
|
|
154
|
-
it_behaves_like 'bit field with one flag set', :
|
154
|
+
it_behaves_like 'bit field with one flag set', :maximum_allowed, 'V', 0x02000000
|
155
155
|
end
|
156
156
|
|
157
157
|
describe '#generic_all' do
|
@@ -19,7 +19,7 @@ RSpec.describe RubySMB::SMB2::BitField::FileAccessMask do
|
|
19
19
|
it { is_expected.to respond_to :generic_write }
|
20
20
|
it { is_expected.to respond_to :generic_execute }
|
21
21
|
it { is_expected.to respond_to :generic_all }
|
22
|
-
it { is_expected.to respond_to :
|
22
|
+
it { is_expected.to respond_to :maximum_allowed }
|
23
23
|
it { is_expected.to respond_to :system_security }
|
24
24
|
|
25
25
|
it 'is little endian' do
|
@@ -146,12 +146,12 @@ RSpec.describe RubySMB::SMB2::BitField::FileAccessMask do
|
|
146
146
|
it_behaves_like 'bit field with one flag set', :system_security, 'V', 0x01000000
|
147
147
|
end
|
148
148
|
|
149
|
-
describe '#
|
149
|
+
describe '#maximum_allowed' do
|
150
150
|
it 'should be a 1-bit field per the SMB spec' do
|
151
|
-
expect(flags.
|
151
|
+
expect(flags.maximum_allowed).to be_a BinData::Bit1
|
152
152
|
end
|
153
153
|
|
154
|
-
it_behaves_like 'bit field with one flag set', :
|
154
|
+
it_behaves_like 'bit field with one flag set', :maximum_allowed, 'V', 0x02000000
|
155
155
|
end
|
156
156
|
|
157
157
|
describe '#generic_all' do
|
@@ -348,6 +348,11 @@ RSpec.describe RubySMB::SMB2::Tree do
|
|
348
348
|
end
|
349
349
|
tree.open_file(filename: filename)
|
350
350
|
end
|
351
|
+
|
352
|
+
it 'removes the leading \\ from the filename if needed' do
|
353
|
+
expect(tree).to receive(:_open).with(filename: filename)
|
354
|
+
tree.open_file(filename: "\\".encode('UTF-16LE') + filename)
|
355
|
+
end
|
351
356
|
end
|
352
357
|
|
353
358
|
describe 'attributes' do
|
@@ -544,7 +549,7 @@ RSpec.describe RubySMB::SMB2::Tree do
|
|
544
549
|
tree.open_pipe(**opts)
|
545
550
|
end
|
546
551
|
|
547
|
-
it '
|
552
|
+
it 'removes the leading \\ from the filename if needed' do
|
548
553
|
expect(tree).to receive(:_open).with(filename: 'test', write: true)
|
549
554
|
tree.open_pipe(**opts)
|
550
555
|
end
|
data/spec/spec_helper.rb
CHANGED
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.0.
|
4
|
+
version: 3.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Metasploit Hackers
|
@@ -97,7 +97,7 @@ cert_chain:
|
|
97
97
|
EknWpNgVhohbot1lfVAMmIhdtOVaRVcQQixWPwprDj/ydB8ryDMDosIMcw+fkoXU
|
98
98
|
9GJsSaSRRYQ9UUkVL27b64okU8D48m8=
|
99
99
|
-----END CERTIFICATE-----
|
100
|
-
date: 2022-
|
100
|
+
date: 2022-04-01 00:00:00.000000000 Z
|
101
101
|
dependencies:
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: redcarpet
|
@@ -189,14 +189,14 @@ dependencies:
|
|
189
189
|
requirements:
|
190
190
|
- - ">="
|
191
191
|
- !ruby/object:Gem::Version
|
192
|
-
version: 0.1.
|
192
|
+
version: 0.1.4
|
193
193
|
type: :runtime
|
194
194
|
prerelease: false
|
195
195
|
version_requirements: !ruby/object:Gem::Requirement
|
196
196
|
requirements:
|
197
197
|
- - ">="
|
198
198
|
- !ruby/object:Gem::Version
|
199
|
-
version: 0.1.
|
199
|
+
version: 0.1.4
|
200
200
|
- !ruby/object:Gem::Dependency
|
201
201
|
name: bindata
|
202
202
|
requirement: !ruby/object:Gem::Requirement
|
@@ -272,6 +272,7 @@ files:
|
|
272
272
|
- examples/negotiate_with_netbios_service.rb
|
273
273
|
- examples/net_share_enum_all.rb
|
274
274
|
- examples/pipes.rb
|
275
|
+
- examples/pwsh_service.rb
|
275
276
|
- examples/query_service_status.rb
|
276
277
|
- examples/read_file.rb
|
277
278
|
- examples/read_file_encryption.rb
|
@@ -371,6 +372,10 @@ files:
|
|
371
372
|
- lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb
|
372
373
|
- lib/ruby_smb/dcerpc/svcctl/control_service_request.rb
|
373
374
|
- lib/ruby_smb/dcerpc/svcctl/control_service_response.rb
|
375
|
+
- lib/ruby_smb/dcerpc/svcctl/create_service_w_request.rb
|
376
|
+
- lib/ruby_smb/dcerpc/svcctl/create_service_w_response.rb
|
377
|
+
- lib/ruby_smb/dcerpc/svcctl/delete_service_request.rb
|
378
|
+
- lib/ruby_smb/dcerpc/svcctl/delete_service_response.rb
|
374
379
|
- lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb
|
375
380
|
- lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb
|
376
381
|
- lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb
|
@@ -670,6 +675,10 @@ files:
|
|
670
675
|
- spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb
|
671
676
|
- spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb
|
672
677
|
- spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb
|
678
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_request_spec.rb
|
679
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_response_spec.rb
|
680
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/delete_service_request_spec.rb
|
681
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/delete_service_response_spec.rb
|
673
682
|
- spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb
|
674
683
|
- spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb
|
675
684
|
- spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb
|
@@ -950,6 +959,10 @@ test_files:
|
|
950
959
|
- spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb
|
951
960
|
- spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb
|
952
961
|
- spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb
|
962
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_request_spec.rb
|
963
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_response_spec.rb
|
964
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/delete_service_request_spec.rb
|
965
|
+
- spec/lib/ruby_smb/dcerpc/svcctl/delete_service_response_spec.rb
|
953
966
|
- spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb
|
954
967
|
- spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb
|
955
968
|
- spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb
|
metadata.gz.sig
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
�������;���'��L�Y�^w%�!���"*�������
|
2
|
+
�J��u�l�lź�$�_��7B`pdɰ�4��ӓ�/Ë��I���.��o��#S�v�f�o�=I�w�8ڳ�Vv�]�˃��u��2��~�x����jj�`���l?'B����Ip��E�?�^����GW�����Yq�^'Ӷ���y{P��y����K&K&��8�<��Q�^��p�kS��F1�G�t"�瓺evoc.����
|