ruby_smb 0.0.21 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/examples/net_share_enum_all.rb +5 -2
  5. data/lib/ruby_smb.rb +1 -1
  6. data/lib/ruby_smb/client.rb +4 -35
  7. data/lib/ruby_smb/dcerpc.rb +7 -22
  8. data/lib/ruby_smb/dcerpc/bind.rb +30 -36
  9. data/lib/ruby_smb/dcerpc/bind_ack.rb +72 -0
  10. data/lib/ruby_smb/dcerpc/error.rb +15 -0
  11. data/lib/ruby_smb/dcerpc/ndr.rb +31 -30
  12. data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +11 -0
  13. data/lib/ruby_smb/dcerpc/pdu_header.rb +29 -0
  14. data/lib/ruby_smb/dcerpc/ptypes.rb +26 -0
  15. data/lib/ruby_smb/dcerpc/request.rb +17 -30
  16. data/lib/ruby_smb/dcerpc/response.rb +15 -34
  17. data/lib/ruby_smb/dcerpc/srvsvc.rb +5 -7
  18. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +8 -4
  19. data/lib/ruby_smb/dcerpc/uuid.rb +31 -13
  20. data/lib/ruby_smb/smb1/bit_field.rb +0 -1
  21. data/lib/ruby_smb/smb1/bit_field/trans_flags.rb +3 -2
  22. data/lib/ruby_smb/smb1/data_block.rb +5 -0
  23. data/lib/ruby_smb/smb1/dcerpc.rb +67 -0
  24. data/lib/ruby_smb/smb1/packet.rb +1 -0
  25. data/lib/ruby_smb/smb1/packet/trans.rb +7 -1
  26. data/lib/ruby_smb/smb1/packet/trans/data_block.rb +19 -7
  27. data/lib/ruby_smb/smb1/packet/trans/request.rb +36 -25
  28. data/lib/ruby_smb/smb1/packet/trans/response.rb +22 -21
  29. data/lib/ruby_smb/smb1/packet/trans/subcommands.rb +1 -0
  30. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +61 -0
  31. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +44 -0
  32. data/lib/ruby_smb/smb1/packet/trans2/request.rb +1 -1
  33. data/lib/ruby_smb/smb1/pipe.rb +3 -0
  34. data/lib/ruby_smb/smb2/dcerpc.rb +68 -0
  35. data/lib/ruby_smb/smb2/pipe.rb +3 -0
  36. data/lib/ruby_smb/version.rb +1 -1
  37. data/spec/lib/ruby_smb/client_spec.rb +53 -6
  38. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +224 -0
  39. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +255 -7
  40. data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +31 -0
  41. data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +84 -0
  42. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +106 -13
  43. data/spec/lib/ruby_smb/dcerpc/response_spec.rb +89 -8
  44. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +176 -0
  45. data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +97 -1
  46. data/spec/lib/ruby_smb/smb1/data_block_spec.rb +43 -3
  47. data/spec/lib/ruby_smb/smb1/packet/trans/data_block_spec.rb +137 -0
  48. data/spec/lib/ruby_smb/smb1/packet/trans/request_spec.rb +239 -13
  49. data/spec/lib/ruby_smb/smb1/packet/trans/response_spec.rb +122 -13
  50. data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request_spec.rb +254 -0
  51. data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response_spec.rb +122 -0
  52. data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
  53. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +199 -1
  54. data/spec/lib/ruby_smb/smb2/file_spec.rb +2 -1
  55. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +196 -1
  56. metadata +25 -10
  57. metadata.gz.sig +0 -0
  58. data/lib/ruby_smb/dcerpc/handle.rb +0 -60
  59. data/lib/ruby_smb/smb1/bit_field/trans2_flags.rb +0 -15
  60. data/spec/lib/ruby_smb/dcerpc/handle_spec.rb +0 -31
  61. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +0 -13
  62. data/spec/lib/ruby_smb/smb1/bit_field/trans2_flags_spec.rb +0 -26
@@ -1,43 +1,30 @@
1
1
  module RubySMB
2
2
  module Dcerpc
3
- #http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm
3
+ # The Request PDU as defined in
4
+ # [The request PDU](http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_09)
4
5
  class Request < BinData::Record
