ruby_smb 2.0.2 → 3.0.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 +46 -0
- data/README.md +0 -1
- data/examples/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/auth_capture.rb +71 -0
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/dump_secrets_from_sid.rb +207 -0
- data/examples/enum_domain_users.rb +75 -0
- data/examples/enum_registry_key.rb +5 -4
- data/examples/enum_registry_values.rb +5 -4
- data/examples/get_computer_info.rb +42 -0
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +11 -12
- data/examples/query_service_status.rb +102 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_registry_key_value.rb +6 -5
- data/examples/rename_file.rb +9 -7
- data/examples/tree_connect.rb +7 -5
- data/examples/write_file.rb +9 -7
- data/lib/ruby_smb/client/authentication.rb +5 -10
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/negotiation.rb +13 -16
- data/lib/ruby_smb/client/tree_connect.rb +2 -4
- data/lib/ruby_smb/client/utils.rb +16 -10
- data/lib/ruby_smb/client/winreg.rb +1 -1
- data/lib/ruby_smb/client.rb +102 -75
- data/lib/ruby_smb/compression/lznt1.rb +164 -0
- data/lib/ruby_smb/compression.rb +7 -0
- 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 +20 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +1204 -80
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/netlogon.rb +102 -0
- 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 +85 -19
- 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 +34 -0
- 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 +36 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +45 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl.rb +477 -0
- 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 +62 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +2 -19
- 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 +6 -7
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +2 -2
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +9 -18
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +4 -13
- 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 +28 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +99 -22
- 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 +45 -11
- data/lib/ruby_smb/dialect.rb +45 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +2 -2
- data/lib/ruby_smb/error.rb +21 -5
- data/lib/ruby_smb/field/file_time.rb +1 -1
- data/lib/ruby_smb/field/string16.rb +5 -1
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/generic_packet.rb +11 -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/nbss/session_header.rb +4 -4
- 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/file.rb +10 -25
- 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/packet/trans2/find_first2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
- data/lib/ruby_smb/smb1/pipe.rb +12 -6
- data/lib/ruby_smb/smb1/tree.rb +13 -9
- data/lib/ruby_smb/smb2/file.rb +33 -33
- data/lib/ruby_smb/smb2/negotiate_context.rb +18 -2
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +4 -0
- 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 +13 -6
- data/lib/ruby_smb/smb2/tree.rb +21 -11
- data/lib/ruby_smb/smb2.rb +3 -1
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +199 -86
- data/spec/lib/ruby_smb/compression/lznt1_spec.rb +32 -0
- 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 +3977 -239
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
- 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 +162 -0
- 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 +168 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +68 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +53 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +76 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +47 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +508 -0
- 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 +73 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +4 -56
- 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 -20
- 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_request_spec.rb +0 -4
- 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 +18 -42
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +4 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +45 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +219 -62
- 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/dispatcher/socket_spec.rb +10 -10
- data/spec/lib/ruby_smb/error_spec.rb +34 -5
- data/spec/lib/ruby_smb/field/string16_spec.rb +22 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -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/nbss/session_header_spec.rb +4 -11
- 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/file_spec.rb +2 -4
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +20 -14
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +20 -14
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/bin_helper.rb +9 -0
- data.tar.gz.sig +0 -0
- metadata +229 -23
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -6
- data/lib/ruby_smb/client/signing.rb +0 -64
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +0 -35
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +0 -98
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
3
|
+
module RubySMB
|
|
4
|
+
class Server
|
|
5
|
+
class ServerClient
|
|
6
|
+
module Negotiation
|
|
7
|
+
#
|
|
8
|
+
# Handle an SMB negotiation request. Once negotiation is complete, the state will be updated to :session_setup.
|
|
9
|
+
# At this point the @dialect will have been set along with other dialect-specific values.
|
|
10
|
+
#
|
|
11
|
+
# @param [String] raw_request the negotiation request to process
|
|
12
|
+
def handle_negotiate(raw_request)
|
|
13
|
+
response = nil
|
|
14
|
+
case raw_request[0...4].unpack1('L>')
|
|
15
|
+
when RubySMB::SMB1::SMB_PROTOCOL_ID
|
|
16
|
+
request = SMB1::Packet::NegotiateRequest.read(raw_request)
|
|
17
|
+
response = do_negotiate_smb1(request) if request.is_a?(SMB1::Packet::NegotiateRequest)
|
|
18
|
+
when RubySMB::SMB2::SMB2_PROTOCOL_ID
|
|
19
|
+
request = SMB2::Packet::NegotiateRequest.read(raw_request)
|
|
20
|
+
response = do_negotiate_smb2(request) if request.is_a?(SMB2::Packet::NegotiateRequest)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if response.nil?
|
|
24
|
+
disconnect!
|
|
25
|
+
else
|
|
26
|
+
send_packet(response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
nil
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def do_negotiate_smb1(request)
|
|
33
|
+
client_dialects = request.dialects.map(&:dialect_string).map(&:value)
|
|
34
|
+
|
|
35
|
+
if client_dialects.include?(Client::SMB1_DIALECT_SMB2_WILDCARD) && \
|
|
36
|
+
@server.dialects.any? { |dialect| Dialect[dialect].order == Dialect::ORDER_SMB2 }
|
|
37
|
+
response = SMB2::Packet::NegotiateResponse.new
|
|
38
|
+
response.smb2_header.credits = 1
|
|
39
|
+
response.security_mode.signing_enabled = 1
|
|
40
|
+
response.dialect_revision = SMB2::SMB2_WILDCARD_REVISION
|
|
41
|
+
response.server_guid = @server.guid
|
|
42
|
+
|
|
43
|
+
response.max_transact_size = 0x800000
|
|
44
|
+
response.max_read_size = 0x800000
|
|
45
|
+
response.max_write_size = 0x800000
|
|
46
|
+
response.system_time.set(Time.now)
|
|
47
|
+
response.security_buffer_offset = response.security_buffer.abs_offset
|
|
48
|
+
response.security_buffer = process_gss.buffer
|
|
49
|
+
return response
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
server_dialects = @server.dialects.select { |dialect| Dialect[dialect].order == Dialect::ORDER_SMB1 }
|
|
53
|
+
dialect = (server_dialects & client_dialects).first
|
|
54
|
+
if dialect.nil?
|
|
55
|
+
# 'NT LM 0.12' is currently the only supported dialect
|
|
56
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/80850595-e301-4464-9745-58e4945eb99b
|
|
57
|
+
response = SMB1::Packet::NegotiateResponse.new
|
|
58
|
+
response.parameter_block.word_count = 1
|
|
59
|
+
response.parameter_block.dialect_index = 0xffff
|
|
60
|
+
response.data_block.byte_count = 0
|
|
61
|
+
return response
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
response = SMB1::Packet::NegotiateResponseExtended.new
|
|
65
|
+
response.parameter_block.dialect_index = client_dialects.index(dialect)
|
|
66
|
+
response.parameter_block.max_mpx_count = 50
|
|
67
|
+
response.parameter_block.max_number_vcs = 1
|
|
68
|
+
response.parameter_block.max_buffer_size = 16644
|
|
69
|
+
response.parameter_block.max_raw_size = 65536
|
|
70
|
+
server_time = Time.now
|
|
71
|
+
response.parameter_block.system_time.set(server_time)
|
|
72
|
+
response.parameter_block.server_time_zone = server_time.utc_offset
|
|
73
|
+
response.data_block.server_guid = @server.guid
|
|
74
|
+
response.data_block.security_blob = process_gss.buffer
|
|
75
|
+
|
|
76
|
+
@state = :session_setup
|
|
77
|
+
@dialect = dialect
|
|
78
|
+
response
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def do_negotiate_smb2(request)
|
|
82
|
+
client_dialects = request.dialects.map { |d| "0x%04x" % d }
|
|
83
|
+
server_dialects = @server.dialects.select { |dialect| Dialect[dialect].order == Dialect::ORDER_SMB2 }
|
|
84
|
+
dialect = (server_dialects & client_dialects).first
|
|
85
|
+
|
|
86
|
+
response = SMB2::Packet::NegotiateResponse.new
|
|
87
|
+
response.smb2_header.credits = 1
|
|
88
|
+
response.smb2_header.message_id = request.smb2_header.message_id
|
|
89
|
+
response.security_mode.signing_enabled = 1
|
|
90
|
+
response.server_guid = @server.guid
|
|
91
|
+
response.max_transact_size = 0x800000
|
|
92
|
+
response.max_read_size = 0x800000
|
|
93
|
+
response.max_write_size = 0x800000
|
|
94
|
+
response.system_time.set(Time.now)
|
|
95
|
+
if dialect.nil?
|
|
96
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/b39f253e-4963-40df-8dff-2f9040ebbeb1
|
|
97
|
+
# > If a common dialect is not found, the server MUST fail the request with STATUS_NOT_SUPPORTED.
|
|
98
|
+
response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_NOT_SUPPORTED.value
|
|
99
|
+
return response
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
contexts = []
|
|
103
|
+
hash_algorithm = hash_value = nil
|
|
104
|
+
if dialect == '0x0311'
|
|
105
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/b39f253e-4963-40df-8dff-2f9040ebbeb1
|
|
106
|
+
nc = request.find_negotiate_context(SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES)
|
|
107
|
+
hash_algorithm = SMB2::PreauthIntegrityCapabilities::HASH_ALGORITM_MAP[nc&.data&.hash_algorithms&.first]
|
|
108
|
+
hash_value = "\x00" * 64
|
|
109
|
+
unless hash_algorithm
|
|
110
|
+
response.smb2_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_PARAMETER.value
|
|
111
|
+
return response
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
contexts << SMB2::NegotiateContext.new(
|
|
115
|
+
context_type: SMB2::NegotiateContext::SMB2_PREAUTH_INTEGRITY_CAPABILITIES,
|
|
116
|
+
data: {
|
|
117
|
+
hash_algorithms: [ SMB2::PreauthIntegrityCapabilities::SHA_512 ],
|
|
118
|
+
salt: SecureRandom.random_bytes(32)
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
nc = request.find_negotiate_context(SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES)
|
|
123
|
+
cipher = nc&.data&.ciphers&.first
|
|
124
|
+
cipher = 0 unless SMB2::EncryptionCapabilities::ENCRYPTION_ALGORITHM_MAP.include? cipher
|
|
125
|
+
contexts << SMB2::NegotiateContext.new(
|
|
126
|
+
context_type: SMB2::NegotiateContext::SMB2_ENCRYPTION_CAPABILITIES,
|
|
127
|
+
data: {
|
|
128
|
+
ciphers: [ cipher ]
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# the order in which the response is built is important to ensure it is valid
|
|
134
|
+
response.dialect_revision = dialect.to_i(16)
|
|
135
|
+
response.security_buffer_offset = response.security_buffer.abs_offset
|
|
136
|
+
response.security_buffer = process_gss.buffer
|
|
137
|
+
if dialect == '0x0311'
|
|
138
|
+
response.negotiate_context_offset = response.negotiate_context_list.abs_offset
|
|
139
|
+
contexts.each { |nc| response.add_negotiate_context(nc) }
|
|
140
|
+
end
|
|
141
|
+
@preauth_integrity_hash_algorithm = hash_algorithm
|
|
142
|
+
@preauth_integrity_hash_value = hash_value
|
|
143
|
+
|
|
144
|
+
if dialect == '0x0311'
|
|
145
|
+
update_preauth_hash(request)
|
|
146
|
+
update_preauth_hash(response)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
@state = :session_setup
|
|
150
|
+
@dialect = dialect
|
|
151
|
+
response
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
class Server
|
|
3
|
+
class ServerClient
|
|
4
|
+
module SessionSetup
|
|
5
|
+
#
|
|
6
|
+
# Setup a new session based on the negotiated dialect. Once session setup is complete, the state will be updated
|
|
7
|
+
# to :authenticated.
|
|
8
|
+
#
|
|
9
|
+
# @param [String] raw_request the session setup request to process
|
|
10
|
+
def handle_session_setup(raw_request)
|
|
11
|
+
response = nil
|
|
12
|
+
|
|
13
|
+
case metadialect.order
|
|
14
|
+
when Dialect::ORDER_SMB1
|
|
15
|
+
request = SMB1::Packet::SessionSetupRequest.read(raw_request)
|
|
16
|
+
response = do_session_setup_smb1(request)
|
|
17
|
+
when Dialect::ORDER_SMB2
|
|
18
|
+
request = SMB2::Packet::SessionSetupRequest.read(raw_request)
|
|
19
|
+
response = do_session_setup_smb2(request)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if response.nil?
|
|
23
|
+
disconnect!
|
|
24
|
+
else
|
|
25
|
+
send_packet(response)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def do_session_setup_smb1(request)
|
|
32
|
+
gss_result = process_gss(request.data_block.security_blob)
|
|
33
|
+
return if gss_result.nil?
|
|
34
|
+
|
|
35
|
+
response = SMB1::Packet::SessionSetupResponse.new
|
|
36
|
+
response.smb_header.pid_low = request.smb_header.pid_low
|
|
37
|
+
response.smb_header.uid = rand(0x10000)
|
|
38
|
+
response.smb_header.mid = request.smb_header.mid
|
|
39
|
+
response.smb_header.nt_status = gss_result.nt_status.value
|
|
40
|
+
response.smb_header.flags.reply = true
|
|
41
|
+
response.smb_header.flags2.unicode = true
|
|
42
|
+
response.smb_header.flags2.extended_security = true
|
|
43
|
+
unless gss_result.buffer.nil?
|
|
44
|
+
response.parameter_block.security_blob_length = gss_result.buffer.length
|
|
45
|
+
response.data_block.security_blob = gss_result.buffer
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if gss_result.nt_status == WindowsError::NTStatus::STATUS_SUCCESS
|
|
49
|
+
@state = :authenticated
|
|
50
|
+
@identity = gss_result.identity
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
response
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def do_session_setup_smb2(request)
|
|
57
|
+
gss_result = process_gss(request.buffer)
|
|
58
|
+
return if gss_result.nil?
|
|
59
|
+
|
|
60
|
+
response = SMB2::Packet::SessionSetupResponse.new
|
|
61
|
+
response.smb2_header.nt_status = gss_result.nt_status.value
|
|
62
|
+
response.smb2_header.credits = 1
|
|
63
|
+
response.smb2_header.message_id = request.smb2_header.message_id
|
|
64
|
+
response.smb2_header.session_id = @session_id = @session_id || SecureRandom.random_bytes(4).unpack1('V')
|
|
65
|
+
response.buffer = gss_result.buffer
|
|
66
|
+
|
|
67
|
+
update_preauth_hash(request) if @dialect == '0x0311'
|
|
68
|
+
if gss_result.nt_status == WindowsError::NTStatus::STATUS_SUCCESS
|
|
69
|
+
@state = :authenticated
|
|
70
|
+
@identity = gss_result.identity
|
|
71
|
+
@session_key = @gss_authenticator.session_key
|
|
72
|
+
elsif gss_result.nt_status == WindowsError::NTStatus::STATUS_MORE_PROCESSING_REQUIRED && @dialect == '0x0311'
|
|
73
|
+
update_preauth_hash(response)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
response
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
class Server
|
|
3
|
+
# This class represents a single connected client to the server. It stores and processes connection specific related
|
|
4
|
+
# information.
|
|
5
|
+
class ServerClient
|
|
6
|
+
|
|
7
|
+
require 'ruby_smb/dialect'
|
|
8
|
+
require 'ruby_smb/signing'
|
|
9
|
+
require 'ruby_smb/server/server_client/negotiation'
|
|
10
|
+
require 'ruby_smb/server/server_client/session_setup'
|
|
11
|
+
|
|
12
|
+
include RubySMB::Signing
|
|
13
|
+
include RubySMB::Server::ServerClient::Negotiation
|
|
14
|
+
include RubySMB::Server::ServerClient::SessionSetup
|
|
15
|
+
|
|
16
|
+
attr_reader :dialect, :identity, :state, :session_key
|
|
17
|
+
|
|
18
|
+
# @param [Server] server the server that accepted this connection
|
|
19
|
+
# @param [Dispatcher::Socket] dispatcher the connection's socket dispatcher
|
|
20
|
+
def initialize(server, dispatcher)
|
|
21
|
+
@server = server
|
|
22
|
+
@dispatcher = dispatcher
|
|
23
|
+
@state = :negotiate
|
|
24
|
+
@dialect = nil
|
|
25
|
+
@session_id = nil
|
|
26
|
+
@session_key = nil
|
|
27
|
+
@gss_authenticator = server.gss_provider.new_authenticator(self)
|
|
28
|
+
@identity = nil
|
|
29
|
+
@tree_connections = {}
|
|
30
|
+
@preauth_integrity_hash_algorithm = nil
|
|
31
|
+
@preauth_integrity_hash_value = nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
# The dialects metadata definition.
|
|
36
|
+
#
|
|
37
|
+
# @return [Dialect::Definition]
|
|
38
|
+
def metadialect
|
|
39
|
+
Dialect::ALL[@dialect]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# The peername of the connected socket. This is a combination of the IPv4 or IPv6 address and port number.
|
|
44
|
+
#
|
|
45
|
+
# @example Parse the value into an IP address
|
|
46
|
+
# ::Socket::unpack_sockaddr_in(server_client.getpeername)
|
|
47
|
+
#
|
|
48
|
+
# @return [String]
|
|
49
|
+
def getpeername
|
|
50
|
+
@dispatcher.tcp_socket.getpeername
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
#
|
|
54
|
+
# Handle an authenticated request. This is the main handler for all requests after the connection has been
|
|
55
|
+
# authenticated.
|
|
56
|
+
#
|
|
57
|
+
# @param [String] raw_request the request that should be handled
|
|
58
|
+
def handle_authenticated(raw_request)
|
|
59
|
+
response = nil
|
|
60
|
+
|
|
61
|
+
case raw_request[0...4].unpack1('L>')
|
|
62
|
+
when RubySMB::SMB1::SMB_PROTOCOL_ID
|
|
63
|
+
raise NotImplementedError
|
|
64
|
+
when RubySMB::SMB2::SMB2_PROTOCOL_ID
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if response.nil?
|
|
69
|
+
disconnect!
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
send_packet(response)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
# Process a GSS authentication buffer. If no buffer is specified, the request is assumed to be the first in the
|
|
78
|
+
# negotiation sequence.
|
|
79
|
+
#
|
|
80
|
+
# @param [String, nil] buffer the request GSS request buffer that should be processed
|
|
81
|
+
# @return [Gss::Provider::Result] the result of the processed GSS request
|
|
82
|
+
def process_gss(buffer=nil)
|
|
83
|
+
@gss_authenticator.process(buffer)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
#
|
|
87
|
+
# Run the processing loop to receive and handle requests. This loop runs until an exception occurs or the
|
|
88
|
+
# dispatcher socket is closed.
|
|
89
|
+
#
|
|
90
|
+
def run
|
|
91
|
+
loop do
|
|
92
|
+
begin
|
|
93
|
+
raw_request = recv_packet
|
|
94
|
+
rescue RubySMB::Error::CommunicationError
|
|
95
|
+
break
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
case @state
|
|
99
|
+
when :negotiate
|
|
100
|
+
handle_negotiate(raw_request)
|
|
101
|
+
when :session_setup
|
|
102
|
+
handle_session_setup(raw_request)
|
|
103
|
+
when :authenticated
|
|
104
|
+
handle_authenticated(raw_request)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
break if @dispatcher.tcp_socket.closed?
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#
|
|
112
|
+
# Disconnect the remote client.
|
|
113
|
+
#
|
|
114
|
+
def disconnect!
|
|
115
|
+
@state = nil
|
|
116
|
+
@dispatcher.tcp_socket.close
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
#
|
|
120
|
+
# Receive a single SMB packet from the dispatcher.
|
|
121
|
+
#
|
|
122
|
+
# @return [String] the raw packet
|
|
123
|
+
def recv_packet
|
|
124
|
+
@dispatcher.recv_packet
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# Send a single SMB packet using the dispatcher. If necessary, the packet will be signed.
|
|
129
|
+
#
|
|
130
|
+
# @param [GenericPacket] packet the packet to send
|
|
131
|
+
def send_packet(packet)
|
|
132
|
+
if @state == :authenticated && @identity != Gss::Provider::IDENTITY_ANONYMOUS && !@session_key.nil?
|
|
133
|
+
case metadialect.family
|
|
134
|
+
when Dialect::FAMILY_SMB2
|
|
135
|
+
packet = smb2_sign(packet)
|
|
136
|
+
when Dialect::FAMILY_SMB3
|
|
137
|
+
packet = smb3_sign(packet)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
@dispatcher.send_packet(packet)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
#
|
|
145
|
+
# Update the preauth integrity hash as used by dialect 3.1.1 for various cryptographic operations. The algorithm
|
|
146
|
+
# and hash values must have been initialized prior to calling this.
|
|
147
|
+
#
|
|
148
|
+
# @param [String] data the data with which to update the preauth integrity hash
|
|
149
|
+
def update_preauth_hash(data)
|
|
150
|
+
unless @preauth_integrity_hash_algorithm
|
|
151
|
+
raise RubySMB::Error::EncryptionError.new(
|
|
152
|
+
'Cannot compute the Preauth Integrity Hash value: Preauth Integrity Hash Algorithm is nil'
|
|
153
|
+
)
|
|
154
|
+
end
|
|
155
|
+
@preauth_integrity_hash_value = OpenSSL::Digest.digest(
|
|
156
|
+
@preauth_integrity_hash_algorithm,
|
|
157
|
+
@preauth_integrity_hash_value + data.to_binary_s
|
|
158
|
+
)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
|
|
3
|
+
module RubySMB
|
|
4
|
+
# This class provides the SMB server core. Settings that are relevant server wide are managed by this object.
|
|
5
|
+
# Currently, the server only supports negotiating and authenticating requests. No other server functionality is
|
|
6
|
+
# available at this time. The negotiating and authentication is supported for SMB versions 1 through 3.1.1.
|
|
7
|
+
class Server
|
|
8
|
+
require 'ruby_smb/server/server_client'
|
|
9
|
+
require 'ruby_smb/gss/provider/ntlm'
|
|
10
|
+
|
|
11
|
+
Connection = Struct.new(:client, :thread)
|
|
12
|
+
|
|
13
|
+
# @param server_sock the socket on which the server should listen
|
|
14
|
+
# @param [Gss::Provider] the authentication provider
|
|
15
|
+
def initialize(server_sock: nil, gss_provider: nil)
|
|
16
|
+
server_sock = ::TCPServer.new(445) if server_sock.nil?
|
|
17
|
+
|
|
18
|
+
@guid = Random.new.bytes(16)
|
|
19
|
+
@socket = server_sock
|
|
20
|
+
@connections = []
|
|
21
|
+
@gss_provider = gss_provider || Gss::Provider::NTLM.new
|
|
22
|
+
# reject the wildcard dialect because it's not a real dialect we can use for this purpose
|
|
23
|
+
@dialects = RubySMB::Dialect::ALL.keys.reject { |dialect| dialect == "0x%04x" % RubySMB::SMB2::SMB2_WILDCARD_REVISION }.reverse
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Run the server and accept any connections. For each connection, the block will be executed if specified. When the
|
|
27
|
+
# block returns false, the loop will exit and the server will no long accept new connections.
|
|
28
|
+
def run(&block)
|
|
29
|
+
loop do
|
|
30
|
+
sock = @socket.accept
|
|
31
|
+
server_client = ServerClient.new(self, RubySMB::Dispatcher::Socket.new(sock))
|
|
32
|
+
@connections << Connection.new(server_client, Thread.new { server_client.run })
|
|
33
|
+
|
|
34
|
+
break unless block.nil? || block.call(server_client)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The dialects that this server will negotiate with clients, in ascending order of preference.
|
|
39
|
+
# @!attribute [r] dialects
|
|
40
|
+
# @return [Array<String>]
|
|
41
|
+
attr_accessor :dialects
|
|
42
|
+
|
|
43
|
+
# The GSS Provider instance that this server will use to authenticate
|
|
44
|
+
# incoming client connections.
|
|
45
|
+
# @!attribute [r] gss_provider
|
|
46
|
+
# @return [RubySMB::Gss::Provider::Base]
|
|
47
|
+
attr_reader :gss_provider
|
|
48
|
+
|
|
49
|
+
# The 16 byte GUID that uniquely identifies this server instance.
|
|
50
|
+
# @!attribute [r] guid
|
|
51
|
+
attr_reader :guid
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
# Contains the methods for handling packet signing
|
|
3
|
+
module Signing
|
|
4
|
+
# The NTLM Session Key used for signing
|
|
5
|
+
# @!attribute [rw] session_key
|
|
6
|
+
# @return [String]
|
|
7
|
+
attr_accessor :session_key
|
|
8
|
+
|
|
9
|
+
# Take an SMB1 packet and sign it.
|
|
10
|
+
#
|
|
11
|
+
# @param packet [RubySMB::GenericPacket] the packet to sign
|
|
12
|
+
# @return [RubySMB::GenericPacket] the signed packet
|
|
13
|
+
def smb1_sign(packet)
|
|
14
|
+
# Pack the Sequence counter into a int64le
|
|
15
|
+
packed_sequence_counter = [sequence_counter].pack('Q<')
|
|
16
|
+
packet.smb_header.security_features = packed_sequence_counter
|
|
17
|
+
signature = OpenSSL::Digest::MD5.digest(session_key + packet.to_binary_s)[0, 8]
|
|
18
|
+
packet.smb_header.security_features = signature
|
|
19
|
+
@sequence_counter += 1
|
|
20
|
+
|
|
21
|
+
packet
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Take an SMB2 packet and sign it.
|
|
25
|
+
#
|
|
26
|
+
# @param packet [RubySMB::GenericPacket] the packet to sign
|
|
27
|
+
# @return [RubySMB::GenericPacket] the signed packet
|
|
28
|
+
def smb2_sign(packet)
|
|
29
|
+
packet.smb2_header.flags.signed = 1
|
|
30
|
+
packet.smb2_header.signature = "\x00" * 16
|
|
31
|
+
hmac = OpenSSL::HMAC.digest(OpenSSL::Digest.new('SHA256'), session_key, packet.to_binary_s)
|
|
32
|
+
packet.smb2_header.signature = hmac[0, 16]
|
|
33
|
+
|
|
34
|
+
packet
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Take an SMB3 packet and sign it.
|
|
38
|
+
#
|
|
39
|
+
# @param packet [RubySMB::GenericPacket] the packet to sign
|
|
40
|
+
# @return [RubySMB::GenericPacket] the signed packet
|
|
41
|
+
def smb3_sign(packet)
|
|
42
|
+
case @dialect
|
|
43
|
+
when '0x0300', '0x0302'
|
|
44
|
+
signing_key = Crypto::KDF.counter_mode(@session_key, "SMB2AESCMAC\x00", "SmbSign\x00")
|
|
45
|
+
when '0x0311'
|
|
46
|
+
signing_key = Crypto::KDF.counter_mode(@session_key, "SMBSigningKey\x00", @preauth_integrity_hash_value)
|
|
47
|
+
else
|
|
48
|
+
raise Error::SigningError.new("Dialect #{@dialect.inspect} is incompatible with SMBv3 signing")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
packet.smb2_header.flags.signed = 1
|
|
52
|
+
packet.smb2_header.signature = "\x00" * 16
|
|
53
|
+
hmac = OpenSSL::CMAC.digest('AES', signing_key, packet.to_binary_s)
|
|
54
|
+
packet.smb2_header.signature = hmac[0, 16]
|
|
55
|
+
|
|
56
|
+
packet
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/ruby_smb/smb1/file.rb
CHANGED
|
@@ -86,8 +86,7 @@ module RubySMB
|
|
|
86
86
|
raise RubySMB::Error::InvalidPacket.new(
|
|
87
87
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
88
88
|
expected_cmd: RubySMB::SMB1::Packet::CloseResponse::COMMAND,
|
|
89
|
-
|
|
90
|
-
received_cmd: response.smb_header.command
|
|
89
|
+
packet: response
|
|
91
90
|
)
|
|
92
91
|
end
|
|
93
92
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
@@ -106,11 +105,7 @@ module RubySMB
|
|
|
106
105
|
# @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
|
|
107
106
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
|
108
107
|
def read(bytes: @size, offset: 0)
|
|
109
|
-
atomic_read_size =
|
|
110
|
-
@tree.client.max_buffer_size
|
|
111
|
-
else
|
|
112
|
-
bytes
|
|
113
|
-
end
|
|
108
|
+
atomic_read_size = [bytes, @tree.client.max_buffer_size].min
|
|
114
109
|
remaining_bytes = bytes
|
|
115
110
|
data = ''
|
|
116
111
|
|
|
@@ -122,8 +117,7 @@ module RubySMB
|
|
|
122
117
|
raise RubySMB::Error::InvalidPacket.new(
|
|
123
118
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
124
119
|
expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
|
|
125
|
-
|
|
126
|
-
received_cmd: response.smb_header.command
|
|
120
|
+
packet: response
|
|
127
121
|
)
|
|
128
122
|
end
|
|
129
123
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
@@ -171,8 +165,7 @@ module RubySMB
|
|
|
171
165
|
raise RubySMB::Error::InvalidPacket.new(
|
|
172
166
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
173
167
|
expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
|
|
174
|
-
|
|
175
|
-
received_cmd: response.smb_header.command
|
|
168
|
+
packet: response
|
|
176
169
|
)
|
|
177
170
|
end
|
|
178
171
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
@@ -193,8 +186,7 @@ module RubySMB
|
|
|
193
186
|
raise RubySMB::Error::InvalidPacket.new(
|
|
194
187
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
195
188
|
expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
|
|
196
|
-
|
|
197
|
-
received_cmd: response.smb_header.command
|
|
189
|
+
packet: response
|
|
198
190
|
)
|
|
199
191
|
end
|
|
200
192
|
response.status_code
|
|
@@ -227,11 +219,7 @@ module RubySMB
|
|
|
227
219
|
total_bytes_written = 0
|
|
228
220
|
|
|
229
221
|
loop do
|
|
230
|
-
atomic_write_size =
|
|
231
|
-
@tree.client.max_buffer_size
|
|
232
|
-
else
|
|
233
|
-
bytes
|
|
234
|
-
end
|
|
222
|
+
atomic_write_size = [bytes, @tree.client.max_buffer_size].min
|
|
235
223
|
write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset)
|
|
236
224
|
raw_response = @tree.client.send_recv(write_request)
|
|
237
225
|
response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
|
|
@@ -239,8 +227,7 @@ module RubySMB
|
|
|
239
227
|
raise RubySMB::Error::InvalidPacket.new(
|
|
240
228
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
241
229
|
expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
|
|
242
|
-
|
|
243
|
-
received_cmd: response.smb_header.command
|
|
230
|
+
packet: response
|
|
244
231
|
)
|
|
245
232
|
end
|
|
246
233
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
@@ -279,8 +266,7 @@ module RubySMB
|
|
|
279
266
|
raise RubySMB::Error::InvalidPacket.new(
|
|
280
267
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
281
268
|
expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
|
|
282
|
-
|
|
283
|
-
received_cmd: response.smb_header.command
|
|
269
|
+
packet: response
|
|
284
270
|
)
|
|
285
271
|
end
|
|
286
272
|
response.parameter_block.count_low
|
|
@@ -298,8 +284,7 @@ module RubySMB
|
|
|
298
284
|
raise RubySMB::Error::InvalidPacket.new(
|
|
299
285
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
300
286
|
expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
|
|
301
|
-
|
|
302
|
-
received_cmd: response.smb_header.command
|
|
287
|
+
packet: response
|
|
303
288
|
)
|
|
304
289
|
end
|
|
305
290
|
response.status_code
|
|
@@ -316,7 +301,7 @@ module RubySMB
|
|
|
316
301
|
passthrough_info_level = RubySMB::Fscc::FileInformation::FILE_RENAME_INFORMATION +
|
|
317
302
|
RubySMB::Fscc::FileInformation::SMB_INFO_PASSTHROUGH
|
|
318
303
|
rename_request.data_block.trans2_parameters.information_level = passthrough_info_level
|
|
319
|
-
rename_request.data_block.trans2_data.info_level_struct.file_name = new_file_name
|
|
304
|
+
rename_request.data_block.trans2_data.info_level_struct.file_name = new_file_name
|
|
320
305
|
set_trans2_params(rename_request)
|
|
321
306
|
end
|
|
322
307
|
|
|
@@ -8,17 +8,17 @@ module RubySMB
|
|
|
8
8
|
|
|
9
9
|
# An SMB_Parameters Block as defined by the {NegotiateResponse}.
|
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
|
11
|
-
uint16 :dialect_index,
|
|
12
|
-
security_mode :security_mode
|
|
13
|
-
uint16 :max_mpx_count, label: 'Max Multiplex Count'
|
|
14
|
-
uint16 :max_number_vcs, label: 'Max Virtual Circuits'
|
|
15
|
-
uint32 :max_buffer_size, label: 'Max Buffer Size'
|
|
16
|
-
uint32 :max_raw_size, label: 'Max Raw Size'
|
|
17
|
-
uint32 :session_key, label: 'Session Key'
|
|
18
|
-
capabilities :capabilities
|
|
19
|
-
file_time :system_time, label: 'Server System Time'
|
|
20
|
-
int16 :server_time_zone, label: 'Server TimeZone'
|
|
21
|
-
uint8 :challenge_length, label: 'Challenge Length', initial_value: 0x08
|
|
11
|
+
uint16 :dialect_index, label: 'Dialect Index'
|
|
12
|
+
security_mode :security_mode, onlyif: -> { dialect_index != 0xffff }
|
|
13
|
+
uint16 :max_mpx_count, label: 'Max Multiplex Count', onlyif: -> { dialect_index != 0xffff }
|
|
14
|
+
uint16 :max_number_vcs, label: 'Max Virtual Circuits', onlyif: -> { dialect_index != 0xffff }
|
|
15
|
+
uint32 :max_buffer_size, label: 'Max Buffer Size', onlyif: -> { dialect_index != 0xffff }
|
|
16
|
+
uint32 :max_raw_size, label: 'Max Raw Size', onlyif: -> { dialect_index != 0xffff }
|
|
17
|
+
uint32 :session_key, label: 'Session Key', onlyif: -> { dialect_index != 0xffff }
|
|
18
|
+
capabilities :capabilities, onlyif: -> { dialect_index != 0xffff }
|
|
19
|
+
file_time :system_time, label: 'Server System Time', onlyif: -> { dialect_index != 0xffff }
|
|
20
|
+
int16 :server_time_zone, label: 'Server TimeZone', onlyif: -> { dialect_index != 0xffff }
|
|
21
|
+
uint8 :challenge_length, label: 'Challenge Length', initial_value: 0x08, onlyif: -> { dialect_index != 0xffff }
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# An SMB_Data Block as defined by the {NegotiateResponse}
|
|
@@ -8,7 +8,7 @@ module RubySMB
|
|
|
8
8
|
|
|
9
9
|
# An SMB_Parameters Block as defined by the {NegotiateResponseExtended}.
|
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
|
11
|
-
uint16 :dialect_index,
|
|
11
|
+
uint16 :dialect_index, label: 'Dialect Index'
|
|
12
12
|
security_mode :security_mode
|
|
13
13
|
uint16 :max_mpx_count, label: 'Max Multiplex Count'
|
|
14
14
|
uint16 :max_number_vcs, label: 'Max Virtual Circuits'
|
|
@@ -47,7 +47,7 @@ module RubySMB
|
|
|
47
47
|
|
|
48
48
|
# Takes an NTLM Type 3 Message and creates the GSS Security Blob
|
|
49
49
|
# for it and sets it in the {RubySMB::SMB1::Packet::SessionSetupRequest::DataBlock#security_blob}
|
|
50
|
-
# field. It also
|
|
50
|
+
# field. It also automatically sets the length in
|
|
51
51
|
# {RubySMB::SMB1::Packet::SessionSetupRequest::ParameterBlock#security_blob_length}
|
|
52
52
|
#
|
|
53
53
|
# @param type3_message [String] the serialized Type 3 NTLM message
|
|
@@ -40,7 +40,6 @@ module RubySMB
|
|
|
40
40
|
|
|
41
41
|
# The {RubySMB::SMB1::DataBlock} specific to this packet type.
|
|
42
42
|
class DataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
|
|
43
|
-
uint8 :name, label: 'Name', initial_value: 0x00
|
|
44
43
|
string :pad1, length: -> { pad1_length }
|
|
45
44
|
trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
|
|
46
45
|
string :pad2, length: -> { pad2_length }
|