ruby_smb 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/verify.yml +8 -9
- data/README.md +1 -0
- data/cortex.yaml +15 -0
- data/examples/dump_secrets_from_sid.rb +2 -1
- data/lib/ruby_smb/client.rb +6 -4
- data/lib/ruby_smb/dcerpc/alter_context.rb +30 -0
- data/lib/ruby_smb/dcerpc/alter_context_resp.rb +42 -0
- data/lib/ruby_smb/dcerpc/bind.rb +3 -35
- data/lib/ruby_smb/dcerpc/bind_ack.rb +0 -31
- data/lib/ruby_smb/dcerpc/client.rb +10 -4
- data/lib/ruby_smb/dcerpc/drsr.rb +13 -13
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_decrypt_file_srv_request.rb +22 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_decrypt_file_srv_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_recover_agents_request.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_recover_agents_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_users_on_file_request.rb +20 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_users_on_file_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/encrypting_file_system.rb +52 -0
- data/lib/ruby_smb/dcerpc/icpr.rb +3 -2
- data/lib/ruby_smb/dcerpc/ndr.rb +148 -3
- data/lib/ruby_smb/dcerpc/p_cont_list_t.rb +37 -0
- data/lib/ruby_smb/dcerpc/p_result_list_t.rb +13 -0
- data/lib/ruby_smb/dcerpc/p_result_t.rb +15 -0
- data/lib/ruby_smb/dcerpc/port_any_t.rb +11 -0
- data/lib/ruby_smb/dcerpc/request.rb +8 -3
- data/lib/ruby_smb/dcerpc/response.rb +6 -1
- data/lib/ruby_smb/dcerpc/samr.rb +4 -2
- data/lib/ruby_smb/dcerpc.rb +165 -122
- data/lib/ruby_smb/dispatcher/socket.rb +1 -1
- data/lib/ruby_smb/field/file_time.rb +2 -2
- data/lib/ruby_smb/field/utime.rb +2 -2
- data/lib/ruby_smb/generic_packet.rb +2 -2
- data/lib/ruby_smb/gss/provider/ntlm.rb +12 -5
- data/lib/ruby_smb/ntlm/client.rb +4 -0
- data/lib/ruby_smb/ntlm/custom/string_encoder.rb +22 -0
- data/lib/ruby_smb/ntlm.rb +37 -0
- data/lib/ruby_smb/server/server_client/share_io.rb +2 -2
- data/lib/ruby_smb/server/server_client/tree_connect.rb +2 -2
- data/lib/ruby_smb/server/share/provider/disk.rb +2 -2
- data/lib/ruby_smb/server/share/provider/processor.rb +25 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk.rb +3 -3
- data/lib/ruby_smb/server/share/provider.rb +48 -1
- data/lib/ruby_smb/smb1/data_block.rb +2 -2
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/parameter_block.rb +2 -2
- data/lib/ruby_smb/smb1/pipe.rb +4 -0
- data/lib/ruby_smb/smb2/create_context.rb +5 -2
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +5 -5
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +1 -1
- data/lib/ruby_smb/smb2/pipe.rb +4 -0
- data/lib/ruby_smb/smb2/tree.rb +3 -1
- data/lib/ruby_smb/utils.rb +15 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +2 -0
- data/spec/lib/ruby_smb/client_spec.rb +4 -4
- data/spec/lib/ruby_smb/dcerpc/client_spec.rb +31 -16
- data/spec/lib/ruby_smb/dcerpc/drsr_spec.rb +4 -1
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +198 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +0 -6
- data/spec/lib/ruby_smb/dcerpc/response_spec.rb +4 -12
- data/spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb +0 -14
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/read_andx_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/write_andx_request_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb2/create_context/create_context_request_spec.rb +35 -0
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +5 -0
- data.tar.gz.sig +0 -0
- metadata +41 -86
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2f696c845250348795f67d3d5b163c65b432acdbcd01bc86d0a6cd81ddcbfc67
|
|
4
|
+
data.tar.gz: b43dcb4fa6ff4497e61329b8b5a17049a6b445fcdf5c3df61dc380960ea02b9c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8368cf1844e47161a57051d7b8dfa807b665c898153636b1baedb2211acd4685ef67c5ba167581ce84a9ec7c8c17e812d1f876bb70f34b647bb075bb94861349
|
|
7
|
+
data.tar.gz: 3b33a185fb3b981147b005e13793aa1f8a09e11c2e5e0dc9b75469ef980ec019bc2dd5e9bef187910f9b5be012d7ca710799b45aa0bdf79547ae3d48de8e22e7
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
|
@@ -33,17 +33,16 @@ jobs:
|
|
|
33
33
|
fail-fast: true
|
|
34
34
|
matrix:
|
|
35
35
|
ruby:
|
|
36
|
-
- 2.
|
|
37
|
-
-
|
|
38
|
-
- 3.
|
|
39
|
-
- 3.
|
|
36
|
+
- '2.7'
|
|
37
|
+
- '3.0'
|
|
38
|
+
- '3.1'
|
|
39
|
+
- '3.2'
|
|
40
40
|
os:
|
|
41
|
-
- ubuntu-
|
|
42
|
-
- ubuntu-
|
|
41
|
+
- ubuntu-20.04
|
|
42
|
+
- ubuntu-latest
|
|
43
43
|
exclude:
|
|
44
|
-
- { os: ubuntu-
|
|
45
|
-
- { os: ubuntu-
|
|
46
|
-
- { os: ubuntu-22.04, ruby: 3.0 }
|
|
44
|
+
- { os: ubuntu-latest, ruby: '2.7' }
|
|
45
|
+
- { os: ubuntu-latest, ruby: '3.0' }
|
|
47
46
|
test_cmd:
|
|
48
47
|
- bundle exec rspec
|
|
49
48
|
|
data/README.md
CHANGED
|
@@ -184,6 +184,7 @@ Example:
|
|
|
184
184
|
2.3.3 :013 > packet.to_binary_s
|
|
185
185
|
=> "\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"
|
|
186
186
|
```
|
|
187
|
+
|
|
187
188
|
### Using the Client
|
|
188
189
|
|
|
189
190
|
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 convenience methods for performing SMB actions. It handles the creation, sending and receiving of packets for the user, providing reasonable defaults in many cases.
|
data/cortex.yaml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
info:
|
|
3
|
+
title: Ruby Smb
|
|
4
|
+
description: A native Ruby implementation of the SMB Protocol Family
|
|
5
|
+
x-cortex-git:
|
|
6
|
+
github:
|
|
7
|
+
alias: r7org
|
|
8
|
+
repository: rapid7/ruby_smb
|
|
9
|
+
x-cortex-tag: ruby-smb
|
|
10
|
+
x-cortex-type: service
|
|
11
|
+
x-cortex-domain-parents:
|
|
12
|
+
- tag: metasploit
|
|
13
|
+
openapi: 3.0.1
|
|
14
|
+
servers:
|
|
15
|
+
- url: "/"
|
|
@@ -26,6 +26,7 @@ client = RubySMB::Dcerpc::Client.new(
|
|
|
26
26
|
client.connect
|
|
27
27
|
puts('Binding to DRSR...')
|
|
28
28
|
client.bind(
|
|
29
|
+
endpoint: RubySMB::Dcerpc::Drsr,
|
|
29
30
|
auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
|
|
30
31
|
auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
|
|
31
32
|
)
|
|
@@ -59,7 +60,7 @@ dc_infos.each do |dc_info|
|
|
|
59
60
|
puts "Decrypting hash for user: #{dn}"
|
|
60
61
|
|
|
61
62
|
entinf_struct = user_record.pmsg_out.msg_getchg.p_objects.entinf
|
|
62
|
-
object_sid = rid = entinf_struct.p_name.sid[-4..-1].unpack('<
|
|
63
|
+
object_sid = rid = entinf_struct.p_name.sid[-4..-1].unpack('L<').first
|
|
63
64
|
lm_hash = Net::NTLM.lm_hash('')
|
|
64
65
|
nt_hash = Net::NTLM.ntlm_hash('')
|
|
65
66
|
disabled = nil
|
data/lib/ruby_smb/client.rb
CHANGED
|
@@ -4,6 +4,7 @@ module RubySMB
|
|
|
4
4
|
class Client
|
|
5
5
|
require 'ruby_smb/ntlm'
|
|
6
6
|
require 'ruby_smb/signing'
|
|
7
|
+
require 'ruby_smb/utils'
|
|
7
8
|
require 'ruby_smb/client/negotiation'
|
|
8
9
|
require 'ruby_smb/client/authentication'
|
|
9
10
|
require 'ruby_smb/client/tree_connect'
|
|
@@ -13,6 +14,7 @@ module RubySMB
|
|
|
13
14
|
require 'ruby_smb/client/encryption'
|
|
14
15
|
|
|
15
16
|
include RubySMB::Signing
|
|
17
|
+
include RubySMB::NTLM
|
|
16
18
|
include RubySMB::Client::Negotiation
|
|
17
19
|
include RubySMB::Client::Authentication
|
|
18
20
|
include RubySMB::Client::TreeConnect
|
|
@@ -322,7 +324,7 @@ module RubySMB
|
|
|
322
324
|
@pid = rand(0xFFFF)
|
|
323
325
|
@domain = domain
|
|
324
326
|
@local_workstation = local_workstation
|
|
325
|
-
@password =
|
|
327
|
+
@password = RubySMB::Utils.safe_encode((password||''), 'utf-8')
|
|
326
328
|
@sequence_counter = 0
|
|
327
329
|
@session_id = 0x00
|
|
328
330
|
@session_key = ''
|
|
@@ -332,7 +334,7 @@ module RubySMB
|
|
|
332
334
|
@smb1 = smb1
|
|
333
335
|
@smb2 = smb2
|
|
334
336
|
@smb3 = smb3
|
|
335
|
-
@username =
|
|
337
|
+
@username = RubySMB::Utils.safe_encode((username||''), 'utf-8')
|
|
336
338
|
@max_buffer_size = MAX_BUFFER_SIZE
|
|
337
339
|
# These sizes will be modified during negotiation
|
|
338
340
|
@server_max_buffer_size = SERVER_MAX_BUFFER_SIZE
|
|
@@ -415,8 +417,8 @@ module RubySMB
|
|
|
415
417
|
local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS)
|
|
416
418
|
@domain = domain
|
|
417
419
|
@local_workstation = local_workstation
|
|
418
|
-
@password =
|
|
419
|
-
@username =
|
|
420
|
+
@password = RubySMB::Utils.safe_encode((pass||''), 'utf-8')
|
|
421
|
+
@username = RubySMB::Utils.safe_encode((user||''), 'utf-8')
|
|
420
422
|
|
|
421
423
|
@ntlm_client = RubySMB::NTLM::Client.new(
|
|
422
424
|
@username,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
# The Alter context PDU as defined in
|
|
4
|
+
# [The alter_context PDU](https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_01)
|
|
5
|
+
class AlterContext < BinData::Record
|
|
6
|
+
PTYPE = PTypes::ALTER_CONTEXT
|
|
7
|
+
|
|
8
|
+
endian :little
|
|
9
|
+
|
|
10
|
+
# PDU Header
|
|
11
|
+
pdu_header :pdu_header, label: 'PDU header'
|
|
12
|
+
ndr_uint16 :max_xmit_frag, label: 'Max transmit frag size', initial_value: RubySMB::Dcerpc::MAX_XMIT_FRAG
|
|
13
|
+
ndr_uint16 :max_recv_frag, label: 'Max receive frag size', initial_value: RubySMB::Dcerpc::MAX_RECV_FRAG
|
|
14
|
+
ndr_uint32 :assoc_group_id, label: 'Incarnation of client-server assoc group'
|
|
15
|
+
p_cont_list_t :p_context_list, label: 'Presentation context list', endpoint: -> { endpoint }
|
|
16
|
+
|
|
17
|
+
# Auth Verifier
|
|
18
|
+
sec_trailer :sec_trailer, onlyif: -> { pdu_header.auth_length > 0 }
|
|
19
|
+
string :auth_value,
|
|
20
|
+
onlyif: -> { pdu_header.auth_length > 0 },
|
|
21
|
+
read_length: -> { pdu_header.auth_length }
|
|
22
|
+
|
|
23
|
+
def initialize_instance
|
|
24
|
+
super
|
|
25
|
+
pdu_header.ptype = PTYPE
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
# The Alter context resp PDU as defined in
|
|
4
|
+
# [The alter_context_resp PDU](https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_02)
|
|
5
|
+
|
|
6
|
+
class AlterContextResp < BinData::Record
|
|
7
|
+
PTYPE = PTypes::ALTER_CONTEXT_RESP
|
|
8
|
+
|
|
9
|
+
# Presentation context negotiation results
|
|
10
|
+
ACCEPTANCE = 0
|
|
11
|
+
USER_REJECTION = 1
|
|
12
|
+
PROVIDER_REJECTION = 2
|
|
13
|
+
|
|
14
|
+
# Reasons for rejection of a context element
|
|
15
|
+
REASON_NOT_SPECIFIED = 0
|
|
16
|
+
ABSTRACT_SYNTAX_NOT_SUPPORTED = 1
|
|
17
|
+
PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED = 2
|
|
18
|
+
LOCAL_LIMIT_EXCEEDED = 3
|
|
19
|
+
|
|
20
|
+
endian :little
|
|
21
|
+
|
|
22
|
+
# PDU Header
|
|
23
|
+
pdu_header :pdu_header, label: 'PDU header'
|
|
24
|
+
ndr_uint16 :max_xmit_frag, label: 'Max transmit frag size', initial_value: RubySMB::Dcerpc::MAX_XMIT_FRAG
|
|
25
|
+
ndr_uint16 :max_recv_frag, label: 'Max receive frag size', initial_value: RubySMB::Dcerpc::MAX_RECV_FRAG
|
|
26
|
+
ndr_uint32 :assoc_group_id, label: 'Association group ID'
|
|
27
|
+
port_any_t :sec_addr, label: 'Secondary address'
|
|
28
|
+
p_result_list_t :p_result_list, label: 'Presentation context result list'
|
|
29
|
+
|
|
30
|
+
# Auth Verifier
|
|
31
|
+
sec_trailer :sec_trailer, onlyif: -> { pdu_header.auth_length > 0 }
|
|
32
|
+
string :auth_value,
|
|
33
|
+
onlyif: -> { pdu_header.auth_length > 0 },
|
|
34
|
+
read_length: -> { pdu_header.auth_length }
|
|
35
|
+
|
|
36
|
+
def initialize_instance
|
|
37
|
+
super
|
|
38
|
+
pdu_header.ptype = PTYPE
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/ruby_smb/dcerpc/bind.rb
CHANGED
|
@@ -2,38 +2,6 @@ module RubySMB
|
|
|
2
2
|
module Dcerpc
|
|
3
3
|
# The Bind PDU as defined in
|
|
4
4
|
# [The bind PDU](http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_03)
|
|
5
|
-
class PContElemT < Ndr::NdrStruct
|
|
6
|
-
default_parameter byte_align: 4
|
|
7
|
-
endian :little
|
|
8
|
-
|
|
9
|
-
ndr_uint16 :p_cont_id, label: 'Context ID'
|
|
10
|
-
ndr_uint8 :n_transfer_syn, label: 'Number of transfer syntaxes', initial_value: 1
|
|
11
|
-
ndr_uint8 :reserved
|
|
12
|
-
p_syntax_id_t :abstract_syntax, label: 'Abstract syntax',
|
|
13
|
-
uuid: -> { endpoint::UUID },
|
|
14
|
-
ver_major: -> { endpoint::VER_MAJOR },
|
|
15
|
-
ver_minor: -> { endpoint::VER_MINOR }
|
|
16
|
-
array :transfer_syntaxes, label: 'Transfer syntax', type: :p_syntax_id_t,
|
|
17
|
-
initial_length: -> { n_transfer_syn },
|
|
18
|
-
uuid: -> { Ndr::UUID },
|
|
19
|
-
ver_major: -> { Ndr::VER_MAJOR },
|
|
20
|
-
ver_minor: -> { Ndr::VER_MINOR },
|
|
21
|
-
byte_align: 4
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
class PContListT < Ndr::NdrStruct
|
|
25
|
-
default_parameter byte_align: 4
|
|
26
|
-
endian :little
|
|
27
|
-
|
|
28
|
-
ndr_uint8 :n_context_elem, label: 'Number of context elements', initial_value: -> { 1 }
|
|
29
|
-
ndr_uint8 :reserved
|
|
30
|
-
ndr_uint16 :reserved2
|
|
31
|
-
array :p_cont_elem, label: 'Presentation context elements', type: :p_cont_elem_t,
|
|
32
|
-
initial_length: -> {n_context_elem},
|
|
33
|
-
endpoint: -> {endpoint},
|
|
34
|
-
byte_align: 4
|
|
35
|
-
end
|
|
36
|
-
|
|
37
5
|
class Bind < BinData::Record
|
|
38
6
|
PTYPE = PTypes::BIND
|
|
39
7
|
|
|
@@ -41,9 +9,9 @@ module RubySMB
|
|
|
41
9
|
|
|
42
10
|
# PDU Header
|
|
43
11
|
pdu_header :pdu_header, label: 'PDU header'
|
|
44
|
-
ndr_uint16 :max_xmit_frag, label: '
|
|
45
|
-
ndr_uint16 :max_recv_frag, label: '
|
|
46
|
-
ndr_uint32 :assoc_group_id, label: '
|
|
12
|
+
ndr_uint16 :max_xmit_frag, label: 'Max transmit frag size', initial_value: RubySMB::Dcerpc::MAX_XMIT_FRAG
|
|
13
|
+
ndr_uint16 :max_recv_frag, label: 'Max receive frag size', initial_value: RubySMB::Dcerpc::MAX_RECV_FRAG
|
|
14
|
+
ndr_uint32 :assoc_group_id, label: 'Incarnation of client-server assoc group'
|
|
47
15
|
p_cont_list_t :p_context_list, label: 'Presentation context list', endpoint: -> { endpoint }
|
|
48
16
|
|
|
49
17
|
# Auth Verifier
|
|
@@ -2,37 +2,6 @@ module RubySMB
|
|
|
2
2
|
module Dcerpc
|
|
3
3
|
# The Bind ACK PDU as defined in
|
|
4
4
|
# [The bind_ack PDU](http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_04)
|
|
5
|
-
|
|
6
|
-
class PResultT < Ndr::NdrStruct
|
|
7
|
-
default_parameter byte_align: 4
|
|
8
|
-
endian :little
|
|
9
|
-
|
|
10
|
-
ndr_uint16 :result, label: 'Presentation context negotiation results'
|
|
11
|
-
ndr_uint16 :reason, label: 'Rejection reason'
|
|
12
|
-
p_syntax_id_t :transfer_syntax, label: 'Presentation syntax ID',
|
|
13
|
-
uuid: -> { Ndr::UUID },
|
|
14
|
-
ver_major: -> { Ndr::VER_MAJOR },
|
|
15
|
-
ver_minor: -> { Ndr::VER_MINOR }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class PResultListT < Ndr::NdrStruct
|
|
19
|
-
default_parameter byte_align: 4
|
|
20
|
-
endian :little
|
|
21
|
-
|
|
22
|
-
ndr_uint8 :n_results, label: 'Number of results', initial_value: -> { p_results.size }
|
|
23
|
-
ndr_uint8 :reserved
|
|
24
|
-
ndr_uint16 :reserved2
|
|
25
|
-
array :p_results, label: 'Results', type: :p_result_t, initial_length: -> { n_results }, byte_align: 4
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
class PortAnyT < Ndr::NdrStruct
|
|
29
|
-
default_parameter byte_align: 2
|
|
30
|
-
endian :little
|
|
31
|
-
|
|
32
|
-
ndr_uint16 :str_length, label: 'Length', initial_value: -> { port_spec.to_binary_s.size }
|
|
33
|
-
stringz :port_spec, label: 'Port string spec', byte_align: 2
|
|
34
|
-
end
|
|
35
|
-
|
|
36
5
|
class BindAck < BinData::Record
|
|
37
6
|
PTYPE = PTypes::BIND_ACK
|
|
38
7
|
|
|
@@ -5,14 +5,16 @@ module RubySMB
|
|
|
5
5
|
class Client
|
|
6
6
|
require 'bindata'
|
|
7
7
|
require 'windows_error'
|
|
8
|
-
require '
|
|
8
|
+
require 'ruby_smb/ntlm'
|
|
9
9
|
require 'ruby_smb/dcerpc'
|
|
10
10
|
require 'ruby_smb/gss'
|
|
11
11
|
require 'ruby_smb/peer_info'
|
|
12
|
+
require 'ruby_smb/utils'
|
|
12
13
|
|
|
13
14
|
include Dcerpc
|
|
14
15
|
include Epm
|
|
15
16
|
include PeerInfo
|
|
17
|
+
include Utils
|
|
16
18
|
|
|
17
19
|
# The default maximum size of a RPC message that the Client accepts (in bytes)
|
|
18
20
|
MAX_BUFFER_SIZE = 64512
|
|
@@ -118,15 +120,15 @@ module RubySMB
|
|
|
118
120
|
@read_timeout = read_timeout
|
|
119
121
|
@domain = domain
|
|
120
122
|
@local_workstation = local_workstation
|
|
121
|
-
@username =
|
|
122
|
-
@password =
|
|
123
|
+
@username = RubySMB::Utils.safe_encode(username, 'utf-8')
|
|
124
|
+
@password = RubySMB::Utils.safe_encode(password, 'utf-8')
|
|
123
125
|
@max_buffer_size = MAX_BUFFER_SIZE
|
|
124
126
|
@call_id = 1
|
|
125
127
|
@ctx_id = 0
|
|
126
128
|
@auth_ctx_id_base = rand(0xFFFFFFFF)
|
|
127
129
|
|
|
128
130
|
unless username.empty? && password.empty?
|
|
129
|
-
@ntlm_client =
|
|
131
|
+
@ntlm_client = RubySMB::NTLM::Client.new(
|
|
130
132
|
@username,
|
|
131
133
|
@password,
|
|
132
134
|
workstation: @local_workstation,
|
|
@@ -207,6 +209,10 @@ module RubySMB
|
|
|
207
209
|
if auth_level &&
|
|
208
210
|
[RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
|
|
209
211
|
set_integrity_privacy(dcerpc_req, auth_level: auth_level, auth_type: auth_type)
|
|
212
|
+
# Per the spec (MS_RPCE 2.2.2.11): start of the trailer should be a multiple of 16 bytes offset from the start of the stub
|
|
213
|
+
valid_offset = (((dcerpc_req.sec_trailer.abs_offset - dcerpc_req.stub.abs_offset) % 16))
|
|
214
|
+
valid_auth_pad = (dcerpc_req.sec_trailer.auth_pad_length == dcerpc_req.auth_pad.length)
|
|
215
|
+
raise Error::InvalidPacket unless valid_offset == 0 && valid_auth_pad
|
|
210
216
|
end
|
|
211
217
|
|
|
212
218
|
send_packet(dcerpc_req)
|
data/lib/ruby_smb/dcerpc/drsr.rb
CHANGED
|
@@ -613,8 +613,8 @@ module RubySMB
|
|
|
613
613
|
drs_bind_request = DrsBindRequest.new(pext_client: drs_extensions_int)
|
|
614
614
|
response = dcerpc_request(
|
|
615
615
|
drs_bind_request,
|
|
616
|
-
auth_level:
|
|
617
|
-
auth_type:
|
|
616
|
+
auth_level: @auth_level,
|
|
617
|
+
auth_type: @auth_type
|
|
618
618
|
)
|
|
619
619
|
begin
|
|
620
620
|
drs_bind_response = DrsBindResponse.read(response)
|
|
@@ -640,8 +640,8 @@ module RubySMB
|
|
|
640
640
|
drs_bind_request.pext_client.assign(drs_extensions_int)
|
|
641
641
|
response = dcerpc_request(
|
|
642
642
|
drs_bind_request,
|
|
643
|
-
auth_level:
|
|
644
|
-
auth_type:
|
|
643
|
+
auth_level: @auth_level,
|
|
644
|
+
auth_type: @auth_type
|
|
645
645
|
)
|
|
646
646
|
begin
|
|
647
647
|
drs_bind_response = DrsBindResponse.read(response)
|
|
@@ -668,8 +668,8 @@ module RubySMB
|
|
|
668
668
|
drs_unbind_request = DrsUnbindRequest.new(ph_drs: ph_drs)
|
|
669
669
|
response = dcerpc_request(
|
|
670
670
|
drs_unbind_request,
|
|
671
|
-
|
|
672
|
-
|
|
671
|
+
auth_level: @auth_level,
|
|
672
|
+
auth_type: @auth_type
|
|
673
673
|
)
|
|
674
674
|
begin
|
|
675
675
|
drs_unbind_response = DrsUnbindResponse.read(response)
|
|
@@ -709,8 +709,8 @@ module RubySMB
|
|
|
709
709
|
)
|
|
710
710
|
response = dcerpc_request(
|
|
711
711
|
drs_domain_controller_info_request,
|
|
712
|
-
auth_level:
|
|
713
|
-
auth_type:
|
|
712
|
+
auth_level: @auth_level,
|
|
713
|
+
auth_type: @auth_type
|
|
714
714
|
)
|
|
715
715
|
begin
|
|
716
716
|
drs_domain_controller_info_response = DrsDomainControllerInfoResponse.read(response)
|
|
@@ -759,8 +759,8 @@ module RubySMB
|
|
|
759
759
|
)
|
|
760
760
|
response = dcerpc_request(
|
|
761
761
|
drs_crack_names_request,
|
|
762
|
-
auth_level:
|
|
763
|
-
auth_type:
|
|
762
|
+
auth_level: @auth_level,
|
|
763
|
+
auth_type: @auth_type
|
|
764
764
|
)
|
|
765
765
|
begin
|
|
766
766
|
drs_crack_names_response = DrsCrackNamesResponse.read(response)
|
|
@@ -790,8 +790,8 @@ module RubySMB
|
|
|
790
790
|
unless @session_key
|
|
791
791
|
raise RubySMB::Error::EncryptionError, 'Unable to decrypt attribute value: session key is empty'
|
|
792
792
|
end
|
|
793
|
-
encrypted_payload = EncryptedPayload.read(attribute)
|
|
794
793
|
|
|
794
|
+
encrypted_payload = EncryptedPayload.read(attribute)
|
|
795
795
|
signature = OpenSSL::Digest::MD5.digest(@session_key + encrypted_payload.salt.to_binary_s)
|
|
796
796
|
rc4 = OpenSSL::Cipher.new('rc4')
|
|
797
797
|
rc4.decrypt
|
|
@@ -886,8 +886,8 @@ module RubySMB
|
|
|
886
886
|
|
|
887
887
|
response = dcerpc_request(
|
|
888
888
|
drs_get_nc_changes_request,
|
|
889
|
-
auth_level:
|
|
890
|
-
auth_type:
|
|
889
|
+
auth_level: @auth_level,
|
|
890
|
+
auth_type: @auth_type
|
|
891
891
|
)
|
|
892
892
|
begin
|
|
893
893
|
drs_get_nc_changes_response = DrsGetNcChangesResponse.read(response)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
module EncryptingFileSystem
|
|
4
|
+
|
|
5
|
+
# [3.1.4.2.6 Receiving an EfsRpcDecryptFileSrv Message (Opnum 5)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/043715de-caee-402a-a61b-921743337e78)
|
|
6
|
+
class EfsRpcDecryptFileSrvRequest < BinData::Record
|
|
7
|
+
attr_reader :opnum
|
|
8
|
+
|
|
9
|
+
endian :little
|
|
10
|
+
|
|
11
|
+
ndr_conf_var_wide_stringz :file_name
|
|
12
|
+
ndr_uint32 :open_flag
|
|
13
|
+
|
|
14
|
+
def initialize_instance
|
|
15
|
+
super
|
|
16
|
+
@opnum = EFS_RPC_DECRYPT_FILE_SRV
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
module EncryptingFileSystem
|
|
4
|
+
|
|
5
|
+
# [3.1.4.2.6 Receiving an EfsRpcDecryptFileSrv Message (Opnum 5)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/043715de-caee-402a-a61b-921743337e78)
|
|
6
|
+
class EfsRpcDecryptFileSrvResponse < 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 = EFS_RPC_DECRYPT_FILE_SRV
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
module EncryptingFileSystem
|
|
4
|
+
|
|
5
|
+
# [3.1.4.2.8 Receiving an EfsRpcQueryRecoveryAgents Message (Opnum 7)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/cf759c00-1b90-4c33-9ace-f51c20149cea)
|
|
6
|
+
class EfsRpcQueryRecoveryAgentsRequest < BinData::Record
|
|
7
|
+
attr_reader :opnum
|
|
8
|
+
|
|
9
|
+
endian :little
|
|
10
|
+
|
|
11
|
+
ndr_conf_var_wide_stringz :file_name
|
|
12
|
+
|
|
13
|
+
def initialize_instance
|
|
14
|
+
super
|
|
15
|
+
@opnum = EFS_RPC_QUERY_RECOVERY_AGENTS
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
module EncryptingFileSystem
|
|
4
|
+
|
|
5
|
+
# [3.1.4.2.8 Receiving an EfsRpcQueryRecoveryAgents Message (Opnum 7)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/cf759c00-1b90-4c33-9ace-f51c20149cea)
|
|
6
|
+
class EfsRpcQueryRecoveryAgentsResponse < BinData::Record
|
|
7
|
+
attr_reader :opnum
|
|
8
|
+
|
|
9
|
+
endian :little
|
|
10
|
+
|
|
11
|
+
encryption_certificate_hash_list_ptr :recover_agents
|
|
12
|
+
ndr_uint32 :error_status
|
|
13
|
+
|
|
14
|
+
def initialize_instance
|
|
15
|
+
super
|
|
16
|
+
@opnum = EFS_RPC_QUERY_RECOVERY_AGENTS
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
module EncryptingFileSystem
|
|
4
|
+
|
|
5
|
+
# [3.1.4.2.7 Receiving an EfsRpcQueryUsersOnFile Message (Opnum 6)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/a058dc6c-bb7e-491c-9143-a5cb1f7e7cea)
|
|
6
|
+
class EfsRpcQueryUsersOnFileRequest < BinData::Record
|
|
7
|
+
attr_reader :opnum
|
|
8
|
+
|
|
9
|
+
endian :little
|
|
10
|
+
|
|
11
|
+
ndr_conf_var_wide_stringz :file_name
|
|
12
|
+
|
|
13
|
+
def initialize_instance
|
|
14
|
+
super
|
|
15
|
+
@opnum = EFS_RPC_QUERY_USERS_ON_FILE
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
module EncryptingFileSystem
|
|
4
|
+
|
|
5
|
+
# [3.1.4.2.7 Receiving an EfsRpcQueryUsersOnFile Message (Opnum 6)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/a058dc6c-bb7e-491c-9143-a5cb1f7e7cea)
|
|
6
|
+
class EfsRpcQueryUsersOnFileResponse < BinData::Record
|
|
7
|
+
attr_reader :opnum
|
|
8
|
+
|
|
9
|
+
endian :little
|
|
10
|
+
|
|
11
|
+
encryption_certificate_hash_list_ptr :users
|
|
12
|
+
ndr_uint32 :error_status
|
|
13
|
+
|
|
14
|
+
def initialize_instance
|
|
15
|
+
super
|
|
16
|
+
@opnum = EFS_RPC_QUERY_USERS_ON_FILE
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -35,10 +35,62 @@ module RubySMB
|
|
|
35
35
|
OVERWRITE_HIDDEN = 0x00000004
|
|
36
36
|
EFS_DROP_ALTERNATE_STREAMS = 0x00000010
|
|
37
37
|
|
|
38
|
+
# [2.2.7 EFS_HASH_BLOB](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/242d857f-ac8e-4cc8-b5e4-9314a942f45e)
|
|
39
|
+
class EfsHashBlob < Ndr::NdrStruct
|
|
40
|
+
endian :little
|
|
41
|
+
default_parameter byte_align: 4
|
|
42
|
+
|
|
43
|
+
ndr_uint32 :cb_data
|
|
44
|
+
ndr_byte_conf_array_ptr :b_data
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class EfsHashBlobPtr < EfsHashBlob
|
|
48
|
+
extend Ndr::PointerClassPlugin
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# [2.2.10 ENCRYPTION_CERTIFICATE_HASH](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/3a7e7151-edcb-4b32-a119-35cdce1584c0)
|
|
52
|
+
class EncryptionCertificateHash < Ndr::NdrStruct
|
|
53
|
+
endian :little
|
|
54
|
+
default_parameter byte_align: 4
|
|
55
|
+
|
|
56
|
+
ndr_uint32 :cb_total_length
|
|
57
|
+
prpc_sid :user_sid
|
|
58
|
+
efs_hash_blob_ptr :certificate_hash
|
|
59
|
+
ndr_wide_stringz_ptr :lp_display_information
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class EncryptionCertificateHashPtr < EncryptionCertificateHash
|
|
63
|
+
extend Ndr::PointerClassPlugin
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
class EncryptionCertificateHashPtrArrayPtr < Ndr::NdrConfArray
|
|
67
|
+
default_parameter type: :encryption_certificate_hash_ptr
|
|
68
|
+
extend Ndr::PointerClassPlugin
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# [2.2.11 ENCRYPTION_CERTIFICATE_HASH_LIST](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/2718804c-6ab9-45fd-98cf-541bc3b6bc75)
|
|
72
|
+
class EncryptionCertificateHashList < BinData::Record
|
|
73
|
+
endian :little
|
|
74
|
+
default_parameter byte_align: 4
|
|
75
|
+
|
|
76
|
+
uint32 :ncert_hash
|
|
77
|
+
encryption_certificate_hash_ptr_array_ptr :users
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class EncryptionCertificateHashListPtr < EncryptionCertificateHashList
|
|
81
|
+
extend Ndr::PointerClassPlugin
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_decrypt_file_srv_request'
|
|
85
|
+
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_decrypt_file_srv_response'
|
|
38
86
|
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_request'
|
|
39
87
|
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response'
|
|
40
88
|
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request'
|
|
41
89
|
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response'
|
|
90
|
+
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_recover_agents_request'
|
|
91
|
+
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_recover_agents_response'
|
|
92
|
+
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_users_on_file_request'
|
|
93
|
+
require 'ruby_smb/dcerpc/encrypting_file_system/efs_rpc_query_users_on_file_response'
|
|
42
94
|
end
|
|
43
95
|
end
|
|
44
96
|
end
|
data/lib/ruby_smb/dcerpc/icpr.rb
CHANGED
|
@@ -35,7 +35,7 @@ module RubySMB
|
|
|
35
35
|
def cert_server_request(attributes:, authority:, csr:)
|
|
36
36
|
cert_server_request_request = CertServerRequestRequest.new(
|
|
37
37
|
pwsz_authority: authority,
|
|
38
|
-
pctb_attribs: { pb: (attributes.map { |k,v| "#{k}:#{v}" }.join("\n")
|
|
38
|
+
pctb_attribs: { pb: (RubySMB::Utils.safe_encode(attributes.map { |k,v| "#{k}:#{v}" }.join("\n"), 'UTF-16le').force_encoding('ASCII-8bit') + "\x00\x00".b) },
|
|
39
39
|
pctb_request: { pb: csr.to_der }
|
|
40
40
|
)
|
|
41
41
|
|
|
@@ -51,6 +51,7 @@ module RubySMB
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
ret = {
|
|
54
|
+
certificate: nil,
|
|
54
55
|
disposition: cert_server_request_response.pdw_disposition.value,
|
|
55
56
|
disposition_message: cert_server_request_response.pctb_disposition_message.buffer.chomp("\x00\x00").force_encoding('utf-16le').encode,
|
|
56
57
|
status: {
|
|
@@ -72,7 +73,7 @@ module RubySMB
|
|
|
72
73
|
status_code: status_code
|
|
73
74
|
)
|
|
74
75
|
end
|
|
75
|
-
|
|
76
|
+
elsif !cert_server_request_response.pctb_encoded_cert.buffer.empty?
|
|
76
77
|
ret[:certificate] = OpenSSL::X509::Certificate.new(cert_server_request_response.pctb_encoded_cert.buffer)
|
|
77
78
|
end
|
|
78
79
|
|