Lucene search
K

LDAP Update Object

🗓️ 31 Jul 2025 18:56:38Reported by jheyselType 
metasploit
 metasploit
🔗 www.rapid7.com👁 409 Views

LDAP object attribute module updates, reads, creates or deletes object attributes with a required object and attribute.

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::LDAP
  include Msf::OptionalSession::LDAP

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'LDAP Update Object',
        'Description' => %q{
          This module allows creating, reading, updating and deleting attributes of LDAP objects.
          Users can specify the object and must specify a corresponding attribute.
        },
        'Author' => ['jheysel'],
        'License' => MSF_LICENSE,
        'Actions' => [
          ['CREATE', { 'Description' => 'Create an LDAP object' }],
          ['READ', { 'Description' => 'Read the the LDAP object' }],
          ['UPDATE', { 'Description' => 'Modify the LDAP object' }],
          ['DELETE', { 'Description' => 'Delete the LDAP object' }]
        ],
        'DefaultAction' => 'READ',
        'Notes' => {
          'Stability' => [CRASH_SAFE],
          'Reliability' => [],
          'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
        }
      )
    )

    register_options(
      [
        OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']),
        OptEnum.new('OBJECT_LOOKUP', [true, 'How to look up the target LDAP object', 'dN', ['dN', 'sAMAccountName']]),
        OptString.new('OBJECT', [true, 'The target LDAP object']),
        OptString.new('ATTRIBUTE', [true, 'The LDAP attribute to update (e.g., userPrincipalName)']),
        OptString.new('VALUE', [false, 'The value for the specified LDAP object attribute'], conditions: ['ACTION', 'in', %w[Create Update] ])
      ]
    )
  end

  def find_target_object
    search_filter = "(&(#{ldap_escape_filter(datastore['OBJECT_LOOKUP'])}=#{ldap_escape_filter(datastore['OBJECT'])}))"
    result = []

    @ldap.search(base: @base_dn, filter: search_filter, attributes: ['distinguishedName', datastore['ATTRIBUTE']]) do |entry|
      result << entry
    end

    if result.empty?
      fail_with(Failure::NotFound, "Could not find any object matching the filter: #{search_filter}")
    elsif result.size > 1
      fail_with(Failure::UnexpectedReply, "Found multiple objects matching the filter: #{search_filter}. This should not happen.")
    end

    result.first
  end

  def action_read
    target_object = find_target_object
    target_dn = target_object['dN'].first
    attribute_value = target_object[datastore['ATTRIBUTE'].to_sym]&.first

    if attribute_value.blank?
      fail_with(Failure::NotFound, "Attribute #{datastore['ATTRIBUTE']} is not set for #{target_dn}")
    end

    print_good("Found #{target_dn} with #{datastore['ATTRIBUTE']} set to #{attribute_value}")
    attribute_value
  end

  def action_create
    target_object = find_target_object
    target_dn = target_object['dN'].first
    attribute = datastore['ATTRIBUTE'].to_sym
    value = datastore['VALUE']

    print_status("Attempting to add attribute #{datastore['ATTRIBUTE']} with value #{value} to #{target_dn}...")

    ops = [[:add, attribute, value]]
    @ldap.modify(dn: target_dn, operations: ops)
    validate_query_result!(@ldap.get_operation_result.table)

    print_good("Successfully added attribute #{datastore['ATTRIBUTE']} with value #{value} to #{target_dn}")
  end

  def action_update
    target_object = find_target_object
    target_dn = target_object['dN'].first
    attribute = datastore['ATTRIBUTE'].to_sym
    original_value = target_object[attribute]&.first
    print_status("Current value of #{datastore['OBJECT']}'s #{datastore['ATTRIBUTE']}: #{original_value}")

    ops = [[:replace, attribute, datastore['VALUE']]]

    print_status("Attempting to update #{datastore['ATTRIBUTE']} for #{target_dn} to #{datastore['VALUE']}...")
    @ldap.modify(dn: target_dn, operations: ops)
    validate_query_result!(@ldap.get_operation_result.table)

    print_good("Successfully updated #{target_dn}'s #{datastore['ATTRIBUTE']} to #{datastore['VALUE']}")
    original_value
  end

  def action_delete
    target_object = find_target_object
    target_dn = target_object['dN'].first
    attribute = datastore['ATTRIBUTE'].to_sym

    print_status("Attempting to delete attribute #{datastore['ATTRIBUTE']} from #{target_dn}...")

    ops = [[:delete, attribute]]
    @ldap.modify(dn: target_dn, operations: ops)
    validate_query_result!(@ldap.get_operation_result.table)

    print_good("Successfully deleted attribute #{datastore['ATTRIBUTE']} from #{target_dn}")
  end

  def run
    if (datastore['ACTION'].downcase == 'update' || datastore['ACTION'].downcase == 'create') && datastore['VALUE'].blank?
      fail_with(Failure::BadConfig, 'The VALUE option must be set for CREATE and UPDATE actions.')
    end

    ldap_connect do |ldap|
      validate_bind_success!(ldap)

      if (@base_dn = datastore['BASE_DN'])
        vprint_status("User-specified base DN: #{@base_dn}")
      else
        vprint_status('Discovering base DN automatically')

        unless (@base_dn = ldap.base_dn)
          fail_with(Failure::NotFound, "Couldn't discover base DN!")
        end
      end
      @ldap = ldap

      result = send("action_#{action.name.downcase}")
      print_good('The operation completed successfully!')
      result
    end
  rescue Errno::ECONNRESET
    fail_with(Failure::Disconnected, 'The connection was reset.')
  rescue Rex::ConnectionError => e
    fail_with(Failure::Unreachable, e.message)
  rescue Net::LDAP::Error => e
    fail_with(Failure::Unknown, "#{e.class}: #{e.message}")
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation