ruby_smb 0.0.8
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.simplecov +42 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/CONTRIBUTING.md +119 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +18 -0
- data/README.md +64 -0
- data/Rakefile +22 -0
- data/examples/authenticate.rb +30 -0
- data/examples/negotiate.rb +25 -0
- data/lib/ruby_smb/client/authentication.rb +236 -0
- data/lib/ruby_smb/client/negotiation.rb +126 -0
- data/lib/ruby_smb/client/signing.rb +48 -0
- data/lib/ruby_smb/client.rb +164 -0
- data/lib/ruby_smb/dispatcher/base.rb +18 -0
- data/lib/ruby_smb/dispatcher/socket.rb +53 -0
- data/lib/ruby_smb/dispatcher.rb +4 -0
- data/lib/ruby_smb/error.rb +17 -0
- data/lib/ruby_smb/field/file_time.rb +62 -0
- data/lib/ruby_smb/field/nt_status.rb +16 -0
- data/lib/ruby_smb/field/stringz16.rb +55 -0
- data/lib/ruby_smb/field.rb +7 -0
- data/lib/ruby_smb/generic_packet.rb +179 -0
- data/lib/ruby_smb/gss.rb +109 -0
- data/lib/ruby_smb/smb1/andx_block.rb +13 -0
- data/lib/ruby_smb/smb1/bit_field/capabilities.rb +39 -0
- data/lib/ruby_smb/smb1/bit_field/header_flags.rb +19 -0
- data/lib/ruby_smb/smb1/bit_field/header_flags2.rb +27 -0
- data/lib/ruby_smb/smb1/bit_field/security_mode.rb +16 -0
- data/lib/ruby_smb/smb1/bit_field.rb +10 -0
- data/lib/ruby_smb/smb1/commands.rb +9 -0
- data/lib/ruby_smb/smb1/data_block.rb +42 -0
- data/lib/ruby_smb/smb1/dialect.rb +11 -0
- data/lib/ruby_smb/smb1/packet/error_packet.rb +14 -0
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +52 -0
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +46 -0
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +47 -0
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +71 -0
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +48 -0
- data/lib/ruby_smb/smb1/packet.rb +12 -0
- data/lib/ruby_smb/smb1/parameter_block.rb +42 -0
- data/lib/ruby_smb/smb1/smb_header.rb +21 -0
- data/lib/ruby_smb/smb1.rb +16 -0
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +17 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_capabailities.rb +23 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_header_flags.rb +23 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_security_mode.rb +15 -0
- data/lib/ruby_smb/smb2/bit_field/smb2_security_mode_single.rb +14 -0
- data/lib/ruby_smb/smb2/bit_field.rb +11 -0
- data/lib/ruby_smb/smb2/commands.rb +25 -0
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +50 -0
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +33 -0
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +53 -0
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +38 -0
- data/lib/ruby_smb/smb2/packet.rb +10 -0
- data/lib/ruby_smb/smb2/smb2_header.rb +22 -0
- data/lib/ruby_smb/smb2.rb +12 -0
- data/lib/ruby_smb/version.rb +3 -0
- data/lib/ruby_smb.rb +22 -0
- data/ruby_smb.gemspec +38 -0
- data/spec/lib/ruby_smb/client_spec.rb +638 -0
- data/spec/lib/ruby_smb/dispatcher/dispatcher_base_spec.rb +22 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +60 -0
- data/spec/lib/ruby_smb/field/file_time_spec.rb +59 -0
- data/spec/lib/ruby_smb/field/nt_status_spec.rb +19 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +50 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +58 -0
- data/spec/lib/ruby_smb/smb1/andx_block_spec.rb +41 -0
- data/spec/lib/ruby_smb/smb1/bit_field/capabilities_spec.rb +245 -0
- data/spec/lib/ruby_smb/smb1/bit_field/header_flags2_spec.rb +146 -0
- data/spec/lib/ruby_smb/smb1/bit_field/header_flags_spec.rb +102 -0
- data/spec/lib/ruby_smb/smb1/bit_field/security_mode_spec.rb +44 -0
- data/spec/lib/ruby_smb/smb1/data_block_spec.rb +26 -0
- data/spec/lib/ruby_smb/smb1/dialect_spec.rb +26 -0
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +39 -0
- data/spec/lib/ruby_smb/smb1/packet/negotiate_request_spec.rb +77 -0
- data/spec/lib/ruby_smb/smb1/packet/negotiate_response_extended_spec.rb +149 -0
- data/spec/lib/ruby_smb/smb1/packet/negotiate_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +100 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +72 -0
- data/spec/lib/ruby_smb/smb1/parameter_block_spec.rb +26 -0
- data/spec/lib/ruby_smb/smb1/smb_header_spec.rb +96 -0
- data/spec/lib/ruby_smb/smb2/bit_field/header_flags_spec.rb +81 -0
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +28 -0
- data/spec/lib/ruby_smb/smb2/bit_field/smb2_capabilities_spec.rb +72 -0
- data/spec/lib/ruby_smb/smb2/bit_field/smb_secruity_mode_spec.rb +22 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +122 -0
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +147 -0
- data/spec/lib/ruby_smb/smb2/packet/session_setup_request_spec.rb +79 -0
- data/spec/lib/ruby_smb/smb2/packet/session_setup_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +127 -0
- data/spec/lib/ruby_smb_spec.rb +2 -0
- data/spec/spec_helper.rb +100 -0
- data/spec/support/mock_socket_dispatcher.rb +8 -0
- data/spec/support/shared/examples/bit_field_single_flag.rb +14 -0
- data.tar.gz.sig +0 -0
- metadata +384 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
|
|
5
|
+
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Request Packet as defined in
|
|
6
|
+
# [2.2.4.6.1](https://msdn.microsoft.com/en-us/library/cc246328.aspx)
|
|
7
|
+
class SessionSetupRequest < RubySMB::GenericPacket
|
|
8
|
+
|
|
9
|
+
# A SMB1 Parameter Block as defined by the {SessionSetupRequest}
|
|
10
|
+
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
|
11
|
+
and_x_block :andx_block
|
|
12
|
+
uint16 :max_buffer_size, label: 'Max Buffer Size'
|
|
13
|
+
uint16 :max_mpx_count, label: 'Max Mpx Count'
|
|
14
|
+
uint16 :vc_number, label: 'VC Number'
|
|
15
|
+
uint32 :session_key, label: 'Session Key'
|
|
16
|
+
uint16 :security_blob_length, label: 'Security Blob Length'
|
|
17
|
+
uint32 :reserved
|
|
18
|
+
capabilities :capabilities
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Represents the specific layout of the DataBlock for a {SessionSetupRequest} Packet.
|
|
22
|
+
# Due to vagaries of character encoding and the way we currently handle NTLM authentication
|
|
23
|
+
# for the security blob, you must null-terminate the {native_os} and {native_lan_man} fields
|
|
24
|
+
# yourself if you set them away from their defaults.
|
|
25
|
+
class DataBlock < RubySMB::SMB1::DataBlock
|
|
26
|
+
string :security_blob, label: 'Security Blob (GSS-API)', length: lambda { self.parent.parameter_block.security_blob_length }
|
|
27
|
+
stringz :native_os, label: 'Native OS', initial_value: 'Windows 7 Ultimate N 7601 Service Pack 1'
|
|
28
|
+
stringz :native_lan_man, label: 'Native LAN Manager', initial_value: 'Windows 7 Ultimate N 6.1'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
smb_header :smb_header
|
|
32
|
+
parameter_block :parameter_block
|
|
33
|
+
data_block :data_block
|
|
34
|
+
|
|
35
|
+
def initialize_instance
|
|
36
|
+
super
|
|
37
|
+
smb_header.command = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Takes an NTLM Type 1 Message and creates the GSS Security Blob
|
|
41
|
+
# for it and sets it in the {RubySMB::SMB1::Packet::SessionSetupRequest::DataBlock#security_blob}
|
|
42
|
+
# field. It also automaticaly sets the length in
|
|
43
|
+
# {RubySMB::SMB1::Packet::SessionSetupRequest::ParameterBlock#security_blob_length}
|
|
44
|
+
#
|
|
45
|
+
# @param type1_message [String] the serialized Type 1 NTLM message
|
|
46
|
+
# @return [void]
|
|
47
|
+
def set_type1_blob(type1_message)
|
|
48
|
+
gss_blob = RubySMB::Gss.gss_type1(type1_message)
|
|
49
|
+
parameter_block.security_blob_length = gss_blob.length
|
|
50
|
+
data_block.security_blob = gss_blob
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Takes an NTLM Type 3 Message and creates the GSS Security Blob
|
|
55
|
+
# for it and sets it in the {RubySMB::SMB1::Packet::SessionSetupRequest::DataBlock#security_blob}
|
|
56
|
+
# field. It also automaticaly sets the length in
|
|
57
|
+
# {RubySMB::SMB1::Packet::SessionSetupRequest::ParameterBlock#security_blob_length}
|
|
58
|
+
#
|
|
59
|
+
# @param type3_message [String] the serialized Type 3 NTLM message
|
|
60
|
+
# @return [void]
|
|
61
|
+
def set_type3_blob(type3_message)
|
|
62
|
+
gss_blob = RubySMB::Gss.gss_type3(type3_message)
|
|
63
|
+
parameter_block.security_blob_length = gss_blob.length
|
|
64
|
+
data_block.security_blob = gss_blob
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
|
|
5
|
+
# A SMB1 SMB_COM_SESSION_SETUP Response Packet as defined in
|
|
6
|
+
# [2.2.4.6.2](https://msdn.microsoft.com/en-us/library/cc246329.aspx)
|
|
7
|
+
class SessionSetupResponse < RubySMB::GenericPacket
|
|
8
|
+
|
|
9
|
+
# A SMB1 Parameter Block as defined by the {SessionSetupResponse}
|
|
10
|
+
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
|
11
|
+
and_x_block :andx_block
|
|
12
|
+
uint16 :action, label: 'Action'
|
|
13
|
+
uint16 :security_blob_length, label: 'Security Blob Length'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Represents the specific layout of the DataBlock for a {SessionSetupResponse} Packet.
|
|
17
|
+
class DataBlock < RubySMB::SMB1::DataBlock
|
|
18
|
+
string :security_blob, label: 'Security Blob (GSS-API)', length: lambda { self.parent.parameter_block.security_blob_length }
|
|
19
|
+
stringz :native_os, label: 'Native OS'
|
|
20
|
+
stringz :native_lan_man, label: 'Native LAN Manager'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
smb_header :smb_header
|
|
24
|
+
parameter_block :parameter_block
|
|
25
|
+
data_block :data_block
|
|
26
|
+
|
|
27
|
+
def initialize_instance
|
|
28
|
+
super
|
|
29
|
+
smb_header.command = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
|
|
30
|
+
smb_header.flags.reply = 1
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Takes an NTLM Type 2 Message and creates the GSS Security Blob
|
|
34
|
+
# for it and sets it in the {RubySMB::SMB1::Packet::SessionSetupRequest::DataBlock#security_blob}
|
|
35
|
+
# field. It also automaticaly sets the length in
|
|
36
|
+
# {RubySMB::SMB1::Packet::SessionSetupRequest::ParameterBlock#security_blob_length}
|
|
37
|
+
#
|
|
38
|
+
# @param type2_message [String] the serialized Type 2 NTLM message
|
|
39
|
+
# @return [void]
|
|
40
|
+
def set_type2_blob(type2_message)
|
|
41
|
+
gss_blob = RubySMB::Gss.gss_type2(type2_message)
|
|
42
|
+
data_block.security_blob = gss_blob
|
|
43
|
+
parameter_block.security_blob_length = gss_blob.length
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
require 'ruby_smb/smb1/packet/error_packet'
|
|
5
|
+
require 'ruby_smb/smb1/packet/negotiate_request'
|
|
6
|
+
require 'ruby_smb/smb1/packet/negotiate_response'
|
|
7
|
+
require 'ruby_smb/smb1/packet/negotiate_response_extended'
|
|
8
|
+
require 'ruby_smb/smb1/packet/session_setup_request'
|
|
9
|
+
require 'ruby_smb/smb1/packet/session_setup_response'
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
# Represents the ParameterBlock portion of an SMB1 Packet. The ParameterBlock will
|
|
4
|
+
# always contain a word_count field that gives the size of the rest of
|
|
5
|
+
# the data block in words.
|
|
6
|
+
class ParameterBlock < BinData::Record
|
|
7
|
+
endian :little
|
|
8
|
+
|
|
9
|
+
uint8 :word_count, label: 'Word Count', value: -> { calculate_word_count }
|
|
10
|
+
|
|
11
|
+
# Class method to stub word count calculation during
|
|
12
|
+
# lazy evaluation.
|
|
13
|
+
#
|
|
14
|
+
# @param [Fixnum] will always return 0
|
|
15
|
+
def self.calculate_word_count
|
|
16
|
+
0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Returns the name of all fields, other than word_count, in
|
|
20
|
+
# the ParameterBlock as symbols.
|
|
21
|
+
#
|
|
22
|
+
# @return [Array<Symbol>] the names of all other ParameterBlock fields
|
|
23
|
+
def self.parameter_fields
|
|
24
|
+
fields = self.fields.collect(&:name)
|
|
25
|
+
fields.reject { |field| field == :word_count }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Calculates the size of the other fields in the ParameterBlock
|
|
29
|
+
# in Words.
|
|
30
|
+
#
|
|
31
|
+
# @return [Fixnum] The size of the ParameterBlock in Words
|
|
32
|
+
def calculate_word_count
|
|
33
|
+
total_count = 0
|
|
34
|
+
self.class.parameter_fields.each do |field_name|
|
|
35
|
+
field_value = send(field_name)
|
|
36
|
+
total_count += field_value.do_num_bytes
|
|
37
|
+
end
|
|
38
|
+
total_count.to_i / 2
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
# Represents the Header of an SMB1 packet as defined in
|
|
4
|
+
# [2.2.3.1 SMB Header Extensions](https://msdn.microsoft.com/en-us/library/cc246254.aspx)
|
|
5
|
+
class SMBHeader < BinData::Record
|
|
6
|
+
endian :little
|
|
7
|
+
bit32 :protocol, label: 'Protocol ID Field', initial_value: RubySMB::SMB1::SMB_PROTOCOL_ID
|
|
8
|
+
bit8 :command, label: 'SMB Command ID'
|
|
9
|
+
nt_status :nt_status, label: 'NTStatus Code'
|
|
10
|
+
header_flags :flags
|
|
11
|
+
header_flags2 :flags2
|
|
12
|
+
bit16 :pid_high, label: 'PID High Bytes'
|
|
13
|
+
string :security_features, label: 'Security Features', length: 8
|
|
14
|
+
bit16 :reserved, label: 'Reserved'
|
|
15
|
+
bit16 :tid, label: 'Tree ID'
|
|
16
|
+
bit16 :pid_low, label: 'PID Low Bytes'
|
|
17
|
+
bit16 :uid, label: 'User ID'
|
|
18
|
+
bit16 :mid, label: 'Multiplex ID'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This module adds the namespace for version 1 of the SMB Protocol
|
|
2
|
+
# as defined in [MS-SMB](https://msdn.microsoft.com/en-us/library/cc246231.aspx)
|
|
3
|
+
module RubySMB::SMB1
|
|
4
|
+
# Protocol ID value. Translates to \xFFSMB
|
|
5
|
+
SMB_PROTOCOL_ID = 0xFF534D42
|
|
6
|
+
|
|
7
|
+
require 'ruby_smb/smb1/commands'
|
|
8
|
+
require 'ruby_smb/smb1/andx_block'
|
|
9
|
+
require 'ruby_smb/smb1/bit_field'
|
|
10
|
+
require 'ruby_smb/smb1/smb_header'
|
|
11
|
+
require 'ruby_smb/smb1/parameter_block'
|
|
12
|
+
require 'ruby_smb/smb1/data_block'
|
|
13
|
+
require 'ruby_smb/smb1/dialect'
|
|
14
|
+
require 'ruby_smb/smb1/packet'
|
|
15
|
+
|
|
16
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module BitField
|
|
4
|
+
# The SessionsFlags bit-field for a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
|
5
|
+
class SessionFlags < BinData::Record
|
|
6
|
+
endian :little
|
|
7
|
+
bit6 :reserved3, label: 'Reserved', value: 0
|
|
8
|
+
bit1 :null, label: 'ASYNC Command', initial_value: 0
|
|
9
|
+
bit1 :guest, label: 'Is Guest?', initial_value: 0
|
|
10
|
+
resume_byte_alignment
|
|
11
|
+
# byte border
|
|
12
|
+
uint8 :reserved1, label: 'Reserved', value: 0
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module BitField
|
|
4
|
+
# Represents a Capabilities BitField as defined by
|
|
5
|
+
# [2.2.3 SMB2 NEGOTIATE Request](https://msdn.microsoft.com/en-us/library/cc246543.aspx)
|
|
6
|
+
class Smb2Capabilities < BinData::Record
|
|
7
|
+
endian :little
|
|
8
|
+
bit1 :reserved1, label: 'Reserved'
|
|
9
|
+
bit1 :encryption, label: 'Encryption'
|
|
10
|
+
bit1 :directory_leasing, label: 'Directory Leasing'
|
|
11
|
+
bit1 :persistent_handles, label: 'Persistent Handles'
|
|
12
|
+
bit1 :multi_channel, label: 'Multi Channel'
|
|
13
|
+
bit1 :large_mtu, label: 'Large MTU'
|
|
14
|
+
bit1 :leasing, label: 'Leasing'
|
|
15
|
+
bit1 :dfs, label: 'DFS'
|
|
16
|
+
# byte border
|
|
17
|
+
uint8 :reserved2, label: 'Reserved'
|
|
18
|
+
uint8 :reserved3, label: 'Reserved'
|
|
19
|
+
uint8 :reserved4, label: 'Reserved'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module BitField
|
|
4
|
+
# The Flags bit-field for an SMB2 Header as defined in
|
|
5
|
+
# [2.2.1.2 SMB2 Packet Header - SYNC](https://msdn.microsoft.com/en-us/library/cc246529.aspx)
|
|
6
|
+
class Smb2HeaderFlags < BinData::Record
|
|
7
|
+
endian :little
|
|
8
|
+
bit4 :reserved3, label: 'Reserved', value: 0
|
|
9
|
+
bit1 :signed, label: 'Packet Signed'
|
|
10
|
+
bit1 :related_operations, label: 'Chained Request'
|
|
11
|
+
bit1 :async_command, label: 'ASYNC Command', value: 0
|
|
12
|
+
bit1 :reply, label: 'Response'
|
|
13
|
+
# byte border
|
|
14
|
+
uint16 :reserved2, label: 'Reserved', value: 0
|
|
15
|
+
# byte border
|
|
16
|
+
bit2 :reserved1, label: 'Reserved', value: 0
|
|
17
|
+
bit1 :replay_operation, label: 'Replay Operation'
|
|
18
|
+
bit1 :dfs_operation, label: 'DFS Operation'
|
|
19
|
+
resume_byte_alignment
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module BitField
|
|
4
|
+
# Represents a Security Mode BitField as defined by
|
|
5
|
+
# [2.2.3 SMB2 NEGOTIATE Request](https://msdn.microsoft.com/en-us/library/cc246543.aspx)
|
|
6
|
+
class Smb2SecurityMode < BinData::Record
|
|
7
|
+
endian :little
|
|
8
|
+
bit6 :reserved, label: 'Reserved'
|
|
9
|
+
bit1 :signing_required, label: 'Signing Required'
|
|
10
|
+
bit1 :signing_enabled, label: 'Signing Enabled'
|
|
11
|
+
uint8 :reserved2, label: 'Reserved'
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module BitField
|
|
4
|
+
# Represents a Security Mode BitField as defined by
|
|
5
|
+
# [2.2.3 SMB2 NEGOTIATE Request](https://msdn.microsoft.com/en-us/library/cc246543.aspx)
|
|
6
|
+
class Smb2SecurityModeSingle < BinData::Record
|
|
7
|
+
endian :little
|
|
8
|
+
bit6 :reserved, label: 'Reserved'
|
|
9
|
+
bit1 :signing_required, label: 'Signing Required'
|
|
10
|
+
bit1 :signing_enabled, label: 'Signing Enabled'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module BitField
|
|
4
|
+
require 'ruby_smb/smb2/bit_field/smb2_header_flags'
|
|
5
|
+
require 'ruby_smb/smb2/bit_field/smb2_security_mode'
|
|
6
|
+
require 'ruby_smb/smb2/bit_field/smb2_security_mode_single'
|
|
7
|
+
require 'ruby_smb/smb2/bit_field/smb2_capabailities'
|
|
8
|
+
require 'ruby_smb/smb2/bit_field/session_flags'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
# [[MS-SMB2] 2.2 Message Syntax](https://msdn.microsoft.com/en-us/library/cc246497.aspx)
|
|
4
|
+
module Commands
|
|
5
|
+
NEGOTIATE = 0x00
|
|
6
|
+
SESSION_SETUP = 0x01
|
|
7
|
+
LOGOFF = 0x02
|
|
8
|
+
TREE_CONNECT = 0x03
|
|
9
|
+
TREE_DISCONNECT = 0x04
|
|
10
|
+
CREATE = 0x05
|
|
11
|
+
CLOSE = 0x06
|
|
12
|
+
FLUSH = 0x07
|
|
13
|
+
READ = 0x08
|
|
14
|
+
WRITE = 0x09
|
|
15
|
+
LOCK = 0x0a
|
|
16
|
+
IOCTL = 0x0b
|
|
17
|
+
CANCEL = 0x0c
|
|
18
|
+
QUERY_DIRECTORY = 0x0e
|
|
19
|
+
ECHO = 0x0d
|
|
20
|
+
CHANGE_NOTIFY = 0x0f
|
|
21
|
+
QUERY_INFO = 0x10
|
|
22
|
+
SET_INFO = 0x11
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module Packet
|
|
4
|
+
# An SMB2 NEGOTIATE Request packet as defined by
|
|
5
|
+
# [2.2.3 SMB2 NEGOTIATE Request](https://msdn.microsoft.com/en-us/library/cc246543.aspx)
|
|
6
|
+
class NegotiateRequest < RubySMB::GenericPacket
|
|
7
|
+
endian :little
|
|
8
|
+
smb2_header :smb2_header
|
|
9
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 36
|
|
10
|
+
uint16 :dialect_count, label: 'Dialect Count'
|
|
11
|
+
smb2_security_mode :security_mode
|
|
12
|
+
uint16 :reserved1, label: 'Reserved', initial_value: 0
|
|
13
|
+
smb2_capabilities :capabilities
|
|
14
|
+
string :client_guid, label: 'Client GUID', length: 16
|
|
15
|
+
file_time :client_start_time, label: 'Client Start Time', initial_value: 0
|
|
16
|
+
array :dialects, label: 'Dialects', type: :uint16, read_until: :eof
|
|
17
|
+
|
|
18
|
+
def initialize_instance
|
|
19
|
+
super
|
|
20
|
+
smb2_header.command = RubySMB::SMB2::Commands::NEGOTIATE
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Adds a dialect to the Dialects array and increments the dialect count
|
|
24
|
+
#
|
|
25
|
+
# @param [Fixnum] the numeric code for the dialect you wish to add
|
|
26
|
+
# @return [Array<Fixnum>] the array of all currently selected dialects
|
|
27
|
+
def add_dialect(dialect)
|
|
28
|
+
return ArgumentError, 'Must be a number' unless dialect.is_a? Fixnum
|
|
29
|
+
self.dialect_count += 1
|
|
30
|
+
dialects << dialect
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Takes an array of dialects and sets it on the packet. Also updates
|
|
34
|
+
# the dialect_count field appropriately. Will erase any previously set
|
|
35
|
+
# dialects.
|
|
36
|
+
#
|
|
37
|
+
# @param [Array<Fixnum>] the array of dialects to set
|
|
38
|
+
# @return [Array<Fixnum>] the current value of the dialects array
|
|
39
|
+
def set_dialects(add_dialects = [])
|
|
40
|
+
self.dialects = []
|
|
41
|
+
self.dialect_count = 0
|
|
42
|
+
add_dialects.each do |dialect|
|
|
43
|
+
add_dialect(dialect)
|
|
44
|
+
end
|
|
45
|
+
dialects
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module Packet
|
|
4
|
+
# An SMB2 NEGOTIATE Response packet as defined by
|
|
5
|
+
# [2.2.4 SMB2 NEGOTIATE Response](https://msdn.microsoft.com/en-us/library/cc246561.aspx)
|
|
6
|
+
class NegotiateResponse < RubySMB::GenericPacket
|
|
7
|
+
endian :little
|
|
8
|
+
smb2_header :smb2_header
|
|
9
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 65
|
|
10
|
+
smb2_security_mode :security_mode
|
|
11
|
+
uint16 :dialect_revision, label: 'Dialect Revision'
|
|
12
|
+
uint16 :negotiate_context_count, label: 'Negotiate Context Count', initial_value: 0
|
|
13
|
+
string :server_guid, label: 'Server GUID', length: 16
|
|
14
|
+
smb2_capabilities :capabilities
|
|
15
|
+
uint32 :max_transact_size, label: 'Max Transaction Size'
|
|
16
|
+
uint32 :max_read_size, label: 'Max Read Size'
|
|
17
|
+
uint32 :max_write_size, label: 'Max Write Size'
|
|
18
|
+
file_time :system_time, label: 'Server System Time'
|
|
19
|
+
file_time :server_start_time, label: 'Server Start Time'
|
|
20
|
+
uint16 :security_buffer_offset, label: 'Offset to Security Buffer'
|
|
21
|
+
uint16 :security_buffer_length, label: 'Security Buffer Length', value: -> { security_buffer.length }
|
|
22
|
+
uint32 :negotiate_context_offset, label: 'Offset to Negotiate Context'
|
|
23
|
+
string :security_buffer, label: 'Security Buffer', read_length: :security_buffer_length
|
|
24
|
+
|
|
25
|
+
def initialize_instance
|
|
26
|
+
super
|
|
27
|
+
smb2_header.command = RubySMB::SMB2::Commands::NEGOTIATE
|
|
28
|
+
smb2_header.flags.reply = 1
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module Packet
|
|
4
|
+
|
|
5
|
+
# An SMB2 SessionSetupRequest Packet as defined in
|
|
6
|
+
# [2.2.5 SMB2 SESSION_SETUP Request](https://msdn.microsoft.com/en-us/library/cc246563.aspx)
|
|
7
|
+
class SessionSetupRequest < RubySMB::GenericPacket
|
|
8
|
+
endian :little
|
|
9
|
+
smb2_header :smb2_header
|
|
10
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 25
|
|
11
|
+
uint8 :flags, label: 'Flags', initial_value: 0x00
|
|
12
|
+
smb2_security_mode_single :security_mode
|
|
13
|
+
smb2_capabilities :capabilities
|
|
14
|
+
uint32 :channel, label: 'Channel', initial_value: 0x00
|
|
15
|
+
uint16 :security_buffer_offset, label: 'Security Buffer Offset', initial_value: 0x58
|
|
16
|
+
uint16 :security_buffer_length, label: 'Security Buffer Length'
|
|
17
|
+
uint64 :previous_session_id, label: 'Previous Session ID'
|
|
18
|
+
string :buffer, label: 'Security Buffer', length: lambda { self.security_buffer_length }
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def initialize_instance
|
|
22
|
+
super
|
|
23
|
+
smb2_header.command = RubySMB::SMB2::Commands::SESSION_SETUP
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Takes a serialized NTLM Type 1 message and wraps it in the GSS ASN1 encoding
|
|
27
|
+
# and inserts it into the {RubySMB::SMB2::Packet::SessionSetupRequest#buffer}
|
|
28
|
+
# as well as updating the {RubySMB::SMB2::Packet::SessionSetupRequest#security_buffer_length}
|
|
29
|
+
#
|
|
30
|
+
# @param type1_message [String] the serialized NTLM Type 1 message
|
|
31
|
+
# @return [void]
|
|
32
|
+
def set_type1_blob(type1_message)
|
|
33
|
+
gss_blob = RubySMB::Gss.gss_type1(type1_message)
|
|
34
|
+
self.security_buffer_length = gss_blob.length
|
|
35
|
+
self.buffer = gss_blob
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Takes a serialized NTLM Type 3 message and wraps it in the GSS ASN1 encoding
|
|
39
|
+
# and inserts it into the {RubySMB::SMB2::Packet::SessionSetupRequest#buffer}
|
|
40
|
+
# as well as updating the {RubySMB::SMB2::Packet::SessionSetupRequest#security_buffer_length}
|
|
41
|
+
#
|
|
42
|
+
# @param type3_message [String] the serialized NTLM Type 3 message
|
|
43
|
+
# @return [void]
|
|
44
|
+
def set_type3_blob(type3_message)
|
|
45
|
+
gss_blob = RubySMB::Gss.gss_type3(type3_message)
|
|
46
|
+
self.security_buffer_length = gss_blob.length
|
|
47
|
+
self.buffer = gss_blob
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module Packet
|
|
4
|
+
|
|
5
|
+
# An SMB2 SessionSetupResponse Packet as defined in
|
|
6
|
+
# [2.2.6 SMB2 SESSION_SETUP Response](https://msdn.microsoft.com/en-us/library/cc246564.aspx)
|
|
7
|
+
class SessionSetupResponse < RubySMB::GenericPacket
|
|
8
|
+
endian :little
|
|
9
|
+
smb2_header :smb2_header
|
|
10
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 9
|
|
11
|
+
session_flags :session_flags
|
|
12
|
+
uint16 :security_buffer_offset, label: 'Security Buffer Offset', initial_value: 0x48
|
|
13
|
+
uint16 :security_buffer_length, label: 'Security Buffer Length'
|
|
14
|
+
string :buffer, label: 'Security Buffer', length: lambda { self.security_buffer_length }
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def initialize_instance
|
|
18
|
+
super
|
|
19
|
+
smb2_header.command = RubySMB::SMB2::Commands::SESSION_SETUP
|
|
20
|
+
smb2_header.flags.reply = 1
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Takes a serialized NTLM Type 2 message and wraps it in the GSS ASN1 encoding
|
|
24
|
+
# and inserts it into the {RubySMB::SMB2::Packet::SessionSetupRequest#buffer}
|
|
25
|
+
# as well as updating the {RubySMB::SMB2::Packet::SessionSetupRequest#security_buffer_length}
|
|
26
|
+
#
|
|
27
|
+
# @param type1_message [String] the serialized NTLM Type 1 message
|
|
28
|
+
# @return [void]
|
|
29
|
+
def set_type2_blob(type1_message)
|
|
30
|
+
gss_blob = RubySMB::Gss.gss_type2(type1_message)
|
|
31
|
+
self.security_buffer_length = gss_blob.length
|
|
32
|
+
self.buffer = gss_blob
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
module Packet
|
|
4
|
+
require 'ruby_smb/smb2/packet/negotiate_request'
|
|
5
|
+
require 'ruby_smb/smb2/packet/negotiate_response'
|
|
6
|
+
require 'ruby_smb/smb2/packet/session_setup_request'
|
|
7
|
+
require 'ruby_smb/smb2/packet/session_setup_response'
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB2
|
|
3
|
+
# Represents the Header of an SMB2 packet as defined in
|
|
4
|
+
# [2.2.1.2 SMB2 Packet Header - SYNC](https://msdn.microsoft.com/en-us/library/cc246529.aspx)
|
|
5
|
+
class SMB2Header < BinData::Record
|
|
6
|
+
endian :little
|
|
7
|
+
bit32 :protocol, label: 'Protocol ID Field', initial_value: RubySMB::SMB2::SMB2_PROTOCOL_ID
|
|
8
|
+
uint16 :structure_size, label: 'Header Structure Size', initial_value: 64
|
|
9
|
+
uint16 :credit_charge, label: 'Credit Charge', initial_value: 0
|
|
10
|
+
nt_status :nt_status, label: 'NT Status', initial_value: 0
|
|
11
|
+
uint16 :command, label: 'Command'
|
|
12
|
+
uint16 :credits, label: 'Credit Request/Response'
|
|
13
|
+
smb2_header_flags :flags, label: 'Flags'
|
|
14
|
+
uint32 :next_command, label: 'Command Chain Offset', initial_value: 0
|
|
15
|
+
uint64 :message_id, label: 'Message ID'
|
|
16
|
+
uint32 :process_id, label: 'Process ID', initial_value: 0x0000feff
|
|
17
|
+
uint32 :tree_id, label: 'Tree ID'
|
|
18
|
+
uint64 :session_id, label: 'Session ID'
|
|
19
|
+
string :signature, label: 'Signature', length: 16
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# A packet parsing and manipulation library for the SMB2 protocol
|
|
2
|
+
#
|
|
3
|
+
# [[MS-SMB2] Server Mesage Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
|
4
|
+
module RubySMB::SMB2
|
|
5
|
+
# Protocol ID value. Translates to \xFESMB
|
|
6
|
+
SMB2_PROTOCOL_ID = 0xFE534D42
|
|
7
|
+
|
|
8
|
+
require 'ruby_smb/smb2/commands'
|
|
9
|
+
require 'ruby_smb/smb2/bit_field'
|
|
10
|
+
require 'ruby_smb/smb2/smb2_header'
|
|
11
|
+
require 'ruby_smb/smb2/packet'
|
|
12
|
+
end
|
data/lib/ruby_smb.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'bit-struct'
|
|
2
|
+
require 'bindata'
|
|
3
|
+
require 'net/ntlm'
|
|
4
|
+
require 'net/ntlm/client'
|
|
5
|
+
require 'windows_error'
|
|
6
|
+
require 'windows_error/nt_status'
|
|
7
|
+
# A packet parsing and manipulation library for the SMB1 and SMB2 protocols
|
|
8
|
+
#
|
|
9
|
+
# [[MS-SMB] Server Mesage Block (SMB) Protocol Version 1](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
|
10
|
+
# [[MS-SMB2] Server Mesage Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
|
|
11
|
+
module RubySMB
|
|
12
|
+
require 'ruby_smb/gss'
|
|
13
|
+
require 'ruby_smb/field'
|
|
14
|
+
require 'ruby_smb/generic_packet'
|
|
15
|
+
require 'ruby_smb/dispatcher'
|
|
16
|
+
require 'ruby_smb/error'
|
|
17
|
+
require 'ruby_smb/version'
|
|
18
|
+
require 'ruby_smb/version'
|
|
19
|
+
require 'ruby_smb/smb2'
|
|
20
|
+
require 'ruby_smb/smb1'
|
|
21
|
+
require 'ruby_smb/client'
|
|
22
|
+
end
|
data/ruby_smb.gemspec
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'ruby_smb/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'ruby_smb'
|
|
8
|
+
spec.version = RubySMB::VERSION
|
|
9
|
+
spec.authors = ['David Maloney', 'James Lee']
|
|
10
|
+
spec.email = ['DMaloney@rapid7.com', 'egypt@metasploit.com']
|
|
11
|
+
spec.summary = 'A message creator and parser for the SMB protocol family'
|
|
12
|
+
spec.description = ''
|
|
13
|
+
spec.homepage = 'http://www.metasploit.com'
|
|
14
|
+
spec.license = 'BSD-3-clause'
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
if RUBY_PLATFORM =~ /java/
|
|
22
|
+
spec.add_development_dependency 'kramdown'
|
|
23
|
+
spec.platform = Gem::Platform::JAVA
|
|
24
|
+
else
|
|
25
|
+
spec.add_development_dependency 'redcarpet'
|
|
26
|
+
spec.platform = Gem::Platform::RUBY
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
spec.add_development_dependency 'bundler'
|
|
30
|
+
spec.add_development_dependency 'fivemat'
|
|
31
|
+
spec.add_development_dependency 'rake'
|
|
32
|
+
spec.add_development_dependency 'yard'
|
|
33
|
+
|
|
34
|
+
spec.add_runtime_dependency 'rubyntlm', '~> 0.5'
|
|
35
|
+
spec.add_runtime_dependency 'bit-struct'
|
|
36
|
+
spec.add_runtime_dependency 'windows_error'
|
|
37
|
+
spec.add_runtime_dependency 'bindata'
|
|
38
|
+
end
|