Class: Msf::DBManager::Import::MarshalValidator

Inherits:
Object
  • Object
show all
Defined in:
lib/msf/core/db_manager/import/marshal_validator.rb

Overview

Walks a Marshal byte stream structurally, reading type bytes only in type positions and skipping over data payloads. Rejects any stream that attempts to instantiate a named class (object, struct, custom marshal, module extension, etc.).

This runs BEFORE Marshal.load so no objects are ever instantiated from an unsafe payload.

Reference: ruby-doc.org/3.3/Marshal.html Reference: github.com/ruby/ruby/blob/master/doc/marshal/marshal.md

Constant Summary collapse

UNSAFE_TYPES =

Type bytes that always instantiate named classes — unconditionally blocked.

Set.new(%w[o c m C S e U d].map(&:ord)).freeze
DEFAULT_PERMITTED_CLASSES =

Default classes permitted for the ‘u’ (_dump/_load) serialization type.

%w[].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, permitted_classes: DEFAULT_PERMITTED_CLASSES) ⇒ MarshalValidator

Returns a new instance of MarshalValidator.

Parameters:

  • data (String)

    raw Marshal binary data

  • permitted_classes (Array<String>) (defaults to: DEFAULT_PERMITTED_CLASSES)

    class names allowed for _dump/_load (‘u’) deserialization. Defaults to DEFAULT_PERMITTED_CLASSES.



32
33
34
35
36
# File 'lib/msf/core/db_manager/import/marshal_validator.rb', line 32

def initialize(data, permitted_classes: DEFAULT_PERMITTED_CLASSES)
  @bytes = data.bytes
  @pos = 0
  @permitted_classes = Set.new(permitted_classes)
end

Class Method Details

.marshalled_data?(data) ⇒ Boolean

Check whether the given data starts with the Marshal 4.8 version header, indicating it is a Marshal-serialized payload.

Parameters:

  • data (String)

    raw binary data

Returns:

  • (Boolean)


62
63
64
# File 'lib/msf/core/db_manager/import/marshal_validator.rb', line 62

def self.marshalled_data?(data)
  data.length >= 2 && data.getbyte(0) == 4 && data.getbyte(1) == 8
end

.safe_load(data, permitted_classes: DEFAULT_PERMITTED_CLASSES) ⇒ Object

Convenience method: validate and then load.

Parameters:

  • data (String)

    raw Marshal binary data

  • permitted_classes (Array<String>) (defaults to: DEFAULT_PERMITTED_CLASSES)

    class names allowed for _dump/_load (‘u’) deserialization. Defaults to DEFAULT_PERMITTED_CLASSES.

Returns:

  • (Object)

    the deserialized object (only primitives + permitted classes)

Raises:



52
53
54
55
# File 'lib/msf/core/db_manager/import/marshal_validator.rb', line 52

def self.safe_load(data, permitted_classes: DEFAULT_PERMITTED_CLASSES)
  new(data, permitted_classes: permitted_classes).validate!
  Marshal.load(data)
end

Instance Method Details

#validate!true

Validate the entire stream. Raises MarshalValidationError if unsafe.

Returns:

  • (true)


40
41
42
43
44
# File 'lib/msf/core/db_manager/import/marshal_validator.rb', line 40

def validate!
  read_version
  validate_value
  true
end