Class: Msf::Exploit::Remote::LDAP::ActiveDirectory::SecurityDescriptorMatcher::Allow

Inherits:
Base
  • Object
show all
Defined in:
lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb

Overview

A general purpose Security Descriptor matcher for permissions in a single ACE. You typically want to use this to check for a single permission.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(permissions, object_id: nil) ⇒ Allow

Returns a new instance of Allow.

Parameters:

  • permissions (Symbol, Array<Symbol>)

    The abbreviated permission names e.g. :WP.

  • object_id (String) (defaults to: nil)

    An optional object GUID to use when matching the permission.



54
55
56
57
58
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 54

def initialize(permissions, object_id: nil)
  @permissions = Array.wrap(permissions)
  @object_id = object_id
  @result = nil
end

Instance Attribute Details

#permissionsObject (readonly)

Returns the value of attribute permissions.



50
51
52
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 50

def permissions
  @permissions
end

Class Method Details

.all(permissions, object_id: nil) ⇒ Object

Build a matcher that will check for all of the specified permissions.

Parameters:

  • The (Array<Symbol>)

    permissions to check for in their 2 letter abbreviated format, e.g. WP.

  • An (String, Nil)

    optional object ID that will be used for matching all the permissions.



109
110
111
112
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 109

def self.all(permissions, object_id: nil)
  permissions = Array.wrap(permissions)
  MultipleAll.new(permissions.map { |permission| new(permission, object_id: object_id) })
end

.any(permissions, object_id: nil) ⇒ Object

Build a matcher that will check for any of the specified permissions.

Parameters:

  • The (Array<Symbol>)

    permissions to check for in their 2 letter abbreviated format, e.g. WP.

  • An (String, Nil)

    optional object ID that will be used for matching all the permissions.



99
100
101
102
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 99

def self.any(permissions, object_id: nil)
  permissions = Array.wrap(permissions)
  MultipleAll.new(permissions.map { |permission| new(permission, object_id: object_id) })
end

.certificate_autoenrollmentObject



120
121
122
123
124
125
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 120

def self.certificate_autoenrollment
  MultipleAny.new([
    Allow.new(:CR, object_id: CERTIFICATE_AUTOENROLLMENT_EXTENDED_RIGHT),
    full_control
  ])
end

.certificate_enrollmentObject

Build a matcher that will check for a certificate’s enrollment permission.



128
129
130
131
132
133
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 128

def self.certificate_enrollment
  MultipleAny.new([
    Allow.new(:CR, object_id: CERTIFICATE_ENROLLMENT_EXTENDED_RIGHT),
    full_control
  ])
end

.full_controlObject



114
115
116
117
118
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 114

def self.full_control
  # Full Control is special and shouldn't be split across multiple ACEs, so to check that we use #new instead of
  # MultipleAll to ensure it's in 1 ACE.
  new(%i[ CC DC LC SW RP WP DT LO CR SD RC WD WO ])
end

Instance Method Details

#apply_ace!(ace) ⇒ Object



74
75
76
77
78
79
80
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 74

def apply_ace!(ace)
  return if ignore_ace?(ace)

  @result = ace.header.ace_type
  
  nil
end

#ignore_ace?(ace) ⇒ Boolean

Returns:

  • (Boolean)


60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 60

def ignore_ace?(ace)
  # ignore anything that's not an allow or deny ACE because those are the only two that will alter the outcome
  return true unless Rex::Proto::MsDtyp::MsDtypAceType.allow?(ace.header.ace_type) || Rex::Proto::MsDtyp::MsDtypAceType.deny?(ace.header.ace_type)

  if Rex::Proto::MsDtyp::MsDtypAceType.has_object?(ace.header.ace_type) && ace.body.flags.ace_object_type_present == 1
    return true if ace.body.object_type != @object_id
  else
    return true if @object_id
  end

  ace_permissions = ace.body.access_mask.permissions
  !@permissions.all? { |perm| ace_permissions.include?(perm) }
end

#matches?Boolean

Returns:

  • (Boolean)


87
88
89
90
91
92
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 87

def matches?
  # This is named matches? instead of allow? so that other matchers can be made in the future
  # to match on the desired outcome including audit and alarm events. We are affirming that the
  # security descriptor will apply the desired affect which in this case is to allow access.
  satisfied? && Rex::Proto::MsDtyp::MsDtypAceType.allow?(@result)
end

#satisfied?Boolean

Returns:

  • (Boolean)


82
83
84
85
# File 'lib/msf/core/exploit/remote/ldap/active_directory/security_descriptor_matcher.rb', line 82

def satisfied?
  # A matcher is satisfied when there's nothing left for it to check.
  !@result.nil?
end