def get_released_findings(project_name: str, attrs: str = '') -> List[Dict[str, FindingType]]: """Get all the findings that has been released.""" key_expression = Key('project_name').eq(project_name.lower()) filtering_exp = Attr('releaseDate').exists() query_attrs = { 'FilterExpression': filtering_exp, 'IndexName': 'project_findings', 'KeyConditionExpression': key_expression } if attrs and 'releaseDate' not in attrs: query_attrs['ProjectionExpression'] = attrs + ', releaseDate' if not attrs: query_attrs['ProjectionExpression'] = 'finding_id' response = FINDINGS_TABLE.query(**query_attrs) findings = response.get('Items', []) while response.get('LastEvaluatedKey'): query_attrs['ExclusiveStartKey'] = response['LastEvaluatedKey'] response = FINDINGS_TABLE.query(**query_attrs) findings += response.get('Items', []) findings = [get_finding(finding.get('finding_id')) for finding in findings] findings_released = [ get_finding(finding.get('finding_id')) for finding in findings if util.validate_release_date(finding) ] return findings_released
def test_create_msj_finding_pending(self): not_new_treatment_finding = get_finding('422286126') new_treatment_finding = get_finding('436992569') test_data = create_msj_finding_pending(not_new_treatment_finding) expected_output = '' assert test_data == expected_output test_data = create_msj_finding_pending(new_treatment_finding) expected_output = u'FIN.S.0038. Fuga de informaciĆ³n de negocio' assert expected_output in test_data
def test_format_data(self): finding_id = '422286126' finding_to_test = get_finding(finding_id) test_data = list(format_data(finding_to_test).keys()) expected_keys = [ 'context', 'modifiedSeverityScope', 'availabilityRequirement', 'evidence', 'releaseDate', 'availabilityImpact', 'exploit', 'modifiedPrivilegesRequired', 'verificationRequestDate', 'modifiedAttackVector', 'testType', 'id', 'affectedSystems', 'attackVectorDesc', 'requirements', 'severity', 'cvssBasescore', 'userInteraction', 'actor', 'cvssEnv', 'privilegesRequired', 'interested', 'treatmentJustification', 'treatment', 'projectName', 'finding', 'confidentialityImpact', 'integrityRequirement', 'remediationLevel', 'cwe', 'leader', 'modifiedConfidentialityImpact', 'files', 'modifiedUserInteraction', 'attackComplexity', 'attackVector', 'reportConfidence', 'cvssTemporal', 'remediated', 'clientProject', 'compromisedAttrs', 'findingType', 'exploitable', 'confidentialityRequirement', 'records', 'recordsNumber', 'modifiedAttackComplexity', 'treatmentManager', 'severityScope', 'cvssVersion', 'analyst', 'subscription', 'reportDate', 'effectSolution', 'reportLevel', 'verificationDate', 'scenario', 'severityCvss', 'modifiedAvailabilityImpact', 'age', 'vulnerability', 'findingId', 'threat', 'lastVulnerability', 'integrityImpact', 'modifiedIntegrityImpact', 'relatedFindings', 'exploitability' ] assert True
def get_finding(finding_id: str) -> Dict[str, FindingType]: """Retrieves and formats finding attributes""" finding = finding_dal.get_finding(finding_id) if not finding or not validate_finding(finding=finding): raise FindingNotFound() return finding_utils.format_data(finding)
def update_treatment_in_vuln(finding_id: str, updated_values: Dict[str, str]) -> bool: new_values = cast( Dict[str, FindingType], { 'treatment': updated_values.get('treatment', ''), 'treatment_justification': updated_values.get('justification'), 'acceptance_date': updated_values.get('acceptance_date'), }) if new_values['treatment'] == 'NEW': new_values['treatment_manager'] = None vulns = get_vulnerabilities(finding_id) resp = True for vuln in vulns: if 'treatment_manager' not in [vuln, new_values]: new_values[ 'treatment_manager'] = vuln_domain.set_treatment_manager( str(new_values.get('treatment', '')), str(updated_values.get('user', '')), finding_dal.get_finding(finding_id), user_domain.get_data(str(updated_values.get('user')), 'role') == 'customeradmin', str(updated_values.get('user', ''))) result_update_treatment = \ vuln_dal.update(finding_id, str(vuln.get('UUID', '')), new_values) if not result_update_treatment: resp = False return resp
def add_vuln_to_dynamo(item: Dict[str, str], specific: str, vuln: str, finding_id: str, info) -> bool: """Add vulnerability to dynamo.""" historic_state = [] last_finding_state = cast( List[Dict[str, str]], finding_dal.get_finding(finding_id)['historic_treatment'])[-1] where = item.get('where', '') vulnerability = cast( List[Dict[str, str]], vuln_dal.get(finding_id, vuln_type=vuln, where=where, specific=specific)) response = False tzn = pytz.timezone(settings.TIME_ZONE) # type: ignore current_day = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S') user_data = cast(UserType, util.get_jwt_content(info.context)) email = str(user_data['user_email']) if vulnerability: response = update_vuln_state(info, vulnerability, item, finding_id, current_day) else: data: Dict[str, FindingType] = {} data['vuln_type'] = vuln data['where'] = where data['specific'] = specific data['finding_id'] = finding_id data['UUID'] = str(uuid.uuid4()) data['treatment'] = 'NEW' if last_finding_state['treatment'] != 'NEW': data['treatment_manager'] = last_finding_state.get('user', '') if item.get('state'): if util.is_api_token(user_data): historic_state.append({ 'date': current_day, 'state': item.get('state', ''), 'origin': item.get('origin', ''), 'approval_status': 'PENDING', 'analyst': 'api-{email}'.format(email=email) }) else: historic_state.append({ 'date': current_day, 'state': item.get('state', ''), 'analyst': email }) data['historic_state'] = historic_state response = vuln_dal.create(data) else: util.cloudwatch_log( info.context, 'Security: Attempted to add vulnerability without state') return response
def validate_finding(finding_id: Union[str, int] = 0, finding: Dict[str, FindingType] = None) -> bool: """Validate if a finding is not deleted.""" if not finding: finding = finding_dal.get_finding(str(finding_id)) historic_state = cast(List[Dict[str, str]], finding.get('historic_state', [{}])) return historic_state[-1].get('state', '') != 'DELETED'
def test_get_by_time_range(self): finding = get_finding('422286126') first_day = '2019-01-01 12:00:00' last_day = '2019-06-30 23:59:59' vuln = get_vulnerabilities('422286126')[0] test_data = get_by_time_range( finding, vuln, first_day, last_day ) expected_output = 1 assert test_data == expected_output
def request_verification(finding_id: str, user_email: str, user_fullname: str, justification: str, vuln_ids: List[str]) -> bool: finding = finding_dal.get_finding(finding_id) vulnerabilities = get_by_ids(finding_id, vuln_ids) vulnerabilities = [ validate_requested_verification(vuln) for vuln in vulnerabilities ] vulnerabilities = [validate_closed(vuln) for vuln in vulnerabilities] if not vulnerabilities: raise VulnNotFound() comment_id = int(round(time() * 1000)) tzn = pytz.timezone(settings.TIME_ZONE) # type: ignore today = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S') historic_verification = cast(List[Dict[str, Union[str, int, List[str]]]], finding.get('historic_verification', [])) historic_verification.append({ 'date': today, 'user': user_email, 'status': 'REQUESTED', 'comment': comment_id, 'vulns': vuln_ids }) update_finding = finding_dal.update( finding_id, {'historic_verification': historic_verification}) comment_data = { 'comment_type': 'verification', 'content': justification, 'created': today, 'email': user_email, 'finding_id': int(finding_id), 'fullname': user_fullname, 'modified': today, 'parent': 0, } comment_dal.create(comment_id, comment_data) update_vulns = [ vuln_dal.request_verification(vuln) for vuln in vulnerabilities ] if all(update_vulns) and update_finding: finding_utils.send_remediation_email( user_email, finding_id, str(finding.get('finding', '')), str(finding.get('project_name', '')), justification) project_users = project_dal.get_users( str(finding.get('project_name', ''))) notifications.notify_mobile( project_users, t('notifications.remediated.title'), t('notifications.remediated.content', finding=finding.get('finding'), project=str(finding.get('project_name', '')).upper())) else: rollbar.report_message('Error: An error occurred remediating', 'error') return all(update_vulns)
def verify_vulnerabilities(finding_id: str, user_email: str, user_fullname: str, info, parameters: Dict[str, FindingType]) -> bool: finding = finding_dal.get_finding(finding_id) vuln_ids = \ cast(List[str], parameters.get('open_vulns', [])) + \ cast(List[str], parameters.get('closed_vulns', [])) vulnerabilities = get_by_ids(finding_id, vuln_ids) vulnerabilities = [validate_verify(vuln) for vuln in vulnerabilities] vulnerabilities = [validate_closed(vuln) for vuln in vulnerabilities] if not vulnerabilities: raise VulnNotFound() tzn = pytz.timezone(settings.TIME_ZONE) # type: ignore today = datetime.now(tz=tzn).today().strftime('%Y-%m-%d %H:%M:%S') comment_id = int(round(time() * 1000)) historic_verification = cast(List[Dict[str, Union[str, int, List[str]]]], finding.get('historic_verification', [])) historic_verification.append({ 'date': today, 'user': user_email, 'status': 'VERIFIED', 'comment': comment_id, 'vulns': vuln_ids }) update_finding = finding_dal.update( finding_id, {'historic_verification': historic_verification}) comment_data: comment_dal.CommentType = { 'comment_type': 'verification', 'content': parameters.get('justification', ''), 'created': today, 'email': user_email, 'finding_id': int(finding_id), 'fullname': user_fullname, 'modified': today, 'parent': 0, } comment_dal.create(comment_id, comment_data) success = [vuln_dal.verify_vulnerability(vuln) for vuln in vulnerabilities] if all(success) and update_finding: success = verify(info, finding_id, cast(List[Dict[str, str]], vulnerabilities), cast(List[str], parameters.get('closed_vulns', [])), today) else: rollbar.report_message('Error: An error occurred verifying', 'error') return all(success)
def test_format_vulnerabilities(self): act_finding = get_finding('422286126') positive_delta = 1 neutral_delta = 0 negative_delta = -1 test_data = format_vulnerabilities(positive_delta, act_finding) expected_output = 'FIN.S.0051. Weak passwords reversed (+1)' assert test_data == expected_output test_data = format_vulnerabilities(neutral_delta, act_finding) expected_output = '' assert test_data == expected_output test_data = format_vulnerabilities(negative_delta, act_finding) expected_output = 'FIN.S.0051. Weak passwords reversed (-1)' assert test_data == expected_output
def verify(info, finding_id: str, vulnerabilities: List[Dict[str, str]], closed_vulns: List[str], date) -> List[bool]: finding = finding_dal.get_finding(finding_id) success = [ update_vuln_state(info, [vuln], {'state': 'closed'}, finding_id, date) for vuln in vulnerabilities if vuln.get('UUID') in closed_vulns ] finding_utils.send_finding_verified_email( finding_id, str(finding.get('finding', '')), str(finding.get('project_name', ''))) project_users = project_dal.get_users(str(finding.get('project_name', ''))) notifications.notify_mobile( project_users, t('notifications.verified.title'), t('notifications.verified.content', finding=str(finding.get('finding', '')), project=str(finding.get('project_name', '')).upper())) return success
def mask_finding(finding_id: str) -> bool: finding = finding_dal.get_finding(finding_id) finding = finding_utils.format_data(finding) attrs_to_mask = [ 'affected_systems', 'attack_vector_desc', 'effect_solution', 'related_findings', 'risk', 'threat', 'treatment', 'treatment_manager', 'vulnerability' ] finding_result = finding_dal.update( finding_id, {attr: 'Masked' for attr in attrs_to_mask}) evidence_prefix = '{}/{}'.format(finding['projectName'], finding_id) evidence_result = all([ finding_dal.remove_evidence(file_name) for file_name in finding_dal.search_evidence(evidence_prefix) ]) finding_dal.update( finding_id, { 'files': [{ 'file_url': 'Masked', 'name': 'Masked', 'description': 'Masked' } for _ in cast(List[Dict[str, str]], finding['evidence'])] }) comments = comment_dal.get_comments('comment', int(finding_id)) comments_result = all([ comment_dal.delete(comment['finding_id'], comment['user_id']) for comment in comments ]) vulns_result = all([ vuln_domain.mask_vuln(finding_id, str(vuln['UUID'])) for vuln in vuln_domain.get_vulnerabilities(finding_id) ]) success = all( [finding_result, evidence_result, comments_result, vulns_result]) util.invalidate_cache(finding_id) return success
def update_treatments(vulnerabilities: List[str], finding_id: str, updated_values: Dict[str, FindingType], info, is_customer_admin: bool) -> bool: """Update treatments data in vulnerability""" user_data = util.get_jwt_content(info.context) finding = finding_dal.get_finding(finding_id) updated_values['treatment'] = cast( List[Dict[str, str]], finding.get('historic_treatment'))[-1]['treatment'] updated_values['treatment_manager'] = \ set_treatment_manager( str(updated_values.get('treatment', '')), str(updated_values.get('treatment_manager', '')), finding, is_customer_admin, user_data['user_email']) updated_values.pop('external_bts', None) updated_values.pop('vulnerabilities', None) if updated_values.get('tag') == '': updated_values.pop('tag', None) return update_treatment_vuln(vulnerabilities, finding_id, updated_values, info)
def test_validate_future_releases(self): finding_released = get_finding('475041513') assert not validate_future_releases(finding_released)
def test_validate_release_date(self): finding = get_finding('422286126') assert validate_release_date(finding)
def test_get_last_vuln(self): finding = get_finding('422286126') test_data = get_last_vuln(finding) expected_output = datetime(2018, 7, 9).date() assert test_data == expected_output