ruby_smb 2.0.10 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/verify.yml +5 -16
- data/examples/auth_capture.rb +71 -0
- data/examples/dump_secrets_from_sid.rb +207 -0
- data/examples/enum_domain_users.rb +75 -0
- data/examples/get_computer_info.rb +42 -0
- data/examples/query_service_status.rb +42 -4
- data/lib/ruby_smb/client/negotiation.rb +1 -1
- data/lib/ruby_smb/client.rb +10 -20
- data/lib/ruby_smb/dcerpc/bind.rb +28 -20
- data/lib/ruby_smb/dcerpc/bind_ack.rb +29 -28
- data/lib/ruby_smb/dcerpc/client.rb +542 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_bind_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_bind_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_request.rb +57 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_response.rb +76 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_request.rb +46 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_response.rb +168 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_extensions.rb +56 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_request.rb +121 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_response.rb +118 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_unbind_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/drsr/drs_unbind_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/drsr.rb +909 -0
- data/lib/ruby_smb/dcerpc/epm/epm_ept_map_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/epm/epm_ept_map_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/epm/epm_twrt.rb +211 -0
- data/lib/ruby_smb/dcerpc/epm.rb +75 -0
- data/lib/ruby_smb/dcerpc/error.rb +17 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +1159 -297
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +3 -13
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +3 -3
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +3 -13
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +3 -11
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/netlogon.rb +5 -4
- data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +4 -3
- data/lib/ruby_smb/dcerpc/pdu_header.rb +7 -7
- data/lib/ruby_smb/dcerpc/ptypes.rb +1 -0
- data/lib/ruby_smb/dcerpc/request.rb +79 -32
- data/lib/ruby_smb/dcerpc/response.rb +45 -10
- data/lib/ruby_smb/dcerpc/rpc_auth3.rb +28 -0
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +11 -11
- data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +118 -0
- data/lib/ruby_smb/dcerpc/samr/rpc_sid.rb +150 -0
- data/lib/ruby_smb/dcerpc/samr/samr_close_handle_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_close_handle_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_connect_request.rb +32 -0
- data/lib/ruby_smb/dcerpc/samr/samr_connect_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +55 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +38 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_response.rb +48 -0
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_domain_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_domain_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_user_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/samr/samr_open_user_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr.rb +613 -0
- data/lib/ruby_smb/dcerpc/sec_trailer.rb +26 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +56 -79
- data/lib/ruby_smb/dcerpc/srvsvc.rb +27 -4
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +13 -25
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +2 -2
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +4 -14
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +3 -11
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +12 -11
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +9 -8
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +3 -3
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/svcctl.rb +1 -3
- data/lib/ruby_smb/dcerpc/uuid.rb +3 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +2 -2
- data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +2 -13
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +3 -3
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +3 -20
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +3 -20
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +5 -14
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +5 -14
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +1 -9
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +4 -3
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +5 -6
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +2 -2
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +9 -18
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +4 -14
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +7 -15
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +3 -1
- data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +0 -9
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg.rb +10 -14
- data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response.rb +88 -0
- data/lib/ruby_smb/dcerpc/wkssvc.rb +65 -0
- data/lib/ruby_smb/dcerpc.rb +41 -11
- data/lib/ruby_smb/dialect.rb +45 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/field/file_time.rb +1 -1
- data/lib/ruby_smb/field/string16.rb +5 -1
- data/lib/ruby_smb/gss/provider/authenticator.rb +42 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +303 -0
- data/lib/ruby_smb/gss/provider.rb +35 -0
- data/lib/ruby_smb/gss.rb +56 -63
- data/lib/ruby_smb/ntlm.rb +61 -0
- data/lib/ruby_smb/server/server_client/negotiation.rb +156 -0
- data/lib/ruby_smb/server/server_client/session_setup.rb +82 -0
- data/lib/ruby_smb/server/server_client.rb +162 -0
- data/lib/ruby_smb/server.rb +54 -0
- data/lib/ruby_smb/signing.rb +59 -0
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +11 -11
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +4 -0
- data/lib/ruby_smb/smb2/negotiate_context.rb +18 -2
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +9 -0
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +0 -1
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +1 -1
- data/lib/ruby_smb/smb2/pipe.rb +4 -0
- data/lib/ruby_smb/smb2.rb +3 -1
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +2 -1
- data/spec/lib/ruby_smb/client_spec.rb +8 -11
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +69 -41
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +75 -21
- data/spec/lib/ruby_smb/dcerpc/client_spec.rb +714 -0
- data/spec/lib/ruby_smb/dcerpc/drsr_spec.rb +2169 -0
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +3792 -1373
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +4 -4
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +4 -4
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +18 -4
- data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +27 -1
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +76 -11
- data/spec/lib/ruby_smb/dcerpc/response_spec.rb +99 -9
- data/spec/lib/ruby_smb/dcerpc/rpc_auth3_spec.rb +75 -0
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +29 -28
- data/spec/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string_spec.rb +340 -0
- data/spec/lib/ruby_smb/dcerpc/samr/rpc_sid_spec.rb +116 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_request_spec.rb +40 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_response_spec.rb +48 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_request_spec.rb +56 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_response_spec.rb +47 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request_spec.rb +63 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +265 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request_spec.rb +52 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_request_spec.rb +56 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_response_spec.rb +48 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request_spec.rb +48 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response_spec.rb +42 -0
- data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +420 -0
- data/spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb +92 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +149 -110
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +21 -17
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +56 -79
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +4 -4
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +19 -29
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +9 -15
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +22 -22
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +18 -14
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +5 -4
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +1 -5
- data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +15 -23
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +4 -41
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +4 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +4 -52
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +4 -56
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +10 -34
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +10 -34
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +2 -26
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +17 -25
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +20 -44
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +8 -32
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +10 -22
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +4 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +0 -12
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +18 -47
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb +43 -0
- data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb +70 -0
- data/spec/lib/ruby_smb/field/string16_spec.rb +22 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm/account_spec.rb +32 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +101 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm/os_version_spec.rb +32 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm_spec.rb +113 -0
- data/spec/lib/ruby_smb/server/server_client_spec.rb +156 -0
- data/spec/lib/ruby_smb/server_spec.rb +32 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +18 -37
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +18 -16
- data/spec/support/bin_helper.rb +9 -0
- data.tar.gz.sig +0 -0
- metadata +119 -6
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/client/signing.rb +0 -64
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +0 -38
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +0 -135
@@ -0,0 +1,542 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
|
4
|
+
# Represents DCERPC SMB client capable of talking to an RPC endpoint in stand-alone.
|
5
|
+
class Client
|
6
|
+
require 'bindata'
|
7
|
+
require 'windows_error'
|
8
|
+
require 'net/ntlm'
|
9
|
+
require 'ruby_smb/dcerpc'
|
10
|
+
require 'ruby_smb/gss'
|
11
|
+
|
12
|
+
include Epm
|
13
|
+
|
14
|
+
# The default maximum size of a RPC message that the Client accepts (in bytes)
|
15
|
+
MAX_BUFFER_SIZE = 64512
|
16
|
+
# The read timeout when receiving packets.
|
17
|
+
READ_TIMEOUT = 30
|
18
|
+
# The default Endpoint Mapper port
|
19
|
+
ENDPOINT_MAPPER_PORT = 135
|
20
|
+
|
21
|
+
# The domain you're trying to authenticate to
|
22
|
+
# @!attribute [rw] domain
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :domain
|
25
|
+
|
26
|
+
# The local workstation to pretend to be
|
27
|
+
# @!attribute [rw] local_workstation
|
28
|
+
# @return [String]
|
29
|
+
attr_accessor :local_workstation
|
30
|
+
|
31
|
+
# The NTLM client used for authentication
|
32
|
+
# @!attribute [rw] ntlm_client
|
33
|
+
# @return [String]
|
34
|
+
attr_accessor :ntlm_client
|
35
|
+
|
36
|
+
# The username to authenticate with
|
37
|
+
# @!attribute [rw] username
|
38
|
+
# @return [String]
|
39
|
+
attr_accessor :username
|
40
|
+
|
41
|
+
# The password to authenticate with
|
42
|
+
# @!attribute [rw] password
|
43
|
+
# @return [String]
|
44
|
+
attr_accessor :password
|
45
|
+
|
46
|
+
# The Netbios Name of the Peer/Server.
|
47
|
+
# @!attribute [rw] default_name
|
48
|
+
# @return [String]
|
49
|
+
attr_accessor :default_name
|
50
|
+
|
51
|
+
# The Netbios Domain of the Peer/Server.
|
52
|
+
# @!attribute [rw] default_domain
|
53
|
+
# @return [String]
|
54
|
+
attr_accessor :default_domain
|
55
|
+
|
56
|
+
# The Fully Qualified Domain Name (FQDN) of the computer.
|
57
|
+
# @!attribute [rw] dns_host_name
|
58
|
+
# @return [String]
|
59
|
+
attr_accessor :dns_host_name
|
60
|
+
|
61
|
+
# The Fully Qualified Domain Name (FQDN) of the domain.
|
62
|
+
# @!attribute [rw] dns_domain_name
|
63
|
+
# @return [String]
|
64
|
+
attr_accessor :dns_domain_name
|
65
|
+
|
66
|
+
# The Fully Qualified Domain Name (FQDN) of the forest.
|
67
|
+
# @!attribute [rw] dns_tree_name
|
68
|
+
# @return [String]
|
69
|
+
attr_accessor :dns_tree_name
|
70
|
+
|
71
|
+
# The OS version number (<major>.<minor>.<build>) of the Peer/Server.
|
72
|
+
# @!attribute [rw] os_version
|
73
|
+
# @return [String]
|
74
|
+
attr_accessor :os_version
|
75
|
+
|
76
|
+
# The maximum size SMB message that the Client accepts (in bytes)
|
77
|
+
# The default value is equal to {MAX_BUFFER_SIZE}.
|
78
|
+
# @!attribute [rw] max_buffer_size
|
79
|
+
# @return [Integer]
|
80
|
+
attr_accessor :max_buffer_size
|
81
|
+
|
82
|
+
# The TCP socket to connect to the remote host
|
83
|
+
# @!attribute [rw] tcp_socket
|
84
|
+
# @return [TcpSocket]
|
85
|
+
attr_accessor :tcp_socket
|
86
|
+
|
87
|
+
|
88
|
+
# @param host [String] The remote host
|
89
|
+
# @param endpoint [Module] A module endpoint that defines UUID, VER_MAJOR and
|
90
|
+
# VER_MINOR constants (e.g. Drsr)
|
91
|
+
# @param tcp_socket [TcpSocket] The socket to use. If not provided, a new
|
92
|
+
# socket will be created when calling #connect
|
93
|
+
# @param read_timeout [Integer] The read timeout value to use
|
94
|
+
# @param username [String] The username to authenticate with, if needed
|
95
|
+
# @param password [String] The password to authenticate with, if needed.
|
96
|
+
# Note that a NTLM hash can be used instead of a password.
|
97
|
+
# @param domain [String] The domain to authenticate to, if needed
|
98
|
+
# @param local_workstation [String] The workstation name to authenticate to, if needed
|
99
|
+
# @param ntlm_flags [Integer] The flags to pass to the Net:NTLM client
|
100
|
+
def initialize(host,
|
101
|
+
endpoint,
|
102
|
+
tcp_socket: nil,
|
103
|
+
read_timeout: READ_TIMEOUT,
|
104
|
+
username: '',
|
105
|
+
password: '',
|
106
|
+
domain: '.',
|
107
|
+
local_workstation: 'WORKSTATION',
|
108
|
+
ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS)
|
109
|
+
|
110
|
+
@endpoint = endpoint
|
111
|
+
extend @endpoint
|
112
|
+
|
113
|
+
@host = host
|
114
|
+
@tcp_socket = tcp_socket
|
115
|
+
@read_timeout = read_timeout
|
116
|
+
@domain = domain
|
117
|
+
@local_workstation = local_workstation
|
118
|
+
@username = username.encode('utf-8')
|
119
|
+
@password = password.encode('utf-8')
|
120
|
+
@max_buffer_size = MAX_BUFFER_SIZE
|
121
|
+
@call_id = 1
|
122
|
+
@ctx_id = 0
|
123
|
+
@auth_ctx_id_base = rand(0xFFFFFFFF)
|
124
|
+
|
125
|
+
unless username.empty? && password.empty?
|
126
|
+
@ntlm_client = Net::NTLM::Client.new(
|
127
|
+
@username,
|
128
|
+
@password,
|
129
|
+
workstation: @local_workstation,
|
130
|
+
domain: @domain,
|
131
|
+
flags: ntlm_flags
|
132
|
+
)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Connect to the RPC endpoint. If a TCP socket was not provided, it takes
|
137
|
+
# care of asking the Enpoint Mapper Interface the port used by the given
|
138
|
+
# endpoint provided in #initialize and connect a TCP socket
|
139
|
+
#
|
140
|
+
# @param port [Integer] An optional port number to connect to. If
|
141
|
+
# provided, it will not ask the Enpoint Mapper Interface for a port
|
142
|
+
# number.
|
143
|
+
# @return [TcpSocket] The connected TCP socket
|
144
|
+
def connect(port: nil)
|
145
|
+
return if @tcp_socket
|
146
|
+
unless port
|
147
|
+
@tcp_socket = TCPSocket.new(@host, ENDPOINT_MAPPER_PORT)
|
148
|
+
bind(endpoint: Epm)
|
149
|
+
begin
|
150
|
+
host_port = get_host_port_from_ept_mapper(
|
151
|
+
uuid: @endpoint::UUID,
|
152
|
+
maj_ver: @endpoint::VER_MAJOR,
|
153
|
+
min_ver: @endpoint::VER_MINOR
|
154
|
+
)
|
155
|
+
rescue RubySMB::Dcerpc::Error::DcerpcError => e
|
156
|
+
e.message.prepend(
|
157
|
+
"Cannot resolve the remote port number for endpoint #{@endpoint::UUID}. "\
|
158
|
+
"Set @tcp_socket parameter to specify the service port number and bypass "\
|
159
|
+
"EPM port resolution. Error: "
|
160
|
+
)
|
161
|
+
raise e
|
162
|
+
end
|
163
|
+
port = host_port[:port]
|
164
|
+
@tcp_socket.close
|
165
|
+
@tcp_socket = nil
|
166
|
+
end
|
167
|
+
@tcp_socket = TCPSocket.new(@host, port)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Close the TCP Socket
|
171
|
+
def close
|
172
|
+
@tcp_socket.close if @tcp_socket && !@tcp_socket.closed?
|
173
|
+
end
|
174
|
+
|
175
|
+
# Add the authentication verifier to the packet. This includes a sec
|
176
|
+
# trailer and the actual authentication data.
|
177
|
+
#
|
178
|
+
# @param req [BinData::Record] the request to be updated
|
179
|
+
# @param auth [String] the authentication data
|
180
|
+
# @param auth_type [Integer] the authentication type
|
181
|
+
# @param auth_level [Integer] the authentication level
|
182
|
+
def add_auth_verifier(req, auth, auth_type, auth_level)
|
183
|
+
req.sec_trailer = {
|
184
|
+
auth_type: auth_type,
|
185
|
+
auth_level: auth_level,
|
186
|
+
auth_context_id: @ctx_id + @auth_ctx_id_base
|
187
|
+
}
|
188
|
+
req.auth_value = auth
|
189
|
+
req.pdu_header.auth_length = auth.length
|
190
|
+
|
191
|
+
nil
|
192
|
+
end
|
193
|
+
|
194
|
+
def process_ntlm_type2(type2_message)
|
195
|
+
ntlmssp_offset = type2_message.index('NTLMSSP')
|
196
|
+
type2_blob = type2_message.slice(ntlmssp_offset..-1)
|
197
|
+
type2_b64_message = [type2_blob].pack('m')
|
198
|
+
type3_message = @ntlm_client.init_context(type2_b64_message)
|
199
|
+
auth3 = type3_message.serialize
|
200
|
+
|
201
|
+
@session_key = @ntlm_client.session_key
|
202
|
+
challenge_message = @ntlm_client.session.challenge_message
|
203
|
+
store_target_info(challenge_message.target_info) if challenge_message.has_flag?(:TARGET_INFO)
|
204
|
+
@os_version = extract_os_version(challenge_message.os_version.to_s) unless challenge_message.os_version.empty?
|
205
|
+
auth3
|
206
|
+
end
|
207
|
+
|
208
|
+
# Send a rpc_auth3 PDU that ends the authentication handshake.
|
209
|
+
#
|
210
|
+
# @param response [BindAck] the BindAck response packet
|
211
|
+
# @param auth_type [Integer] the authentication type
|
212
|
+
# @param auth_level [Integer] the authentication level
|
213
|
+
# @raise [ArgumentError] if `:auth_type` is unknown
|
214
|
+
# @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
|
215
|
+
def send_auth3(response, auth_type, auth_level)
|
216
|
+
case auth_type
|
217
|
+
when RPC_C_AUTHN_NONE
|
218
|
+
when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
|
219
|
+
auth3 = process_ntlm_type2(response.auth_value)
|
220
|
+
when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
|
221
|
+
# TODO
|
222
|
+
raise NotImplementedError
|
223
|
+
else
|
224
|
+
raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
|
225
|
+
end
|
226
|
+
|
227
|
+
rpc_auth3 = RpcAuth3.new
|
228
|
+
add_auth_verifier(rpc_auth3, auth3, auth_type, auth_level)
|
229
|
+
rpc_auth3.pdu_header.call_id = @call_id
|
230
|
+
|
231
|
+
# The server should not respond
|
232
|
+
send_packet(rpc_auth3)
|
233
|
+
@call_id += 1
|
234
|
+
|
235
|
+
nil
|
236
|
+
end
|
237
|
+
|
238
|
+
# Bind to the remote server interface endpoint. It takes care of adding
|
239
|
+
# the necessary authentication verifier if `:auth_level` is set to
|
240
|
+
# anything different than RPC_C_AUTHN_LEVEL_NONE
|
241
|
+
#
|
242
|
+
# @param endpoint [Module] the endpoint to bind to. This must be a Dcerpc
|
243
|
+
# class with UUID, VER_MAJOR and VER_MINOR constants defined.
|
244
|
+
# @param auth_level [Integer] the authentication level
|
245
|
+
# @param auth_type [Integer] the authentication type
|
246
|
+
# @return [BindAck] the BindAck response packet
|
247
|
+
# @raise [Error::InvalidPacket] if an invalid packet is received
|
248
|
+
# @raise [Error::BindError] if the response is not a BindAck packet or if the Bind result code is not ACCEPTANCE
|
249
|
+
# @raise [ArgumentError] if `:auth_type` is unknown
|
250
|
+
# @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
|
251
|
+
def bind(endpoint: @endpoint, auth_level: RPC_C_AUTHN_LEVEL_NONE, auth_type: nil)
|
252
|
+
bind_req = Bind.new(endpoint: endpoint)
|
253
|
+
bind_req.pdu_header.call_id = @call_id
|
254
|
+
# TODO: evasion: generate random UUIDs for bogus binds
|
255
|
+
|
256
|
+
if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
|
257
|
+
case auth_type
|
258
|
+
when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
|
259
|
+
raise ArgumentError, "NTLM Client not initialized. Username and password must be provided" unless @ntlm_client
|
260
|
+
type1_message = @ntlm_client.init_context
|
261
|
+
auth = type1_message.serialize
|
262
|
+
when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
|
263
|
+
when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL
|
264
|
+
# TODO
|
265
|
+
raise NotImplementedError
|
266
|
+
else
|
267
|
+
raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
|
268
|
+
end
|
269
|
+
add_auth_verifier(bind_req, auth, auth_type, auth_level)
|
270
|
+
end
|
271
|
+
|
272
|
+
send_packet(bind_req)
|
273
|
+
bindack_response = recv_struct(BindAck)
|
274
|
+
# TODO: see if BindNack response should be handled too
|
275
|
+
|
276
|
+
res_list = bindack_response.p_result_list
|
277
|
+
if res_list.n_results == 0 ||
|
278
|
+
res_list.p_results[0].result != BindAck::ACCEPTANCE
|
279
|
+
raise Error::BindError,
|
280
|
+
"Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
|
281
|
+
end
|
282
|
+
|
283
|
+
@max_buffer_size = bindack_response.max_xmit_frag
|
284
|
+
@call_id = bindack_response.pdu_header.call_id
|
285
|
+
|
286
|
+
if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
|
287
|
+
# The number of legs needed to build the security context is defined
|
288
|
+
# by the security provider
|
289
|
+
# (see [2.2.1.1.7 Security Providers](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d4097450-c62f-484b-872f-ddf59a7a0d36))
|
290
|
+
case auth_type
|
291
|
+
when RPC_C_AUTHN_WINNT
|
292
|
+
send_auth3(bindack_response, auth_type, auth_level)
|
293
|
+
when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
|
294
|
+
# TODO
|
295
|
+
raise NotImplementedError
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
nil
|
300
|
+
end
|
301
|
+
|
302
|
+
# Extract and store useful information about the peer/server from the
|
303
|
+
# NTLM Type 2 (challenge) TargetInfo fields.
|
304
|
+
#
|
305
|
+
# @param target_info_str [String] the Target Info string
|
306
|
+
def store_target_info(target_info_str)
|
307
|
+
target_info = Net::NTLM::TargetInfo.new(target_info_str)
|
308
|
+
{
|
309
|
+
Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME => :@default_name,
|
310
|
+
Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME => :@default_domain,
|
311
|
+
Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME => :@dns_host_name,
|
312
|
+
Net::NTLM::TargetInfo::MSV_AV_DNS_DOMAIN_NAME => :@dns_domain_name,
|
313
|
+
Net::NTLM::TargetInfo::MSV_AV_DNS_TREE_NAME => :@dns_tree_name
|
314
|
+
}.each do |constant, attribute|
|
315
|
+
if target_info.av_pairs[constant]
|
316
|
+
value = target_info.av_pairs[constant].dup
|
317
|
+
value.force_encoding('UTF-16LE')
|
318
|
+
instance_variable_set(attribute, value.encode('UTF-8'))
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# Extract the peer/server version number from the NTLM Type 2 (challenge)
|
324
|
+
# Version field.
|
325
|
+
#
|
326
|
+
# @param version [String] the version number as a binary string
|
327
|
+
# @return [String] the formated version number (<major>.<minor>.<build>)
|
328
|
+
def extract_os_version(version)
|
329
|
+
#version.unpack('CCS').join('.')
|
330
|
+
begin
|
331
|
+
os_version = NTLM::OSVersion.read(version)
|
332
|
+
rescue IOError
|
333
|
+
return ''
|
334
|
+
end
|
335
|
+
return "#{os_version.major}.#{os_version.minor}.#{os_version.build}"
|
336
|
+
end
|
337
|
+
|
338
|
+
# Add the authentication verifier to a Request packet. This includes a
|
339
|
+
# sec trailer and the signature of the packet. This also encrypts the
|
340
|
+
# Request stub if privacy is required (`:auth_level` option is
|
341
|
+
# RPC_C_AUTHN_LEVEL_PKT_PRIVACY).
|
342
|
+
#
|
343
|
+
# @param dcerpc_req [Request] the Request packet to be updated
|
344
|
+
# @param opts [Hash] the authenticaiton options: `:auth_type` and `:auth_level`
|
345
|
+
# @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
|
346
|
+
# @raise [ArgumentError] if `:auth_type` is unknown
|
347
|
+
def set_integrity_privacy(dcerpc_req, auth_level:, auth_type:)
|
348
|
+
dcerpc_req.sec_trailer = {
|
349
|
+
auth_type: auth_type,
|
350
|
+
auth_level: auth_level,
|
351
|
+
auth_context_id: @ctx_id + @auth_ctx_id_base
|
352
|
+
}
|
353
|
+
dcerpc_req.auth_value = ' ' * 16
|
354
|
+
dcerpc_req.pdu_header.auth_length = 16
|
355
|
+
|
356
|
+
data_to_sign = plain_stub = dcerpc_req.stub.to_binary_s + dcerpc_req.auth_pad.to_binary_s
|
357
|
+
if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
|
358
|
+
data_to_sign = dcerpc_req.to_binary_s[0..-(dcerpc_req.pdu_header.auth_length + 1)]
|
359
|
+
end
|
360
|
+
|
361
|
+
encrypted_stub = ''
|
362
|
+
if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
363
|
+
case auth_type
|
364
|
+
when RPC_C_AUTHN_NONE
|
365
|
+
when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
|
366
|
+
encrypted_stub = @ntlm_client.session.seal_message(plain_stub)
|
367
|
+
when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
|
368
|
+
# TODO
|
369
|
+
raise NotImplementedError
|
370
|
+
else
|
371
|
+
raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
signature = @ntlm_client.session.sign_message(data_to_sign)
|
376
|
+
|
377
|
+
unless encrypted_stub.empty?
|
378
|
+
pad_length = dcerpc_req.sec_trailer.auth_pad_length.to_i
|
379
|
+
dcerpc_req.enable_encrypted_stub
|
380
|
+
dcerpc_req.stub = encrypted_stub[0..-(pad_length + 1)]
|
381
|
+
dcerpc_req.auth_pad = encrypted_stub[-(pad_length)..-1]
|
382
|
+
end
|
383
|
+
dcerpc_req.auth_value = signature
|
384
|
+
dcerpc_req.pdu_header.auth_length = signature.size
|
385
|
+
end
|
386
|
+
|
387
|
+
# Send a DCERPC request with the provided stub packet.
|
388
|
+
#
|
389
|
+
# @param stub_packet [BinData::Record] the stub packet to be sent as
|
390
|
+
# part of a Request packet
|
391
|
+
# @param opts [Hash] the authenticaiton options: `:auth_type` and `:auth_level`
|
392
|
+
# @raise [Error::CommunicationError] if socket-related error occurs
|
393
|
+
def dcerpc_request(stub_packet, auth_level: nil, auth_type: nil)
|
394
|
+
stub_class = stub_packet.class.name.split('::')
|
395
|
+
#opts.merge!(endpoint: stub_class[-2])
|
396
|
+
values = {
|
397
|
+
opnum: stub_packet.opnum,
|
398
|
+
p_cont_id: @ctx_id
|
399
|
+
}
|
400
|
+
dcerpc_req = Request.new(values, { endpoint: stub_class[-2] })
|
401
|
+
dcerpc_req.pdu_header.call_id = @call_id
|
402
|
+
dcerpc_req.stub.read(stub_packet.to_binary_s)
|
403
|
+
# TODO: handle fragmentation
|
404
|
+
# We should fragment PDUs if:
|
405
|
+
# 1) Payload exceeds max_xmit_frag (@max_buffer_size) received during BIND response
|
406
|
+
# 2) We'e explicitly fragmenting packets with lower values
|
407
|
+
|
408
|
+
if auth_level &&
|
409
|
+
[RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
|
410
|
+
set_integrity_privacy(dcerpc_req, auth_level: auth_level, auth_type: auth_type)
|
411
|
+
end
|
412
|
+
|
413
|
+
send_packet(dcerpc_req)
|
414
|
+
|
415
|
+
dcerpc_res = recv_struct(Response)
|
416
|
+
unless dcerpc_res.pdu_header.pfc_flags.first_frag == 1
|
417
|
+
raise Error::InvalidPacket, "Not the first fragment"
|
418
|
+
end
|
419
|
+
|
420
|
+
if auth_level &&
|
421
|
+
[RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
|
422
|
+
handle_integrity_privacy(dcerpc_res, auth_level: auth_level, auth_type: auth_type)
|
423
|
+
end
|
424
|
+
|
425
|
+
raw_stub = dcerpc_res.stub.to_binary_s
|
426
|
+
loop do
|
427
|
+
break if dcerpc_res.pdu_header.pfc_flags.last_frag == 1
|
428
|
+
dcerpc_res = recv_struct(Response)
|
429
|
+
|
430
|
+
if auth_level &&
|
431
|
+
[RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
|
432
|
+
handle_integrity_privacy(dcerpc_res, auth_level: auth_level, auth_type: auth_type)
|
433
|
+
end
|
434
|
+
|
435
|
+
raw_stub << dcerpc_res.stub.to_binary_s
|
436
|
+
end
|
437
|
+
|
438
|
+
raw_stub
|
439
|
+
end
|
440
|
+
|
441
|
+
# Send a packet to the remote host
|
442
|
+
#
|
443
|
+
# @param packet [BinData::Record] the packet to send
|
444
|
+
# @raise [Error::CommunicationError] if socket-related error occurs
|
445
|
+
def send_packet(packet)
|
446
|
+
data = packet.to_binary_s
|
447
|
+
bytes_written = 0
|
448
|
+
begin
|
449
|
+
loop do
|
450
|
+
break unless bytes_written < data.size
|
451
|
+
retval = @tcp_socket.write(data[bytes_written..-1])
|
452
|
+
bytes_written += retval
|
453
|
+
end
|
454
|
+
|
455
|
+
rescue IOError, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
|
456
|
+
raise Error::CommunicationError, "An error occurred writing to the Socket: #{e.message}"
|
457
|
+
end
|
458
|
+
nil
|
459
|
+
end
|
460
|
+
|
461
|
+
# Receive a packet from the remote host and parse it according to `struct`
|
462
|
+
#
|
463
|
+
# @param struct [Class] the structure class to parse the response with
|
464
|
+
# @raise [Error::CommunicationError] if socket-related error occurs
|
465
|
+
def recv_struct(struct)
|
466
|
+
raise Error::CommunicationError, 'Connection has already been closed' if @tcp_socket.closed?
|
467
|
+
if IO.select([@tcp_socket], nil, nil, @read_timeout).nil?
|
468
|
+
raise Error::CommunicationError, "Read timeout expired when reading from the Socket (timeout=#{@read_timeout})"
|
469
|
+
end
|
470
|
+
|
471
|
+
begin
|
472
|
+
response = struct.read(@tcp_socket)
|
473
|
+
rescue IOError
|
474
|
+
raise Error::InvalidPacket, "Error reading the #{struct} response"
|
475
|
+
end
|
476
|
+
unless response.pdu_header.ptype == struct::PTYPE
|
477
|
+
raise Error::InvalidPacket, "Not a #{struct} packet"
|
478
|
+
end
|
479
|
+
|
480
|
+
response
|
481
|
+
rescue Errno::EINVAL, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
|
482
|
+
raise Error::CommunicationError, "An error occurred reading from the Socket: #{e.message}"
|
483
|
+
end
|
484
|
+
|
485
|
+
# Process the security context received in a response. It decrypts the
|
486
|
+
# encrypted stub if `:auth_level` is set to anything different than
|
487
|
+
# RPC_C_AUTHN_LEVEL_PKT_PRIVACY. It also checks the packet signature and
|
488
|
+
# raises an InvalidPacket error if it fails. Note that the exception is
|
489
|
+
# disabled by default and can be enabled with the
|
490
|
+
# `:raise_signature_error` option
|
491
|
+
#
|
492
|
+
# @param dcerpc_response [Response] the Response packet
|
493
|
+
# containing the security context to process
|
494
|
+
# @param opts [Hash] the authenticaiton options: `:auth_type` and
|
495
|
+
# `:auth_level`. To enable errors when signature check fails, set the
|
496
|
+
# `:raise_signature_error` option to true
|
497
|
+
# @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
|
498
|
+
# @raise [Error::CommunicationError] if socket-related error occurs
|
499
|
+
def handle_integrity_privacy(dcerpc_response, auth_level:, auth_type:, raise_signature_error: false)
|
500
|
+
decrypted_stub = ''
|
501
|
+
if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
|
502
|
+
encrypted_stub = dcerpc_response.stub.to_binary_s + dcerpc_response.auth_pad.to_binary_s
|
503
|
+
case auth_type
|
504
|
+
when RPC_C_AUTHN_NONE
|
505
|
+
when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
|
506
|
+
decrypted_stub = @ntlm_client.session.unseal_message(encrypted_stub)
|
507
|
+
when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
|
508
|
+
# TODO
|
509
|
+
raise NotImplementedError
|
510
|
+
else
|
511
|
+
raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
unless decrypted_stub.empty?
|
516
|
+
pad_length = dcerpc_response.sec_trailer.auth_pad_length.to_i
|
517
|
+
dcerpc_response.stub = decrypted_stub[0..-(pad_length + 1)]
|
518
|
+
dcerpc_response.auth_pad = decrypted_stub[-(pad_length)..-1]
|
519
|
+
end
|
520
|
+
|
521
|
+
signature = dcerpc_response.auth_value
|
522
|
+
data_to_check = dcerpc_response.stub.to_binary_s
|
523
|
+
if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
|
524
|
+
data_to_check = dcerpc_response.to_binary_s[0..-(dcerpc_response.pdu_header.auth_length + 1)]
|
525
|
+
end
|
526
|
+
unless @ntlm_client.session.verify_signature(signature, data_to_check)
|
527
|
+
if raise_signature_error
|
528
|
+
raise Error::InvalidPacket.new(
|
529
|
+
"Wrong packet signature received (set `raise_signature_error` to false to ignore)"
|
530
|
+
)
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
@call_id += 1
|
535
|
+
|
536
|
+
nil
|
537
|
+
end
|
538
|
+
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Drsr
|
4
|
+
|
5
|
+
# [4.1.3 IDL_DRSBind (Opnum 0)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/605b1ea1-9cdc-428f-ab7a-70120e020a3d)
|
6
|
+
class DrsBindRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
uuid_ptr :puuid_client_dsa, initial_value: NTSAPI_CLIENT_GUID
|
12
|
+
drs_extensions_ptr :pext_client
|
13
|
+
|
14
|
+
def initialize_instance
|
15
|
+
super
|
16
|
+
@opnum = DRS_BIND
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Drsr
|
4
|
+
|
5
|
+
# [4.1.3 IDL_DRSBind (Opnum 0)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/605b1ea1-9cdc-428f-ab7a-70120e020a3d)
|
6
|
+
class DrsBindResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
drs_extensions_ptr :ppext_server
|
12
|
+
drs_handle :ph_drs
|
13
|
+
ndr_uint32 :error_status
|
14
|
+
|
15
|
+
def initialize_instance
|
16
|
+
super
|
17
|
+
@opnum = DRS_BIND
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Drsr
|
4
|
+
|
5
|
+
class DrsNameArrayPtr < Ndr::NdrConfArray
|
6
|
+
default_parameters type: :ndr_wide_stringz_ptr
|
7
|
+
extend Ndr::PointerClassPlugin
|
8
|
+
end
|
9
|
+
|
10
|
+
#[4.1.4.1.2 DRS_MSG_CRACKREQ_V1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/b47debc0-59ee-40e4-ad0f-4bc9f96043b2)
|
11
|
+
class DrsMsgCrackreqV1 < Ndr::NdrStruct
|
12
|
+
default_parameter byte_align: 4
|
13
|
+
endian :little
|
14
|
+
|
15
|
+
ndr_uint32 :code_page
|
16
|
+
ndr_uint32 :locale_id
|
17
|
+
ndr_uint32 :dw_flags
|
18
|
+
ndr_uint32 :format_offered
|
19
|
+
ndr_uint32 :format_desired
|
20
|
+
ndr_uint32 :c_names, initial_value: -> { rp_names.size }
|
21
|
+
drs_name_array_ptr :rp_names
|
22
|
+
end
|
23
|
+
|
24
|
+
# [4.1.4.1.1 DRS_MSG_CRACKREQ](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/f2d5166e-09f6-4788-a391-66471b2f7d6d)
|
25
|
+
class DrsMsgCrackreq < Ndr::NdrStruct
|
26
|
+
default_parameter byte_align: 4
|
27
|
+
endian :little
|
28
|
+
|
29
|
+
ndr_uint32 :switch_type, initial_value: 1
|
30
|
+
choice :msg_crack, selection: :switch_type, byte_align: 4 do
|
31
|
+
drs_msg_crackreq_v1 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# [4.1.4 IDL_DRSCrackNames (Opnum 12)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/9b4bfb44-6656-4404-bcc8-dc88111658b3)
|
36
|
+
class DrsCrackNamesRequest < BinData::Record
|
37
|
+
attr_reader :opnum
|
38
|
+
|
39
|
+
endian :little
|
40
|
+
|
41
|
+
drs_handle :h_drs
|
42
|
+
ndr_uint32 :dw_in_version, initial_value: 1
|
43
|
+
drs_msg_crackreq :pmsg_in
|
44
|
+
|
45
|
+
def initialize_instance
|
46
|
+
super
|
47
|
+
@opnum = DRS_CRACK_NAMES
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
|