5
6
  endian :little
6
7
 
7
- #common fields
8
- uint8 :rpc_vers, initial_value: 5 # 00:01 RPC version
9
- uint8 :rpc_vers_minor # 01:01 minor version
10
- uint8 :ptype # 02:01 request PDU
11
- struct :pfc_flags do
12
- bit1 :object
13
- bit1 :maybe
14
- bit1 :did_not_execute
15
- bit1 :multiplex
16
- bit1 :reserved
17
- bit1 :cancel
18
- bit1 :last_frag, initial_value: 1
19
- bit1 :first_frag, initial_value: 1
20
- end
21
-
22
- uint32 :packed_drep, initial_value: 0x00000010 # 04:04 NDR data rep format label
23
-
24
- uint16 :frag_length, initial_value: -> { self.do_num_bytes } # 08:02 total length of fragment
25
- uint16 :auth_length # 10:02 length of auth_value
26
- uint32 :call_id # 12:04 call identifier
8
+ pdu_header :pdu_header, label: 'PDU header'
27
9
 
28
- #needed on request, response, fault
10
+ uint32 :alloc_hint, label: 'Allocation hint', initial_value: -> { stub.do_num_bytes }
11
+ uint16 :p_cont_id, label: 'Presentation context identification'
12
+ uint16 :opnum, label: 'Operation Number'
29
13
 
30
- uint32 :alloc_hint, initial_value: -> {stub.do_num_bytes} # 16:04 allocation hint
31
- uint16 :p_cont_id # 20:02 pres context, i.e. data rep
32
- uint16 :opnum # 22:02 operation #within the interface
14
+ uuid :object, label: 'Object UID', onlyif: -> { pdu_header.pfc_flags.object_uuid == 1 }
33
15
 
34
- # optional field for request, only present if the PFC_OBJECT_UUID field is non-zero
16
+ choice :stub, label: 'Stub', selection: -> { opnum } do
17
+ net_share_enum_all RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL, host: -> { host }
18
+ end
35
19
 
36
- string :stub, read_length: -> {alloc_hint} # stub data, 8-octet aligned
37
- string :auth_verifier_co_t # optional authentication verifier
38
- # following fields present iff auth_length != 0 */
20
+ string :auth_verifier, label: 'Authentication verifier',
21
+ onlyif: -> { pdu_header.auth_length > 0 },
22
+ read_length: -> { pdu_header.auth_length }
39
23
 
40
- #auth_verifier_co_t auth_verifier # xx:yy
24
+ def initialize_instance
25
+ super
26
+ pdu_header.ptype = RubySMB::Dcerpc::PTypes::REQUEST
27
+ end
41
28
  end
42
29
  end
43
30
  end
@@ -1,46 +1,27 @@
1
1
  module RubySMB
2
2
  module Dcerpc
3
- #http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm
3
+ # The Response PDU as defined in
4
+ # [The response PDU](http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_10)
4
5
  class Response < BinData::Record
5
6
  endian :little
6
7
 
7
- #common fields
8
- uint8 :rpc_vers # 00:01 RPC version
9
- uint8 :rpc_vers_minor # 01:01 minor version
10
- uint8 :ptype # 02:01 request PDU
11
- struct :pfc_flags do
12
- bit1 :object
13
- bit1 :maybe
14
- bit1 :did_not_execute
15
- bit1 :multiplex
16
- bit1 :reserved
17
- bit1 :cancel
18
- bit1 :last_frag, initial_value: 1
19
- bit1 :first_frag, initial_value: 1
20
- end
21
-
22
- uint32 :packed_drep # 04:04 NDR data rep format label
23
-
24
- uint16 :frag_length # 08:02 total length of fragment
25
- uint16 :auth_length # 10:02 length of auth_value
26
- uint32 :call_id # 12:04 call identifier
27
-
28
- #needed on request, response, fault
8
+ pdu_header :pdu_header, label: 'PDU header'
29
9
 
