rex 2.0.5 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex/exploitation/egghunter.rb +4 -6
  3. data/lib/rex/exploitation/powershell/psh_methods.rb +9 -0
  4. data/lib/rex/java/serialization.rb +2 -1
  5. data/lib/rex/java/serialization/builder.rb +94 -0
  6. data/lib/rex/java/serialization/model.rb +29 -18
  7. data/lib/rex/java/serialization/model/annotation.rb +2 -2
  8. data/lib/rex/java/serialization/model/field.rb +2 -2
  9. data/lib/rex/java/serialization/model/new_array.rb +8 -3
  10. data/lib/rex/java/serialization/model/new_class_desc.rb +3 -3
  11. data/lib/rex/java/serialization/model/new_enum.rb +4 -4
  12. data/lib/rex/java/serialization/model/new_object.rb +17 -10
  13. data/lib/rex/ole/direntry.rb +1 -1
  14. data/lib/rex/ole/samples/create_ole.rb +0 -0
  15. data/lib/rex/ole/samples/dir.rb +0 -0
  16. data/lib/rex/ole/samples/dump_stream.rb +0 -0
  17. data/lib/rex/ole/samples/ole_info.rb +0 -0
  18. data/lib/rex/parser/foundstone_nokogiri.rb +1 -1
  19. data/lib/rex/parser/fs/ntfs.rb +252 -0
  20. data/lib/rex/parser/openvas_nokogiri.rb +2 -0
  21. data/lib/rex/payloads/win32/kernel.rb +3 -3
  22. data/lib/rex/post/meterpreter/client_core.rb +172 -64
  23. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +3 -2
  24. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +12 -10
  25. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +64 -37
  26. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +8 -2
  27. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +15 -3
  28. data/lib/rex/post/meterpreter/packet.rb +41 -38
  29. data/lib/rex/post/meterpreter/packet_dispatcher.rb +7 -1
  30. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +17 -4
  31. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +11 -4
  32. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +1 -1
  33. data/lib/rex/proto.rb +2 -0
  34. data/lib/rex/proto/acpp.rb +17 -0
  35. data/lib/rex/proto/acpp/client.rb +29 -0
  36. data/lib/rex/proto/acpp/message.rb +183 -0
  37. data/lib/rex/proto/http/client.rb +1 -2
  38. data/lib/rex/proto/iax2/call.rb +22 -3
  39. data/lib/rex/proto/iax2/client.rb +1 -0
  40. data/lib/rex/proto/kerberos.rb +13 -0
  41. data/lib/rex/proto/kerberos/client.rb +213 -0
  42. data/lib/rex/proto/kerberos/credential_cache.rb +19 -0
  43. data/lib/rex/proto/kerberos/credential_cache/cache.rb +81 -0
  44. data/lib/rex/proto/kerberos/credential_cache/credential.rb +151 -0
  45. data/lib/rex/proto/kerberos/credential_cache/element.rb +49 -0
  46. data/lib/rex/proto/kerberos/credential_cache/key_block.rb +62 -0
  47. data/lib/rex/proto/kerberos/credential_cache/principal.rb +70 -0
  48. data/lib/rex/proto/kerberos/credential_cache/time.rb +69 -0
  49. data/lib/rex/proto/kerberos/crypto.rb +21 -0
  50. data/lib/rex/proto/kerberos/crypto/rc4_hmac.rb +65 -0
  51. data/lib/rex/proto/kerberos/crypto/rsa_md5.rb +15 -0
  52. data/lib/rex/proto/kerberos/model.rb +133 -0
  53. data/lib/rex/proto/kerberos/model/ap_req.rb +98 -0
  54. data/lib/rex/proto/kerberos/model/authenticator.rb +143 -0
  55. data/lib/rex/proto/kerberos/model/authorization_data.rb +85 -0
  56. data/lib/rex/proto/kerberos/model/checksum.rb +59 -0
  57. data/lib/rex/proto/kerberos/model/element.rb +67 -0
  58. data/lib/rex/proto/kerberos/model/enc_kdc_response.rb +215 -0
  59. data/lib/rex/proto/kerberos/model/encrypted_data.rb +171 -0
  60. data/lib/rex/proto/kerberos/model/encryption_key.rb +106 -0
  61. data/lib/rex/proto/kerberos/model/kdc_request.rb +166 -0
  62. data/lib/rex/proto/kerberos/model/kdc_request_body.rb +315 -0
  63. data/lib/rex/proto/kerberos/model/kdc_response.rb +141 -0
  64. data/lib/rex/proto/kerberos/model/krb_error.rb +219 -0
  65. data/lib/rex/proto/kerberos/model/last_request.rb +82 -0
  66. data/lib/rex/proto/kerberos/model/pre_auth_data.rb +104 -0
  67. data/lib/rex/proto/kerberos/model/pre_auth_enc_time_stamp.rb +126 -0
  68. data/lib/rex/proto/kerberos/model/pre_auth_pac_request.rb +81 -0
  69. data/lib/rex/proto/kerberos/model/principal_name.rb +116 -0
  70. data/lib/rex/proto/kerberos/model/ticket.rb +151 -0
  71. data/lib/rex/proto/kerberos/pac.rb +36 -0
  72. data/lib/rex/proto/kerberos/pac/client_info.rb +53 -0
  73. data/lib/rex/proto/kerberos/pac/element.rb +52 -0
  74. data/lib/rex/proto/kerberos/pac/logon_info.rb +566 -0
  75. data/lib/rex/proto/kerberos/pac/priv_svr_checksum.rb +29 -0
  76. data/lib/rex/proto/kerberos/pac/server_checksum.rb +30 -0
  77. data/lib/rex/proto/kerberos/pac/type.rb +121 -0
  78. data/lib/rex/proto/rmi.rb +7 -0
  79. data/lib/rex/proto/rmi/model.rb +31 -0
  80. data/lib/rex/proto/rmi/model/call.rb +60 -0
  81. data/lib/rex/proto/rmi/model/continuation.rb +76 -0
  82. data/lib/rex/proto/rmi/model/dgc_ack.rb +62 -0
  83. data/lib/rex/proto/rmi/model/element.rb +143 -0
  84. data/lib/rex/proto/rmi/model/output_header.rb +86 -0
  85. data/lib/rex/proto/rmi/model/ping.rb +41 -0
  86. data/lib/rex/proto/rmi/model/ping_ack.rb +41 -0
  87. data/lib/rex/proto/rmi/model/protocol_ack.rb +100 -0
  88. data/lib/rex/proto/rmi/model/return_data.rb +60 -0
  89. data/lib/rex/socket.rb +9 -1
  90. data/lib/rex/socket/tcp_server.rb +3 -0
  91. data/lib/rex/ui/text/dispatcher_shell.rb +4 -4
  92. data/lib/rex/ui/text/output/tee.rb +2 -0
  93. data/lib/rex/zip/samples/comment.rb +0 -0
  94. data/lib/rex/zip/samples/mkwar.rb +0 -0
  95. data/lib/rex/zip/samples/mkzip.rb +0 -0
  96. data/lib/rex/zip/samples/recursive.rb +0 -0
  97. data/rex.gemspec +1 -1
  98. metadata +56 -2
