Class: Contrast::Agent::Protect::Rule::Xxe::EntityWrapper

Inherits:
Object
  • Object
show all
Defined in:
lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb

Overview

A holder for the external entity which was determined to be an attack.

Constant Summary collapse

DTD_MARKER =
'.dtd'
FILE_START =
'file:'
FTP_START =
'ftp:'
GOPHER_START =
'gopher:'
JAR_START =
'jar:'
UP_DIR_LINUX =
'../'
UP_DIR_WIN =
'..\\'
SYSTEM_ID_REGEXP =

<!ENTITY name SYSTEM “URI”>

/<!ENTITY\s+(?<name>[a-zA-Z0-f]+)\s+SYSTEM\s+"(?<id>.*?)">/.cs__freeze
PUBLIC_ID_REGEXP =

<!ENTITY name PUBLIC “public_ID” “URI”>

/<!ENTITY\s+(?<name>[a-zA-Z0-f]+)\s+PUBLIC\s+".*?"\s+"(?<id>.*?)">/.cs__freeze
FILE_PATTERN_WINDOWS =

we only use this against lowercase strings, removed A-Z for speed

/^\\*[a-z]{1,3}:.*/.cs__freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(entity) ⇒ EntityWrapper

Returns a new instance of EntityWrapper.



28
29
30
31
32
# File 'lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb', line 28

def initialize entity
  @system_id = parse_system_id(entity)
  # an entity cannot be system and public
  @public_id = parse_public_id(entity) unless @system_id
end

Instance Attribute Details

#public_idObject (readonly)

Returns the value of attribute public_id.



12
13
14
# File 'lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb', line 12

def public_id
  @public_id
end

#system_idObject (readonly)

Returns the value of attribute system_id.



12
13
14
# File 'lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb', line 12

def system_id
  @system_id
end

Instance Method Details

#external_entity?Boolean

Returns:

  • (Boolean)


34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb', line 34

def external_entity?
  if @_external_entity.nil?
    @_external_entity ||= if @system_id
                            external_id?(@system_id)
                          elsif @public_id
                            external_id?(@public_id)
                          else
                            false
                          end
  end
  @_external_entity
end

#external_id?(entity_id) ⇒ Boolean

Returns:

  • (Boolean)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb', line 57

def external_id? entity_id
  return false unless entity_id

  # downcase this since we don't have an ignore case compare
  tmp_id = entity_id.to_s.downcase

  # external if http(s) and not a dtd file
  http = tmp_id.start_with?(Contrast::Utils::ObjectShare::HTTP_START,
                            Contrast::Utils::ObjectShare::HTTPS_START)
  return true if http && !tmp_id.end_with?(DTD_MARKER)

  # external if using external protocol
  return true if tmp_id.start_with?(FTP_START, FILE_START, JAR_START, GOPHER_START)

  # external if start with path marker (/ or .)
  return true if tmp_id.start_with?(Contrast::Utils::ObjectShare::SLASH,
                                    Contrast::Utils::ObjectShare::PERIOD)

  # external if start with path up marker (../ or ..\)
  return true if tmp_id.start_with?(UP_DIR_LINUX, UP_DIR_WIN)

  # external if matches windows file pattern
  tmp_id.match?(FILE_PATTERN_WINDOWS)
end

#parse_public_id(entity) ⇒ Object



52
53
54
55
# File 'lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb', line 52

def parse_public_id entity
  match = PUBLIC_ID_REGEXP.match(entity)
  match[:id] if match
end

#parse_system_id(entity) ⇒ Object



47
48
49
50
# File 'lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb', line 47

def parse_system_id entity
  match = SYSTEM_ID_REGEXP.match(entity)
  match[:id] if match
end