ruby_smb 0.0.21 → 0.0.22

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.
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
+