30
- uint32 :alloc_hint # 16:04 allocation hint
31
- uint16 :p_cont_id # 20:02 pres context, i.e. data rep
32
- uint16 :cancel_count # 22:02 operation #within the interface
10
+ uint32 :alloc_hint, label: 'Allocation hint', initial_value: -> { stub.do_num_bytes }
11
+ uint16 :p_cont_id, label: 'Presentation context identification'
12
+ uint8 :cancel_count, label: 'Cancel count'
13
+ uint8 :reserved
33
14
 
34
- # optional field for request, only present if the PFC_OBJECT_UUID field is non-zero
15
+ string :stub, label: 'Stub', read_length: -> { pdu_header.frag_length - stub.abs_offset - pdu_header.auth_length }
35
16
 
36
- string :stub, length: -> {alloc_hint}
17
+ string :auth_verifier, label: 'Authentication verifier',
18
+ onlyif: -> { pdu_header.auth_length > 0 },
19
+ read_length: -> { pdu_header.auth_length }
37
20
 
38
- # stub data, 8-octet aligned
39
-
40
- # optional authentication verifier
41
- # following fields present iff auth_length != 0 */
42
-
43
- #auth_verifier_co_t auth_verifier # xx:yy
21
+ def initialize_instance
22
+ super
23
+ pdu_header.ptype = RubySMB::Dcerpc::PTypes::RESPONSE
24
+ end
44
25
  end
45
26
  end
46
27
  end
@@ -2,14 +2,12 @@ module RubySMB
2
2
  module Dcerpc
3
3
  module Srvsvc
4
4
 
5
- class SrvSvcHandle < Dcerpc::NdrLpStr; end
5
+ UUID = '4b324fc8-1670-01d3-1278-5a47bf6ee188'
6
+ VER_MAJOR = 3
7
+ VER_MINOR = 0
6
8
 
7
- class SrvSvcSyntax < BinData::Record
8
- endian :little
9
- uuid :if_uuid, initial_value: '4b324fc8-1670-01d3-1278-5a47bf6ee188'
10
- uint16 :if_ver, initial_value: 3
11
- uint16 :if_ver_minor, initial_value: 0
12
- end
9
+ # Operation numbers
10
+ NET_SHARE_ENUM_ALL = 0xF
13
11
 
14
12
  require 'ruby_smb/dcerpc/srvsvc/net_share_enum_all'
15
13
  end
@@ -5,17 +5,16 @@ module RubySMB
5
5
  #https://msdn.microsoft.com/en-us/library/cc247293.aspx
6
6
 
7
7
  class NetShareEnumAll < BinData::Record
8
- Opnum = 0xF
9
-
10
8
  endian :little
11
9
 
12
10
  uint32 :referent_id, initial_value: 0x00000001
13
11
  uint32 :max_count, initial_value: -> { server_unc.do_num_bytes / 2 }
14
12
  uint32 :offset, initial_value: 0
15
13
  uint32 :actual_count, initial_value: -> {max_count}
16
- stringz16 :server_unc, pad_front: false, read_length: -> { actual_count * 2 },
17
- initial_value: -> {host.encode('utf-16le')}
14
+ stringz16 :server_unc, pad_front: false, read_length: -> { actual_count * 2 },
15
+ initial_value: -> {"\\\\#{host.encode('utf-8')}".encode('utf-16le')}
18
16
 
17
+ string :pad, length: lambda { pad_length }
19
18
  uint32 :level, initial_value: 1
20
19
 
21
20
  uint32 :ctr, initial_value: 1
@@ -28,6 +27,11 @@ module RubySMB
28
27
  uint32 :resume_referent_id, initial_value: 0x00000001
29
28
  uint32 :resume_handle, initial_value: 0
30
29
 
30
+ def pad_length
31
+ offset = (server_unc.abs_offset + server_unc.to_binary_s.length) % 4
32
+ (4 - offset) % 4
33
+ end
34
+
31
35
  def self.parse_response(response)
32
36
 
33
37
  shares = []
@@ -1,28 +1,46 @@
1
1
  module RubySMB
2
2
  module Dcerpc
3
3
 
4
- #https://msdn.microsoft.com/en-us/library/windows/desktop/aa379358(v=vs.85).aspx
4
+ # [Universal Unique Identifier](http://pubs.opengroup.org/onlinepubs/9629399/apdxa.htm)
5
5
  class Uuid < BinData::Primitive
