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
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
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
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
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
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
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
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