ruby_smb 3.0.5 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -3
  3. data/.github/workflows/verify.yml +1 -1
  4. data/.simplecov +1 -1
  5. data/CONTRIBUTING.md +28 -3
  6. data/README.md +8 -0
  7. data/examples/pwsh_service.rb +112 -0
  8. data/lib/ruby_smb/client/encryption.rb +16 -4
  9. data/lib/ruby_smb/client/negotiation.rb +10 -8
  10. data/lib/ruby_smb/dcerpc/request.rb +2 -0
  11. data/lib/ruby_smb/dcerpc/svcctl/create_service_w_request.rb +35 -0
  12. data/lib/ruby_smb/dcerpc/svcctl/create_service_w_response.rb +24 -0
  13. data/lib/ruby_smb/dcerpc/svcctl/delete_service_request.rb +21 -0
  14. data/lib/ruby_smb/dcerpc/svcctl/delete_service_response.rb +21 -0
  15. data/lib/ruby_smb/dcerpc/svcctl.rb +66 -5
  16. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +1 -1
  17. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +1 -1
  18. data/lib/ruby_smb/dcerpc/winreg.rb +1 -1
  19. data/lib/ruby_smb/fscc/file_information.rb +4 -0
  20. data/lib/ruby_smb/gss/provider/ntlm.rb +4 -0
  21. data/lib/ruby_smb/server/server_client/encryption.rb +66 -0
  22. data/lib/ruby_smb/server/server_client/negotiation.rb +14 -3
  23. data/lib/ruby_smb/server/server_client/session_setup.rb +18 -3
  24. data/lib/ruby_smb/server/server_client/share_io.rb +17 -0
  25. data/lib/ruby_smb/server/server_client/tree_connect.rb +40 -3
  26. data/lib/ruby_smb/server/server_client.rb +147 -37
  27. data/lib/ruby_smb/server/share/provider/disk/file_system.rb +28 -0
  28. data/lib/ruby_smb/server/share/provider/disk/processor/close.rb +42 -0
  29. data/lib/ruby_smb/server/share/provider/disk/processor/create.rb +143 -0
  30. data/lib/ruby_smb/server/share/provider/disk/processor/query.rb +359 -0
  31. data/lib/ruby_smb/server/share/provider/disk/processor/read.rb +69 -0
  32. data/lib/ruby_smb/server/share/provider/disk/processor.rb +159 -0
  33. data/lib/ruby_smb/server/share/provider/disk.rb +4 -416
  34. data/lib/ruby_smb/server/share/provider/pipe.rb +2 -2
  35. data/lib/ruby_smb/server/share/provider/processor.rb +16 -0
  36. data/lib/ruby_smb/signing.rb +18 -4
  37. data/lib/ruby_smb/smb1/bit_field/directory_access_mask.rb +1 -1
  38. data/lib/ruby_smb/smb1/bit_field/file_access_mask.rb +1 -1
  39. data/lib/ruby_smb/smb1/commands.rb +1 -0
  40. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +11 -1
  41. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +1 -1
  42. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +5 -4
  43. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +12 -4
  44. data/lib/ruby_smb/smb1/packet/trans2/data_block.rb +9 -1
  45. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +52 -51
  46. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +37 -37
  47. data/lib/ruby_smb/smb1/packet/trans2/find_information_level/find_file_both_directory_info.rb +48 -0
  48. data/lib/ruby_smb/smb1/packet/trans2/find_information_level.rb +28 -15
  49. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +51 -51
  50. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +36 -36
  51. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +40 -39
  52. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +40 -40
  53. data/lib/ruby_smb/smb1/packet/trans2/query_file_information_request.rb +60 -0
  54. data/lib/ruby_smb/smb1/packet/trans2/query_file_information_response.rb +59 -0
  55. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_attribute_info.rb +31 -0
  56. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +40 -0
  57. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +46 -0
  58. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response.rb +59 -0
  59. data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_basic_info.rb +23 -0
  60. data/lib/ruby_smb/smb1/packet/trans2/query_information_level/query_file_standard_info.rb +22 -0
  61. data/lib/ruby_smb/smb1/packet/trans2/query_information_level.rb +62 -0
  62. data/lib/ruby_smb/smb1/packet/trans2/query_path_information_request.rb +65 -0
  63. data/lib/ruby_smb/smb1/packet/trans2/query_path_information_response.rb +59 -0
  64. data/lib/ruby_smb/smb1/packet/trans2/request.rb +24 -8
  65. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +4 -4
  66. data/lib/ruby_smb/smb1/packet/trans2/response.rb +29 -20
  67. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +42 -42
  68. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +23 -23
  69. data/lib/ruby_smb/smb1/packet/trans2/subcommands.rb +23 -5
  70. data/lib/ruby_smb/smb1/packet/trans2.rb +4 -0
  71. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +4 -1
  72. data/lib/ruby_smb/smb2/bit_field/directory_access_mask.rb +1 -1
  73. data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +1 -1
  74. data/lib/ruby_smb/smb2/negotiate_context.rb +10 -1
  75. data/lib/ruby_smb/smb2/packet/transform_header.rb +7 -7
  76. data/lib/ruby_smb/smb2.rb +1 -0
  77. data/lib/ruby_smb/version.rb +1 -1
  78. data/ruby_smb.gemspec +1 -1
  79. data/spec/lib/ruby_smb/client_spec.rb +31 -8
  80. data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_request_spec.rb +143 -0
  81. data/spec/lib/ruby_smb/dcerpc/svcctl/create_service_w_response_spec.rb +45 -0
  82. data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_request_spec.rb +29 -0
  83. data/spec/lib/ruby_smb/dcerpc/svcctl/delete_service_response_spec.rb +29 -0
  84. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +8 -8
  85. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +1 -1
  86. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +1 -1
  87. data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +4 -4
  88. data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +4 -4
  89. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_request_spec.rb +2 -2
  90. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +36 -2
  91. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_request_spec.rb +2 -2
  92. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +35 -1
  93. data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_request_spec.rb +74 -0
  94. data/spec/lib/ruby_smb/smb1/packet/trans2/query_file_information_response_spec.rb +96 -0
  95. data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +62 -0
  96. data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_response_spec.rb +88 -0
  97. data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_request_spec.rb +79 -0
  98. data/spec/lib/ruby_smb/smb1/packet/trans2/query_path_information_response_spec.rb +96 -0
  99. data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
  100. data/spec/lib/ruby_smb/smb1/packet/trans2/response_spec.rb +3 -3
  101. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_request_spec.rb +3 -2
  102. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +7 -2
  103. data/spec/lib/ruby_smb/smb1/tree_spec.rb +3 -3
  104. data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +4 -4
  105. data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +4 -4
  106. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +2 -2
  107. data/spec/spec_helper.rb +2 -3
  108. data.tar.gz.sig +0 -0
  109. metadata +48 -4
  110. metadata.gz.sig +1 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a4881649381520e25f5f014f66baac4130dd8a58d4eadd3476198fec3fc9e8d