6
- uint32le :time_low
7
- uint16le :time_mid
8
- uint16le :time_hi_and_version
6
+ endian :little
7
+ uint32 :time_low, label: 'Low field of the timestamp'
8
+ uint16 :time_mid, label: 'Middle field of the timestamp'
9
+ uint16 :time_hi_and_version, label: 'High field of the timestamp multiplexed with the version number'
9
10
 
10
- uint16be :clock_seq_hi_and_res
11
- uint48be :node
11
+ uint8 :clock_seq_hi_and_reserved, label: 'High field of the clock sequence multiplexed with the variant'
12
+ uint8 :clock_seq_low, label: 'Low field of the clock sequence'
13
+ array :node, label: 'Spatially unique node identifier', :type => :uint8, initial_length: 6
12
14
 
13
15
  def get
14
- self.to_binary_s
16
+ "#{to_string_le(time_low.to_binary_s)}"\
17
+ "-#{to_string_le(time_mid.to_binary_s)}"\
18
+ "-#{to_string_le(time_hi_and_version.to_binary_s)}"\
19
+ "-#{clock_seq_hi_and_reserved.to_hex}#{clock_seq_low.to_hex}"\
20
+ "-#{node.to_hex}"
15
21
  end
16
22
 
17
23
  def set(uuid_string)
18
24
  components = uuid_string.split('-')
19
- self.time_low = components[0].hex
20
- self.time_mid = components[1].hex
21
- self.time_hi_and_version = components[2].hex
22
- self.clock_seq_hi_and_res = components[3].hex
23
- self.node = components[4].hex
25
+ self.time_low.read(to_binary_le(components[0]))
26
+ self.time_mid.read(to_binary_le(components[1]))
27
+ self.time_hi_and_version.read(to_binary_le(components[2]))
28
+ self.clock_seq_hi_and_reserved.read(components[3][0,2].hex.chr)
29
+ self.clock_seq_low.read(components[3][2,2].hex.chr)
30
+ self.node.read(components[4].gsub(/../) {|e| e.hex.chr})
31
+ end
32
+
33
+
34
+ private
35
+
36
+ def to_binary_le(str)
37
+ str.scan(/../).map {|char| char.hex.chr}.reverse.join
38
+ end
39
+
40
+ def to_string_le(bin)
41
+ bin.each_byte.map {|byte| byte.to_s(16).rjust(2, '0')}.reverse.join
24
42
  end
25
43
  end
26
44
 
27
45
  end
28
- end
46
+ end
@@ -11,7 +11,6 @@ module RubySMB
11
11
  require 'ruby_smb/smb1/bit_field/directory_access_mask'
12
12
  require 'ruby_smb/smb1/bit_field/file_access_mask'
13
13
  require 'ruby_smb/smb1/bit_field/trans_flags'
14
- require 'ruby_smb/smb1/bit_field/trans2_flags'
15
14
  require 'ruby_smb/smb1/bit_field/open2_flags'
16
15
  require 'ruby_smb/smb1/bit_field/open2_access_mode'
17
16
  require 'ruby_smb/smb1/bit_field/open2_open_mode'
@@ -1,8 +1,9 @@
1
1
  module RubySMB
2
2
  module SMB1
3
3
  module BitField
4
- # The Flags bit-field for a Trans Request Packet
5
- # [2.2.4.33.1 Request](https://msdn.microsoft.com/en-us/library/ee441730.aspx)
4
+ # The Flags bit-field for Trans and Trans2 Request Packets as defined in
5
+ # [2.2.4.33.1 Request](https://msdn.microsoft.com/en-us/library/ee441730.aspx) and
6
+ # [2.2.4.46.1 Request](https://msdn.microsoft.com/en-us/library/ee442192.aspx)
6
7
  class TransFlags < BinData::Record
7
8
  endian :little
8
9
  bit6 :reserved, label: 'Reserved Space', initial_value: 0
@@ -32,11 +32,16 @@ module RubySMB
32
32
  def calculate_byte_count
33
33
  total_count = 0
34
34
  self.class.data_fields.each do |field_name|
35
+ next unless field_enabled?(field_name)
35
36
  field_value = send(field_name)
36
37
  total_count += field_value.do_num_bytes
37
38
  end
38
39
  total_count
39
40
  end
41
+
42
+ def field_enabled?(field_name)
43
+ send("#{field_name}?".to_sym)
44
+ end
40
45
  end
41
46
  end
42
47
  end
@@ -0,0 +1,67 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Dcerpc
4
+
5
+ def net_share_enum_all(host)
6
+ bind(endpoint: RubySMB::Dcerpc::Srvsvc)
7
+
8
+ response = request(RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL, host: host)
9
+
10
+ shares = RubySMB::Dcerpc::Srvsvc::NetShareEnumAll.parse_response(response.stub.to_binary_s)
11
+ shares.map{|s|{name: s[0], type: s[1], comment: s[2]}}
12
+ end
13
+
14
+ def bind(options={})
15
+ bind_req = RubySMB::Dcerpc::Bind.new(options)
16
+ write(data: bind_req.to_binary_s)
17
+ @size = 1024
18
+ dcerpc_raw_response = read()
19
+ begin
20
+ dcerpc_response = RubySMB::Dcerpc::BindAck.read(dcerpc_raw_response)
21
+ rescue IOError
22
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
23
+ end
24
+ unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::BIND_ACK
25
+ raise RubySMB::Dcerpc::Error::BindError, "Not a BindAck packet"
26
+ end
27
+
28
+ res_list = dcerpc_response.p_result_list
29
+ if res_list.n_results == 0 ||
30
+ res_list.p_results[0].result != RubySMB::Dcerpc::BindAck::ACCEPTANCE
31
+ raise RubySMB::Dcerpc::Error::BindError,
32
+ "Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
33
+ end
34
+ dcerpc_response
35
+ end
36
+
37
+ def request(opnum, options={})
38
+ dcerpc_request = RubySMB::Dcerpc::Request.new({ :opnum => opnum }, options)
39
+ request = RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options)
40
+ @tree.set_header_fields(request)
41
+ request.set_fid(@fid)
42
+ request.data_block.trans_data.write_data = dcerpc_request.to_binary_s
43
+
44
+ trans_nmpipe_raw_response = @tree.client.send_recv(request)
45
+ trans_nmpipe_response = RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.read(trans_nmpipe_raw_response)
46
+ unless trans_nmpipe_response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
47
+ raise RubySMB::Error::InvalidPacket, 'Not a Trans packet'
48
+ end
49
+ unless trans_nmpipe_response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
50
+ raise RubySMB::Error::UnexpectedStatusCode, trans_nmpipe_response.status_code.name
51
+ end
52
+
53
+ begin
54
+ dcerpc_response = RubySMB::Dcerpc::Response.read(trans_nmpipe_response.data_block.trans_data.read_data)
55
+ rescue IOError
56
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
57
+ end
58
+ unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::RESPONSE
59
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Not a Response packet"
60
+ end
61
+ dcerpc_response
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+
@@ -30,6 +30,7 @@ module RubySMB
30
30
  require 'ruby_smb/smb1/packet/write_andx_response'
31
31
  require 'ruby_smb/smb1/packet/close_request'
32
32
  require 'ruby_smb/smb1/packet/close_response'
33
+ require 'ruby_smb/smb1/packet/trans'
33
34
  end
34
35
  end
35
36
  end
@@ -4,10 +4,16 @@ module RubySMB
4
4
  # Namespace for the Transaction sub-protocol documented in
5
5
  # [2.2.4.33 SMB_COM_TRANSACTION (0x25)](https://msdn.microsoft.com/en-us/library/ee441489.aspx)
6
6
  module Trans
7
- require 'ruby_smb/smb1/packet/trans/subcommands'
7
+ MAX_PARAMETER_COUNT = 1024
8
+ MAX_DATA_COUNT = 1024
9
+ MAX_SETUP_COUNT = 255
10
+
8
11
  require 'ruby_smb/smb1/packet/trans/data_block'
12
+ require 'ruby_smb/smb1/packet/trans/subcommands'
9
13
  require 'ruby_smb/smb1/packet/trans/request'
