def from_buffer(buff):
		sd = SECURITY_DESCRIPTOR()
		sd.Revision = int.from_bytes(buff.read(1), 'little', signed = False)
		sd.Sbz1 =  int.from_bytes(buff.read(1), 'little', signed = False)
		sd.Control = SE_SACL(int.from_bytes(buff.read(2), 'little', signed = False))
		OffsetOwner  = int.from_bytes(buff.read(4), 'little', signed = False)
		OffsetGroup  = int.from_bytes(buff.read(4), 'little', signed = False)
		OffsetSacl  = int.from_bytes(buff.read(4), 'little', signed = False)
		OffsetDacl  = int.from_bytes(buff.read(4), 'little', signed = False)
		if OffsetOwner > 0:
			buff.seek(OffsetOwner)
			sd.Owner = SID.from_buffer(buff)
		
		if OffsetGroup > 0:
			buff.seek(OffsetGroup)
			sd.Group = SID.from_buffer(buff)
			
		if OffsetSacl > 0:
			buff.seek(OffsetSacl)
			sd.Sacl = ACL.from_buffer(buff)
		
		if OffsetDacl > 0:
			buff.seek(OffsetDacl)
			sd.Dacl = ACL.from_buffer(buff)
			
		return sd
Exemple #2
0
	def from_buffer(buff):
		ace = SYSTEM_RESOURCE_ATTRIBUTE_ACE()
		ace.Header = ACEHeader.from_buffer(buff)
		ace.Mask = ADS_ACCESS_MASK(int.from_bytes(buff.read(4), 'little', signed = False))
		ace.Sid = SID.from_buffer(buff)
		ace.AttributeData = buff.read() #not really sure, this will consume the whole buffer! (but we dont know the size at this point!)
		return ace
Exemple #3
0
	def from_buffer(buff):
		ace = SYSTEM_AUDIT_CALLBACK_ACE()
		ace.Header = ACEHeader.from_buffer(buff)
		ace.Mask = ADS_ACCESS_MASK(int.from_bytes(buff.read(4), 'little', signed = False))
		ace.Sid = SID.from_buffer(buff)
		ace.ApplicationData = buff.read() #not really sure, this will consume the whole buffer! (but we dont know the size at this point!)
		return ace
Exemple #4
0
	def from_buffer(buff):
		ace = ACCESS_DENIED_OBJECT_ACE()
		ace.Header = ACEHeader.from_buffer(buff)
		ace.Mask = ADS_ACCESS_MASK(int.from_bytes(buff.read(4), 'little', signed = False))
		ace.Flags = ACCESS_ALLOWED_OBJECT_Flags(int.from_bytes(buff.read(4), 'little', signed = False))
		if ace.Flags & ACCESS_ALLOWED_OBJECT_Flags.ACE_OBJECT_TYPE_PRESENT:
			ace.ObjectType = GUID.from_buffer(buff)
		if ace.Flags & ACCESS_ALLOWED_OBJECT_Flags.ACE_INHERITED_OBJECT_TYPE_PRESENT:
			ace.InheritedObjectType = GUID.from_buffer(buff)
		ace.Sid = SID.from_buffer(buff)
		return ace
Exemple #5
0
	def from_buffer(buff):
		ace = SYSTEM_AUDIT_CALLBACK_OBJECT_ACE()
		ace.Header = ACEHeader.from_buffer(buff)
		ace.Mask = ADS_ACCESS_MASK(int.from_bytes(buff.read(4), 'little', signed = False))
		ace.Flags = ACCESS_ALLOWED_OBJECT_Flags(int.from_bytes(buff.read(4), 'little', signed = False))
		if ace.Flags & ACCESS_ALLOWED_OBJECT_Flags.ACE_OBJECT_TYPE_PRESENT:
			ace.ObjectType = GUID.from_buffer(buff)
		if ace.Flags & ACCESS_ALLOWED_OBJECT_Flags.ACE_INHERITED_OBJECT_TYPE_PRESENT:
			ace.InheritedObjectType = GUID.from_buffer(buff)
		ace.Sid = SID.from_buffer(buff)
		ace.ApplicationData = buff.read() #not really sure, this will consume the whole buffer! (but we dont know the size at this point!)
		return ace