4
- data.tar.gz: 809b581025c19ab7ca1162a7b73d342d63b24edd77835744191a0d7c930425fd
3
+ metadata.gz: 5567054608b80da9be641c717d1d8b69e71452fb2fc67c2e390d9a6a34fb19d3
4
+ data.tar.gz: 0b439033b20bd578414e51d56d98ee4ccc4d44c60e6248bf0b8ad37a33b0fd6d
5
5
  SHA512:
6
- metadata.gz: 4e340189b0ae87ec98e7ca6bde9d4c30c1eb3a0d3e1f69383869e4803bf3d3d9bbc502cef143a83bad9f91dc1de10ca3bcd4132a8d518a1bb2121a7d4490309d
7
- data.tar.gz: 0c7198d84416da8b995e50c17f7826abba21affa03cc1c2404e2e2ecaac1322178f76c356d8d026c4a75b7e9d356bd134f1a0df12fe327eca1240b87afaeee0d
6
+ metadata.gz: 19ad76e3ed2e1902141aac772cd7908de06b402414b787e7f2371584e5cee6fc1cf82e9b80dce10ae0599082ee65a4dbd4f6c62a3c32bd3b154d47de25944b20
7
+ data.tar.gz: dd970aad2f91aec70671b7364438ee7df79908c552a6826aad99318e10fb63b6ebcad5929f131fa4284ff5531c189061a83f499203188ac919dc74e6007d422f
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1,2 @@
1
- ����IJ��%���vV
2
- �{Z���z<6�]�
3
- u��_A7��*�L)�X��N��c
1
+ ��Gӹ������ =�|)�і��c�澫W^P��&d����Lx�<����L��A 8���y(�Չ���2+�\O,�So�Gɲ�)����5ו�����L (@���Ea���ܴo��f� d!��4zn�2t�_��%9��[�?Y!�*Bﳯ���Wa���nO�c�Oz �`x�Z|n"V��d,���H���@�����V��
2
+ �|�A�C���\�~ۀ.�T)? ~\G��kG��z��� ����}'>
@@ -17,10 +17,10 @@ jobs:
17
17
  fail-fast: true
18
18
  matrix:
19
19
  ruby:
20
- - 2.5
21
20
  - 2.6
22
21
  - 2.7
23
22
  - 3.0.3
23
+ - 3.1.1
24
24
  test_cmd:
25
25
  - bundle exec rspec
26
26
 
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/smb2/fork)
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/smb2/issues) or an issue from some other
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/smb2/compare/)
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!
@@ -4,18 +4,24 @@ module RubySMB
4
4
  module Encryption
5
5
  def smb3_encrypt(data)
6
6
  unless @client_encryption_key
7
+ raise RubySMB::Error::EncryptionError.new('The encryption algorithm has not been set') if @encryption_algorithm.nil?
8
+
9
+ key_bit_len = OpenSSL::Cipher.new(@encryption_algorithm).key_len * 8
10
+
7
11
  case @dialect
8
12
  when '0x0300', '0x0302'
9
13
  @client_encryption_key = RubySMB::Crypto::KDF.counter_mode(
10
14
  @session_key,
11
15
  "SMB2AESCCM\x00",
12
- "ServerIn \x00"
16
+ "ServerIn \x00",
17
+ length: key_bit_len
13
18
  )
14
19
  when '0x0311'
15
20
  @client_encryption_key = RubySMB::Crypto::KDF.counter_mode(
16
21
  @session_key,
17
22
  "SMBC2SCipherKey\x00",
18
- @preauth_integrity_hash_value
23
+ @preauth_integrity_hash_value,
24
+ length: key_bit_len
19
25
  )
20
26
  else
21
27
  raise RubySMB::Error::EncryptionError.new('Dialect is incompatible with SMBv3 encryption')
@@ -33,18 +39,24 @@ module RubySMB
33
39
 
34
40
  def smb3_decrypt(th)
35
41
  unless @server_encryption_key
42
+ raise RubySMB::Error::EncryptionError.new('The encryption algorithm has not been set') if @encryption_algorithm.nil?
43
+
44
+ key_bit_len = OpenSSL::Cipher.new(@encryption_algorithm).key_len * 8
45
+
36
46
  case @dialect
37
47
  when '0x0300', '0x0302'
38
48
  @server_encryption_key = RubySMB::Crypto::KDF.counter_mode(
39
49
  @session_key,
40
50
  "SMB2AESCCM\x00",
41
- "ServerOut\x00"
51
+ "ServerOut\x00",
52
+ length: key_bit_len
42
53
  )
43
54
  when '0x0311'
44
55
  @server_encryption_key = RubySMB::Crypto::KDF.counter_mode(
45
56
  @session_key,
46
57
  "SMBS2CCipherKey\x00",
47
- @preauth_integrity_hash_value
58
+ @preauth_integrity_hash_value,
59
+ length: key_bit_len
48
60
  )
49
61
  else
50
62
  raise RubySMB::Error::EncryptionError.new('Dialect is incompatible with SMBv3 decryption')
@@ -5,7 +5,7 @@ module RubySMB
5
5
  module Negotiation
6
6
  # Handles the entire SMB Multi-Protocol Negotiation from the
7
7
  # Client to the Server. It sets state on the client appropriate
8
- # to the protocol and capabilites negotiated during the exchange.
8
+ # to the protocol and capabilities negotiated during the exchange.
9
9
  # It also keeps track of the negotiated dialect.
10
10
  #
11
11
  # @return [void]
@@ -23,13 +23,13 @@ module RubySMB
23
23
  update_preauth_hash(response_packet)
24
24
  end
25
25
 
26
- # If the response contains the SMB2 wildcard revision number dialect;
27
- # it indicates that the server implements SMB 2.1 or future dialect
28
- # revisions and expects the client to send a subsequent SMB2 Negotiate
29
- # request to negotiate the actual SMB 2 Protocol revision to be used.
30
- # The wildcard revision number is sent only in response to a
26
+ # If the response contains an SMB2 dialect and the request was SMB1;
27
+ # it indicates that the server supports SMB2 and wants to upgrade the
28
+ # connection. The server expects the client to send a subsequent SMB2
29
+ # Negotiate request to negotiate the actual SMB 2 Protocol revision to
30
+ # be used. The wildcard revision number is sent only in response to a
31
31
  # multi-protocol negotiate request with the "SMB 2.???" dialect string.
32
- if @dialect == '0x02ff'
32
+ if request_packet.packet_smb_version == 'SMB1' && RubySMB::Dialect[@dialect]&.order == RubySMB::Dialect::ORDER_SMB2
33
33
  self.smb2_message_id += 1
34
34
  version = negotiate
35
35
  end
@@ -265,8 +265,10 @@ module RubySMB
265
265
  nc = RubySMB::SMB2::NegotiateContext.new(
266
266
  context_type: RubySMB::SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES
267
267
  )
268
- nc.data.ciphers << RubySMB::SMB2::EncryptionCapabilities::AES_128_CCM
268
+ nc.data.ciphers << RubySMB::SMB2::EncryptionCapabilities::AES_256_GCM
269
+ nc.data.ciphers << RubySMB::SMB2::EncryptionCapabilities::AES_256_CCM
269
270
  nc.data.ciphers << RubySMB::SMB2::EncryptionCapabilities::AES_128_GCM
271
+ nc.data.ciphers << RubySMB::SMB2::EncryptionCapabilities::AES_128_CCM
270
272
  packet.add_negotiate_context(nc)
271
273
 
272
274
  nc = RubySMB::SMB2::NegotiateContext.new(
@@ -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 [Srting] the ServiceName of the service record
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
- open_sercice_w_response = OpenServiceWResponse.read(response)
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 open_sercice_w_response.error_status == WindowsError::Win32::ERROR_SUCCESS
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(open_sercice_w_response.error_status.value).join(',')}"
354
+ "#{WindowsError::Win32.find_by_retval(open_service_w_response.error_status.value).join(',')}"
314
355
  end
315
- open_sercice_w_response.lp_sc_handle
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.maximum = 1 unless [OPEN_HKPD, OPEN_HKPT, OPEN_HKPN].include?(@opnum)
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 :maximum, label: 'Maximum Allowed'
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(maximum: 1),
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
  }
@@ -65,6 +65,10 @@ module RubySMB
65
65
  # [2.2.2.3.5 Pass-through Information Level Codes](https://msdn.microsoft.com/en-us/library/ff470158.aspx)
66
66
  SMB_INFO_PASSTHROUGH = 0x03e8
67
67
 
68
+ def self.name(value)
69
+ constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
70
+ end
71
+
68
72
  # The FILE_NAME_INFORMATION type as defined in
69
73
  # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/20406fb1-605f-4629-ba9a-c67ee25f23d2
70
74
  class FileNameInformation < BinData::Record
@@ -78,6 +78,10 @@ module RubySMB
78
78
  msg.flag |= NTLM::NEGOTIATE_FLAGS.fetch(flag)
79
79
  end
80
80
 
81
+ if type1_msg.flag & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] == NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY]
82
+ msg.flag |= NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY]
83
+ end
84
+
81
85
  @server_challenge = @provider.generate_server_challenge
82
86
  msg.challenge = @server_challenge.unpack1('Q<') # 64-bit unsigned, little endian (uint64_t)
83
87
  target_info = Net::NTLM::TargetInfo.new('')