10
14
  require 'ruby_smb/smb1/packet/trans/response'
15
+ require 'ruby_smb/smb1/packet/trans/transact_nmpipe_request'
16
+ require 'ruby_smb/smb1/packet/trans/transact_nmpipe_response'
11
17
  require 'ruby_smb/smb1/packet/trans/peek_nmpipe_request'
12
18
  require 'ruby_smb/smb1/packet/trans/peek_nmpipe_response'
13
19
  end
@@ -2,6 +2,7 @@ module RubySMB
2
2
  module SMB1
3
3
  module Packet
4
4
  module Trans
5
+
5
6
  # Extends the {RubySMB::SMB1::DataBlock} to include padding methods
6
7
  # that all Trans DataBlocks will need to handle proper byte alignment.
7
8
  class DataBlock < RubySMB::SMB1::DataBlock
@@ -18,14 +19,14 @@ module RubySMB
18
19
  private
19
20
 
20
21
  # Determines the correct length for the padding in front of
21
- # trans_parameters. It should always force a 4-byte alignment.
22
+ # #trans_parameters. It should always force a 4-byte alignment.
22
23
  def pad1_length
23
24
  if enable_padding
24
- offset = if respond_to?(:name)
25
- (name.abs_offset + 1) % 4
26
- else
27
- (byte_count.abs_offset + 2) % 4
28
- end
25
+ if self.respond_to?(:name)
26
+ offset = (name.abs_offset + name.to_binary_s.length) % 4
27
+ else
28
+ offset = (byte_count.abs_offset + 2) % 4
29
+ end
29
30
  (4 - offset) % 4
30
31
  else
31
32
  0
@@ -33,7 +34,7 @@ module RubySMB
33
34
  end
34
35
 
35
36
  # Determines the correct length for the padding in front of
36
- # trans_data. It should always force a 4-byte alignment.
37
+ # #trans_data. It should always force a 4-byte alignment.
37
38
  def pad2_length
38
39
  if enable_padding
39
40
  offset = (trans_parameters.abs_offset + trans_parameters.length) % 4
@@ -42,6 +43,17 @@ module RubySMB
42
43
  0
43
44
  end
44
45
  end
46
+
47
+ # Determines the correct length for the padding in front of
48
+ # #name. It should always force a 2-byte alignment.
49
+ def pad_name_length
50
+ if enable_padding
51
+ offset = (byte_count.abs_offset + 2) % 2
52
+ (2 - offset) % 2
53
+ else
54
+ 0
55
+ end
56
+ end
45
57
  end
46
58
  end
47
59
  end
@@ -2,37 +2,46 @@ module RubySMB
2
2
  module SMB1
3
3
  module Packet
4
4
  module Trans
5
- # A SMB1 SMB_COM_TRANSACTION Request Packet as defined in
6
- # [2.2.4.33.1 Request](https://msdn.microsoft.com/en-us/library/ee441730.aspx)
5
+
6
+ # This class represents a generic SMB1 Trans Request Packet as defined in
7
+ # [2.2.4.33.1 Request](https://msdn.microsoft.com/en-us/library/ee441730.aspx)
7
8
  class Request < RubySMB::GenericPacket
8
9
  # A SMB1 Parameter Block
9
10
  class ParameterBlock < RubySMB::SMB1::ParameterBlock
10
- uint16 :total_parameter_count, label: 'Total Parameter Count(bytes)'
11
- uint16 :total_data_count, label: 'Total Data Count(bytes)'
12
- uint16 :max_parameter_count, label: 'Max Parameter Count(bytes)'
13
- uint16 :max_data_count, label: 'Max Data Count(bytes)'
14
- uint8 :max_setup_count, label: 'Max Setup Count'
15
- uint8 :reserved, label: 'Reserved Space', initial_value: 0x00
16
- trans_flags :flags
17
- uint32 :timeout, label: 'Timeout', initial_value: 0x00000000
18
- uint16 :reserved2, label: 'Reserved Space', initial_value: 0x00
19
- uint16 :parameter_count, label: 'Parameter Count(bytes)', initial_value: -> { parent.data_block.trans_parameters.length }
20
- uint16 :parameter_offset, label: 'Parameter Offset', initial_value: -> { parent.data_block.trans_parameters.abs_offset }
21
- uint16 :data_count, label: 'Data Count(bytes)', initial_value: -> { parent.data_block.trans_data.length }
22
- uint16 :data_offset, label: 'Data Offset', initial_value: -> { parent.data_block.trans_data.abs_offset }
23
- uint8 :setup_count, label: 'Setup Count', initial_value: -> { setup.length }
24
- uint8 :reserved3, label: 'Reserved Space', initial_value: 0x00
25
-
26
- array :setup, type: :uint16, initial_length: 0
11
+ uint16 :total_parameter_count, label: 'Total Parameter Count(bytes)', initial_value: -> { parameter_count }
12
+ uint16 :total_data_count, label: 'Total Data Count(bytes)', initial_value: -> { data_count }
13
+ uint16 :max_parameter_count, label: 'Max Parameter Count(bytes)', initial_value: Trans::MAX_PARAMETER_COUNT
14
+ uint16 :max_data_count, label: 'Max Data Count(bytes)', initial_value: Trans::MAX_DATA_COUNT
15
+ uint8 :max_setup_count, label: 'Max Setup Count', initial_value: Trans::MAX_SETUP_COUNT
16
+ uint8 :reserved, label: 'Reserved Space', value: 0x00
17
+ trans_flags :flags
18
+ uint32 :timeout, label: 'Timeout', initial_value: 0x00000000
19
+ uint16 :reserved2, label: 'Reserved Space', value: 0x0000
20
+ uint16 :parameter_count, label: 'Parameter Count(bytes)', initial_value: -> { parent.data_block.trans_parameters.length }
21
+ uint16 :parameter_offset, label: 'Parameter Offset', initial_value: -> { parent.data_block.trans_parameters.abs_offset }
22
+ uint16 :data_count, label: 'Data Count(bytes)', initial_value: -> { parent.data_block.trans_data.length }
23
+ uint16 :data_offset, label: 'Data Offset', initial_value: -> { parent.data_block.trans_data.abs_offset }
24
+ uint8 :setup_count, label: 'Setup Count', initial_value: -> { setup.length }
25
+ uint8 :reserved3, label: 'Reserved Space', value: 0x00
26
+ array :setup, type: :uint16, initial_length: :setup_count
27
27
  end
28
28
 
29
29
  # The {RubySMB::SMB1::DataBlock} specific to this packet type.
30
30
  class DataBlock < RubySMB::SMB1::Packet::Trans::DataBlock
31
- stringz :name, label: 'Name', initial_value: ""
32
- string :pad1, length: -> { pad1_length }
33
- string :trans_parameters, label: 'Trans Parameters'
34
- string :pad2, length: -> { pad2_length }
35
- string :trans_data, label: 'Trans Data'
31
+ # If unicode is set, the name field must be aligned to start on a 2-byte
32
+ # boundary from the start of the SMB header:
33
+ string :pad_name, length: -> { pad_name_length },
34
+ onlyif: -> { parent.smb_header.flags2.unicode.to_i == 1 }
35
+ choice :name, :selection => lambda { parent.smb_header.flags2.unicode.to_i },
36
+ :copy_on_change => true do
37
+ stringz 0, label: 'Name', initial_value: "\\PIPE\\"
38
+ stringz16 1, label: 'Name', initial_value: "\\PIPE\\".encode('utf-16le')
39
+
40
+ end
41
+ string :pad1, length: lambda { pad1_length }
42
+ string :trans_parameters, label: 'Trans Parameters', read_length: -> { parent.parameter_block.parameter_count }
43
+ string :pad2, length: lambda { pad2_length }
44
+ string :trans_data, label: 'Trans Data', read_length: -> { parent.parameter_block.data_count }
36
45
  end
37
46
 
38
47
  smb_header :smb_header
@@ -43,8 +52,10 @@ module RubySMB
43
52
  super
44
53
  smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
45
54
  end
55
+
46
56
  end
47
57
  end
48
58
  end
49
59
  end
50
- end
60
+ end
61
+