Exemple #6
0
	def from_buffer(buff):
		ace = ACCESS_ALLOWED_ACE()
		ace.Header = ACEHeader.from_buffer(buff)
		ace.Mask = ADS_ACCESS_MASK(int.from_bytes(buff.read(4), 'little', signed = False))
		ace.Sid = SID.from_buffer(buff)
		return ace
Exemple #7
0
	def from_buffer(buff):
		ace = SYSTEM_MANDATORY_LABEL_ACE()
		ace.Header = ACEHeader.from_buffer(buff)
		ace.Mask = ADS_ACCESS_MASK(int.from_bytes(buff.read(4), 'little', signed = False))
		ace.Sid = SID.from_buffer(buff)
		return ace
Exemple #8
0
    async def get_user_secrets(self, username):
        ra = {
            'userPrincipalName': '1.2.840.113556.1.4.656',
            'sAMAccountName': '1.2.840.113556.1.4.221',
            'unicodePwd': '1.2.840.113556.1.4.90',
            'dBCSPwd': '1.2.840.113556.1.4.55',
            'ntPwdHistory': '1.2.840.113556.1.4.94',
            'lmPwdHistory': '1.2.840.113556.1.4.160',
            'supplementalCredentials': '1.2.840.113556.1.4.125',
            'objectSid': '1.2.840.113556.1.4.146',
            'pwdLastSet': '1.2.840.113556.1.4.96',
            'userAccountControl': '1.2.840.113556.1.4.8'
        }
        formatOffered = drsuapi.DS_NT4_ACCOUNT_NAME_SANS_DOMAIN

        crackedName = await self.DRSCrackNames(
            formatOffered,
            drsuapi.DS_NAME_FORMAT.DS_UNIQUE_ID_NAME,
            name=username)

        ###### TODO: CHECKS HERE

        #guid = GUID.from_string(crackedName['pmsgOut']['V1']['pResult']['rItems'][0]['pName'][:-1][1:-1])
        guid = crackedName['pmsgOut']['V1']['pResult']['rItems'][0][
            'pName'][:-1][1:-1]

        userRecord = await self.DRSGetNCChanges(guid, ra)

        replyVersion = 'V%d' % userRecord['pdwOutVersion']
        if userRecord['pmsgOut'][replyVersion]['cNumObjects'] == 0:
            raise Exception('DRSGetNCChanges didn\'t return any object!')

        #print(userRecord.dump())
        #print(userRecord['pmsgOut'][replyVersion]['PrefixTableSrc']['pPrefixEntry'])

        record = userRecord
        prefixTable = userRecord['pmsgOut'][replyVersion]['PrefixTableSrc'][
            'pPrefixEntry']
        ##### decryption!
        logger.debug('Decrypting hash for user: %s' %
                     record['pmsgOut'][replyVersion]['pNC']['StringName'][:-1])

        us = SMBUserSecrets()
        user_properties = None

        rid = int.from_bytes(record['pmsgOut'][replyVersion]['pObjects']
                             ['Entinf']['pName']['Sid'][-4:],
                             'little',
                             signed=False)

        for attr in record['pmsgOut'][replyVersion]['pObjects']['Entinf'][
                'AttrBlock']['pAttr']:

            try:
                attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp'])
                LOOKUP_TABLE = self.ATTRTYP_TO_ATTID
            except Exception as e:
                logger.error(
                    'Failed to execute OidFromAttid with error %s, fallbacking to fixed table'
                    % e)
                logger.error('Exception', exc_info=True)
                input()
                # Fallbacking to fixed table and hope for the best
                attId = attr['attrTyp']
                LOOKUP_TABLE = self.NAME_TO_ATTRTYP

            if attId == LOOKUP_TABLE['dBCSPwd']:
                if attr['AttrVal']['valCount'] > 0:
                    encrypteddBCSPwd = b''.join(
                        attr['AttrVal']['pAVal'][0]['pVal'])
                    encryptedLMHash = drsuapi.DecryptAttributeValue(
                        self.dce.get_session_key(), encrypteddBCSPwd)
                    us.lm_hash = drsuapi.removeDESLayer(encryptedLMHash, rid)
                else:
                    us.lm_hash = bytes.fromhex(
                        'aad3b435b51404eeaad3b435b51404ee')

            elif attId == LOOKUP_TABLE['unicodePwd']:
                if attr['AttrVal']['valCount'] > 0:
                    encryptedUnicodePwd = b''.join(
                        attr['AttrVal']['pAVal'][0]['pVal'])
                    encryptedNTHash = drsuapi.DecryptAttributeValue(
                        self.dce.get_session_key(), encryptedUnicodePwd)
                    us.nt_hash = drsuapi.removeDESLayer(encryptedNTHash, rid)
                else:
                    us.nt_hash = bytes.fromhex(
                        '31d6cfe0d16ae931b73c59d7e0c089c0')

            elif attId == LOOKUP_TABLE['userPrincipalName']:
                if attr['AttrVal']['valCount'] > 0:
                    try:
                        us.domain = b''.join(
                            attr['AttrVal']['pAVal'][0]['pVal']).decode(
                                'utf-16le').split('@')[-1]
                    except:
                        us.domain = None
                else:
                    us.domain = None

            elif attId == LOOKUP_TABLE['sAMAccountName']:
                if attr['AttrVal']['valCount'] > 0:
                    try:
                        us.username = b''.join(attr['AttrVal']['pAVal'][0]
                                               ['pVal']).decode('utf-16le')
                    except Exception as e:
                        logger.error('Cannot get sAMAccountName for %s' %
                                     record['pmsgOut'][replyVersion]['pNC']
                                     ['StringName'][:-1])
                        us.username = '******'
                else:
                    logger.error('Cannot get sAMAccountName for %s' %
                                 record['pmsgOut'][replyVersion]['pNC']
                                 ['StringName'][:-1])
                    us.username = '******'

            elif attId == LOOKUP_TABLE['objectSid']:
                if attr['AttrVal']['valCount'] > 0:
                    us.object_sid = SID.from_bytes(b''.join(
                        attr['AttrVal']['pAVal'][0]['pVal']))
                else:
                    logger.error('Cannot get objectSid for %s' %
                                 record['pmsgOut'][replyVersion]['pNC']
                                 ['StringName'][:-1])
                    us.object_sid = rid
            elif attId == LOOKUP_TABLE['pwdLastSet']:
                if attr['AttrVal']['valCount'] > 0:
                    try:

                        us.pwd_last_set = FILETIME.from_bytes(
                            b''.join(attr['AttrVal']['pAVal'][0]
                                     ['pVal'])).datetime.isoformat()
                    except Exception as e:

                        logger.error('Cannot get pwdLastSet for %s' %
                                     record['pmsgOut'][replyVersion]['pNC']
                                     ['StringName'][:-1])
                        us.pwd_last_set = None
                        input(e)

            elif attId == LOOKUP_TABLE['userAccountControl']:
                if attr['AttrVal']['valCount'] > 0:
                    us.user_account_status = int.from_bytes(b''.join(
                        attr['AttrVal']['pAVal'][0]['pVal']),
                                                            'little',
                                                            signed=False)
                else:
                    us.user_account_status = None

            if attId == LOOKUP_TABLE['lmPwdHistory']:
                if attr['AttrVal']['valCount'] > 0:
                    encryptedLMHistory = b''.join(
                        attr['AttrVal']['pAVal'][0]['pVal'])
                    tmpLMHistory = drsuapi.DecryptAttributeValue(
                        self.dce.get_session_key(), encryptedLMHistory)
                    for i in range(0, len(tmpLMHistory) // 16):
                        LMHashHistory = drsuapi.removeDESLayer(
                            tmpLMHistory[i * 16:(i + 1) * 16], rid)
                        us.lm_history.append(LMHashHistory)
                else:
                    logger.debug('No lmPwdHistory for user %s' %
                                 record['pmsgOut'][replyVersion]['pNC']
                                 ['StringName'][:-1])
            elif attId == LOOKUP_TABLE['ntPwdHistory']:
                if attr['AttrVal']['valCount'] > 0:
                    encryptedNTHistory = b''.join(
                        attr['AttrVal']['pAVal'][0]['pVal'])
                    tmpNTHistory = drsuapi.DecryptAttributeValue(
                        self.dce.get_session_key(), encryptedNTHistory)
                    for i in range(0, len(tmpNTHistory) // 16):
                        NTHashHistory = drsuapi.removeDESLayer(
                            tmpNTHistory[i * 16:(i + 1) * 16], rid)
                        us.nt_history.append(NTHashHistory)
                else:
                    logger.debug('No ntPwdHistory for user %s' %
                                 record['pmsgOut'][replyVersion]['pNC']
                                 ['StringName'][:-1])

            elif attId == LOOKUP_TABLE['supplementalCredentials']:
                if attr['AttrVal']['valCount'] > 0:
                    blob = b''.join(attr['AttrVal']['pAVal'][0]['pVal'])
                    supplementalCredentials = drsuapi.DecryptAttributeValue(
                        self.dce.get_session_key(), blob)
                    if len(supplementalCredentials) < 24:
                        supplementalCredentials = None

                    else:
                        try:
                            user_properties = samr.USER_PROPERTIES(
                                supplementalCredentials)
                        except Exception as e:
                            # On some old w2k3 there might be user properties that don't
                            # match [MS-SAMR] structure, discarding them
                            pass

        if user_properties is not None:
            propertiesData = user_properties['UserProperties']
            for propertyCount in range(user_properties['PropertyCount']):
                userProperty = samr.USER_PROPERTY(propertiesData)
                propertiesData = propertiesData[len(userProperty):]
                # For now, we will only process Newer Kerberos Keys and CLEARTEXT
                if userProperty['PropertyName'].decode(
                        'utf-16le') == 'Primary:Kerberos-Newer-Keys':
                    propertyValueBuffer = bytes.fromhex(
                        userProperty['PropertyValue'].decode())
                    kerbStoredCredentialNew = samr.KERB_STORED_CREDENTIAL_NEW(
                        propertyValueBuffer)
                    data = kerbStoredCredentialNew['Buffer']
                    for credential in range(
                            kerbStoredCredentialNew['CredentialCount']):
                        keyDataNew = samr.KERB_KEY_DATA_NEW(data)
                        data = data[len(keyDataNew):]
                        keyValue = propertyValueBuffer[
                            keyDataNew['KeyOffset']:][:keyDataNew['KeyLength']]

                        if keyDataNew['KeyType'] in self.KERBEROS_TYPE:
                            answer = (
                                self.KERBEROS_TYPE[keyDataNew['KeyType']],
                                keyValue)
                        else:
                            answer = (hex(keyDataNew['KeyType']), keyValue)
                        # We're just storing the keys, not printing them, to make the output more readable
                        # This is kind of ugly... but it's what I came up with tonight to get an ordered
                        # set :P. Better ideas welcomed ;)
                        us.kerberos_keys.append(answer)
                elif userProperty['PropertyName'].decode(
                        'utf-16le') == 'Primary:CLEARTEXT':
                    # [MS-SAMR] 3.1.1.8.11.5 Primary:CLEARTEXT Property
                    # This credential type is the cleartext password. The value format is the UTF-16 encoded cleartext password.
                    try:
                        answer = (
                            userProperty['PropertyValue'].decode('utf-16le'))
                    except UnicodeDecodeError:
                        # This could be because we're decoding a machine password. Printing it hex
                        answer = (
                            userProperty['PropertyValue'].decode('utf-8'))

                    us.cleartext_pwds.append(answer)

        return us