@@ -0,0 +1,29 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Kerberos
6
+ module Pac
7
+ # This class provides a representation of a PAC_PRIVSVR_CHECKSUM structure, which contains the
8
+ # checksum using the key of the KDC.
9
+ class PrivSvrChecksum < Element
10
+
11
+ # @!attribute version
12
+ # @return [Fixnum] The checksum type
13
+ attr_accessor :checksum
14
+
15
+ # Encodes the Rex::Proto::Kerberos::Pac::PacPrivSvrChecksum
16
+ #
17
+ # @return [String]
18
+ def encode
19
+ encoded = ''
20
+ encoded << [checksum].pack('V')
21
+ encoded << "\x00" * 16
22
+
23
+ encoded
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Kerberos
6
+ module Pac
7
+ # This class provides a representation of a PAC_SERVER_CHECKSUM structure, which contains the
8
+ # checksum using the key of the server.
9
+ class ServerChecksum < Element
10
+
11
+ # @!attribute version
12
+ # @return [Fixnum] The checksum type
13
+ attr_accessor :checksum
14
+
15
+ # Encodes the Rex::Proto::Kerberos::Pac::ServerChecksum
16
+ #
17
+ # @return [String]
18
+ def encode
19
+ encoded = ''
20
+ encoded << [checksum].pack('V')
21
+ encoded << "\x00" * 16
22
+
23
+ encoded
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,121 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Kerberos
6
+ module Pac
7
+ # This class provides a representation of a PAC_TYPE structure, the topmost structure
8
+ # of the PAC.
9
+ class Type < Element
10
+
11
+ # @!attribute buffers
12
+ # @return [Array<Rex::Proto::Kerberos::Pac::Element>] The array of PAC_INFO_BUFFER structures
13
+ attr_accessor :buffers
14
+ # @!attribute checksum
15
+ # @return [Fixnum] The type of checksum to use when encoding PAC-TYPE
16
+ attr_accessor :checksum
17
+
18
+ # Encodes the Rex::Proto::Kerberos::Pac::Type
19
+ #
20
+ # @return [String]
21
+ def encode
22
+ offset_one = 0
23
+ offset_two = 0
24
+
25
+ draft = ''
26
+ draft << encode_buffers_length
27
+ draft << encode_version
28
+ draft << encode_pac_info_buffers
29
+
30
+ # Encode buffers
31
+ buffers.each do |buffer|
32
+ if buffer.class == ServerChecksum
33
+ offset_one = draft.length + 4
34
+ elsif buffer.class == PrivSvrChecksum
35
+ offset_two = draft.length + 4
36
+ end
37
+
38
+ buffer_encoded = buffer.encode
39
+ draft << buffer_encoded
40
+ draft << "\x00" * ((buffer_encoded.length + 7) / 8 * 8 - buffer_encoded.length)
41
+ end
42
+
43
+ checksum_draft = make_checksum(draft)
44
+ double_checksum = make_checksum(checksum_draft)
45
+
46
+ encoded = ''
47
+ encoded << draft[0..(offset_one - 1)]
48
+ encoded << checksum_draft
49
+ encoded << draft[(offset_one + checksum_draft.length)..(offset_two - 1)]
50
+ encoded << double_checksum
51
+ encoded << draft[(offset_two + double_checksum.length)..(draft.length - 1)]
52
+
53
+ encoded
54
+ end
55
+
56
+ private
57
+
58
+ # Encodes the number of buffers contained in the PAC
59
+ #
60
+ # @return [String]
61
+ def encode_buffers_length
62
+ [buffers.length].pack('V')
63
+ end
64
+
65
+ # Encodes the PAC version
66
+ #
67
+ # @return [String]
68
+ def encode_version
69
+ [VERSION].pack('V')
70
+ end
71
+
72
+ # Encodes the PAC_INFO_BUFFER data
73
+ #
74
+ # @return [String]
75
+ def encode_pac_info_buffers
76
+ offset = 8 + buffers.length * 16
77
+ encoded = ''
78
+ buffers.each do |buffer|
79
+ case buffer
80
+ when ClientInfo
81
+ encoded << [PAC_CLIENT_INFO].pack('V')
82
+ when LogonInfo
83
+ encoded << [PAC_LOGON_INFO].pack('V')
84
+ when PrivSvrChecksum
85
+ encoded << [PAC_PRIVSVR_CHECKSUM].pack('V')
86
+ when ServerChecksum
87
+ encoded << [PAC_SERVER_CHECKSUM].pack('V')
88
+ end
89
+
90
+ buffer_length = buffer.encode.length
91
+
92
+ encoded << [buffer_length].pack('V')
93
+ encoded << [offset].pack('Q<')
94
+
95
+ offset = (offset + buffer_length + 7) / 8 * 8
96
+ end
97
+
98
+ encoded
99
+ end
100
+
101
+ # Calculates the checksum for the PAC data
102
+ #
103
+ # @param data [String] the data to checksum
104
+ # @return [String] the checksum result
105
+ # @raise [NotImplementedError] if checksum schema isn't supported
106
+ def make_checksum(data)
107
+ res = ''
108
+ case checksum
109
+ when RSA_MD5
110
+ res = checksum_rsa_md5(data)
111
+ else
112
+ raise ::NotImplementedError, 'PAC-TYPE checksum not supported'
113
+ end
114
+
115
+ res
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,7 @@
1
+ # -*- coding: binary -*-
2
+
3
+ # JAVA RMI Wire protocol implementation
4
+ # http://docs.oracle.com/javase/7/docs/platform/rmi/spec/rmi-protocol.html
5
+
6
+ require 'rex/proto/rmi/model'
7
+
@@ -0,0 +1,31 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Rmi
6
+ module Model
7
+ SIGNATURE = 'JRMI'
8
+ STREAM_PROTOCOL = 0x4b
9
+ SINGLE_OP_PROTOCOL = 0x4c
10
+ MULTIPLEX_PROTOCOL = 0x4d
11
+ CALL_MESSAGE = 0x50
12
+ PING_MESSAGE = 0x52
13
+ DGC_ACK_MESSAGE = 0x54
14
+ PROTOCOL_ACK = 0x4e
15
+ PROTOCOL_NOT_SUPPORTED = 0x4f
16
+ RETURN_DATA = 0x51
17
+ PING_ACK = 0x53
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ require 'rex/proto/rmi/model/element'
24
+ require 'rex/proto/rmi/model/output_header'
25
+ require 'rex/proto/rmi/model/protocol_ack'
26
+ require 'rex/proto/rmi/model/continuation'
27
+ require 'rex/proto/rmi/model/call'
28
+ require 'rex/proto/rmi/model/return_data'
29
+ require 'rex/proto/rmi/model/dgc_ack'
30
+ require 'rex/proto/rmi/model/ping'
31
+ require 'rex/proto/rmi/model/ping_ack'
@@ -0,0 +1,60 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Rmi
6
+ module Model
7
+ # This class provides a representation of an RMI call message
8
+ class Call < Element
9
+
10
+ # @!attribute message_id
11
+ # @return [Fixnum] the message id
12
+ attr_accessor :message_id
13
+ # @!attribute call_data
14
+ # @return [Rex::Java::Serialization::Model::Stream] the serialized call data
15
+ attr_accessor :call_data
16
+
17
+ private
18
+
19
+ # Reads the message id from the IO
20
+ #
21
+ # @param io [IO] the IO to read from
22
+ # @return [String]
23
+ # @raise [RuntimeError] if fails to decode the message id
24
+ def decode_message_id(io)
25
+ message_id = read_byte(io)
26
+ unless message_id == CALL_MESSAGE
27
+ raise ::RuntimeError, 'Failed to decode Call message id'
28
+ end
29
+
30
+ message_id
31
+ end
32
+
33
+ # Reads and deserializes the call data from the IO
34
+ #
35
+ # @param io [IO] the IO to read from
36
+ # @return [Rex::Java::Serialization::Model::Stream]
37
+ def decode_call_data(io)
38
+ call_data = Rex::Java::Serialization::Model::Stream.decode(io)
39
+
40
+ call_data
41
+ end
42
+
43
+ # Encodes the message_id field
44
+ #
45
+ # @return [String]
46
+ def encode_message_id
47
+ [message_id].pack('C')
48
+ end
49
+
50
+ # Encodes the address field
51
+ #
52
+ # @return [String]
53
+ def encode_call_data
54
+ call_data.encode
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,76 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Rmi
6
+ module Model
7
+ # This class provides a representation of an RMI continuation stream
8
+ class Continuation < Element
9
+
10
+ # @!attribute length
11
+ # @return [Fixnum] the end point address length
12
+ attr_accessor :length
13
+ # @!attribute address
14
+ # @return [String] the end point address
15
+ attr_accessor :address
16
+ # @!attribute port
17
+ # @return [Fixnum] the end point port
18
+ attr_accessor :port
19
+
20
+ private
21
+
22
+ # Reads the end point identifier address length from the IO
23
+ #
24
+ # @param io [IO] the IO to read from
25
+ # @return [Fixnum]
26
+ def decode_length(io)
27
+ length = read_short(io)
28
+
29
+ length
30
+ end
31
+
32
+ # Reads the end point address from the IO
33
+ #
34
+ # @param io [IO] the IO to read from
35
+ # @return [String]
36
+ def decode_address(io)
37
+ version = read_string(io, length)
38
+
39
+ version
40
+ end
41
+
42
+ # Reads the end point port from the IO
43
+ #
44
+ # @param io [IO] the IO to read from
45
+ # @return [Fixnum]
46
+ def decode_port(io)
47
+ port = read_int(io)
48
+
49
+ port
50
+ end
51
+
52
+ # Encodes the length field
53
+ #
54
+ # @return [String]
55
+ def encode_length
56
+ [length].pack('n')
57
+ end
58
+
59
+ # Encodes the address field
60
+ #
61
+ # @return [String]
62
+ def encode_address
63
+ address
64
+ end
65
+
66
+ # Encodes the port field
67
+ #
68
+ # @return [String]
69
+ def encode_port
70
+ [port].pack('N')
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,62 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Rmi
6
+ module Model
7
+ # This class provides a representation of an RMI DbgACK stream. It is an acknowledgement
8
+ # directed to a server's distributed garbage collector that indicates that remote objects
9
+ # in a return value from a server have been received by the client.
10
+ class DgcAck < Element
11
+
12
+ # @!attribute stream_id
13
+ # @return [Fixnum] the input stream id
14
+ attr_accessor :stream_id
15
+ # @!attribute unique_identifier
16
+ # @return [String] the unique identifier
17
+ attr_accessor :unique_identifier
18
+
19
+ private
20
+
21
+ # Reads the stream id from the IO
22
+ #
23
+ # @param io [IO] the IO to read from
24
+ # @return [String]
25
+ # @raise [RuntimeError] if fails to decode stream id
26
+ def decode_stream_id(io)
27
+ stream_id = read_byte(io)
28
+ unless stream_id == DGC_ACK_MESSAGE
29
+ raise ::RuntimeError, 'Failed to decode DgcAck stream id'
30
+ end
31
+
32
+ stream_id
33
+ end
34
+
35
+ # Reads the unique identifier from the IO
36
+ #
37
+ # @param io [IO] the IO to read from
38
+ # @return [String]
39
+ def decode_unique_identifier(io)
40
+ unique_identifier = read_string(io, 14)
41
+
42
+ unique_identifier
43
+ end
44
+
45
+ # Encodes the stream_id field
46
+ #
47
+ # @return [String]
48
+ def encode_stream_id
49
+ [stream_id].pack('C')
50
+ end
51
+
52
+ # Encodes the unique_identifier field
53
+ #
54
+ # @return [String]
55
+ def encode_unique_identifier
56
+ unique_identifier
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,143 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Proto
5
+ module Rmi
6
+ module Model
7
+ class Element
8
+
9
+ include Rex::Proto::Rmi::Model
10
+
11
+ def self.attr_accessor(*vars)
12
+ @attributes ||= []
13
+ @attributes.concat vars
14
+ super(*vars)
15
+ end
16
+
17
+ # Retrieves the element class fields
18
+ #
19
+ # @return [Array]
20
+ def self.attributes
21
+ @attributes
22
+ end
23
+
24
+ # Creates a Rex::Proto::Rmi::Model::Element with data from the IO.
25
+ #
26
+ # @param io [IO] the IO to read data from
27
+ # @return [Rex::Proto::Rmi::Model::Element]
28
+ def self.decode(io)
29
+ elem = self.new
30
+ elem.decode(io)
31
+
32
+ elem
33
+ end
34
+
35
+ def initialize(options = {})
36
+ self.class.attributes.each do |attr|
37
+ if options.has_key?(attr)
38
+ m = (attr.to_s + '=').to_sym
39
+ self.send(m, options[attr])
40
+ end
41
+ end
42
+ end
43
+
44
+ # Retrieves the element instance fields
45
+ #
46
+ # @return [Array]
47
+ def attributes
48
+ self.class.attributes
49
+ end
50
+
51
+ # Decodes the Rex::Proto::Rmi::Model::Element from the input.
52
+ #
53
+ # @raise [NoMethodError]
54
+ # @return [Rex::Proto::Rmi::Model::Element]
55
+ def decode(io)
56
+ self.class.attributes.each do |attr|
57
+ dec_method = ("decode_#{attr}").to_sym
58
+ decoded = self.send(dec_method, io)
59
+ assign_method = (attr.to_s + '=').to_sym
60
+ self.send(assign_method, decoded)
61
+ end
62
+
63
+ self
64
+ end
65
+
66
+ # Encodes the Rex::Proto::Rmi::Model::Element into an String.
67
+ #
68
+ # @raise [NoMethodError]
69
+ # @return [String]
70
+ def encode
71
+ encoded = ''
72
+ self.class.attributes.each do |attr|
73
+ m = ("encode_#{attr}").to_sym
74
+ encoded << self.send(m) if self.send(attr)
75
+ end
76
+
77
+ encoded
78
+ end
79
+
80
+ private
81
+
82
+ # Reads a byte from an IO
83
+ #
84
+ # @param io [IO] the IO to read from
85
+ # @return [Fixnum]
86
+ # @raise [RuntimeError] if the byte can't be read from io
87
+ def read_byte(io)
88
+ raw = io.read(1)
89
+ raise ::RuntimeError, 'Failed to read byte' unless raw
90
+
91
+ raw.unpack('C')[0]
92
+ end
93
+
94
+ # Reads a two bytes short from an IO
95
+ #
96
+ # @param io [IO] the IO to read from
97
+ # @return [Fixnum]
98
+ # @raise [RuntimeError] if the short can't be read from io
99
+ def read_short(io)
100
+ raw = io.read(2)
101
+
102
+ unless raw && raw.length == 2
103
+ raise ::RuntimeError, 'Failed to read short'
104
+ end
105
+
106
+ raw.unpack('n')[0]
107
+ end
108
+
109
+ # Reads a four bytes int from an IO
110
+ #
111
+ # @param io [IO] the IO to read from
112
+ # @return [Fixnum]
113
+ # @raise [RuntimeError] if the int can't be read from io
114
+ def read_int(io)
115
+ raw = io.read(4)
116
+
117
+ unless raw && raw.length == 4
118
+ raise ::RuntimeError, 'Failed to read short'
119
+ end
120
+
121
+ raw.unpack('N')[0]
122
+ end
123
+
124
+ # Reads an string from an IO
125
+ #
126
+ # @param io [IO] the IO to read from
127
+ # @param length [Fixnum] the string length
128
+ # @return [String]
129
+ # @raise [RuntimeError] if the string can't be read from io
130
+ def read_string(io, length)
131
+ raw = io.read(length)
132
+
133
+ unless raw && raw.length == length
134
+ raise ::RuntimeError, 'Failed to read string'
135
+ end
136
+
137
+ raw
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end