def test_send_analysis_by_file_sends_analysis_and_waits_specific_time_until_compilation( self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) analysis = FileAnalysis(file_path='a') wait = 1 with patch(self.patch_prop, mock_open(read_data='data')): # Act start = datetime.datetime.utcnow() analysis.send(wait=wait) duration = (datetime.datetime.utcnow() - start).total_seconds() # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.FINISH) self.assertGreater(duration, wait)
def test_send_analysis_by_file_with_disable_unpacking(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) analysis = FileAnalysis(file_path='a', disable_dynamic_unpacking=True, disable_static_unpacking=True) with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send(wait=True) # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.FINISH) self.assertEqual(analysis.result(), 'report') request_body = mock.calls[0].request.body.decode() self.assertTrue( 'Content-Disposition: form-data; name="disable_static_extraction"\r\n\r\nTrue' in request_body) self.assertTrue( 'Content-Disposition: form-data; name="disable_dynamic_execution"\r\n\r\nTrue' in request_body)
def test_send_analysis_by_sha256_with_expired_jwt_token_gets_new_token( self): # Arrange analysis = FileAnalysis(file_hash='a' * 64) # FileAnalysis attempt will initiate an access-token refresh by getting UNAUTHORIZED 401 with responses.RequestsMock() as mock: def request_callback(request): if request.headers[ 'Authorization'] == 'Bearer newer-access-token': return HTTPStatus.CREATED, {}, json.dumps( {'result_url': 'https://analyze.intezer.com/test-url'}) if request.headers['Authorization'] == 'Bearer access-token': return HTTPStatus.UNAUTHORIZED, {}, json.dumps({}) # Fail test completley is unexpected access token received return HTTPStatus.SERVICE_UNAVAILABLE, {}, json.dumps({}) mock.add_callback('POST', url=self.full_url + '/analyze-by-hash', callback=request_callback) mock.add('POST', url=self.full_url + '/get-access-token', status=HTTPStatus.OK, json={'result': 'newer-access-token'}) # Act & Assert analysis.send() self.assertEqual( 3, len(mock.calls )) # analyze -> refresh access_token -> analyze retry
def test_send_analysis_by_file_and_get_dynamic_ttps(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) mock.add('GET', url=self.full_url + '/analyses/asd/dynamic-ttps', status=200, json={'result': 'ttps_report'}) analysis = FileAnalysis(file_path='a') with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send(wait=True) ttps = analysis.dynamic_ttps # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.FINISH) self.assertEqual(ttps, 'ttps_report')
def test_send_analysis_by_file_sent_analysis_with_pulling_and_get_status_finish( self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=202) mock.add('GET', url=self.full_url + '/analyses/asd', status=202) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) analysis = FileAnalysis(file_path='a') with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send() analysis.check_status() analysis.check_status() analysis.check_status() # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.FINISH)
def test_analysis_by_sha256_raise_value_error_when_sha256_file_path_and_file_stream_given( self): # Assert with self.assertRaises(ValueError): FileAnalysis(file_hash='a', file_stream=__file__, file_path='/test/test')
def test_send_analysis_and_get_root_analyses(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze-by-hash', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd/sub-analyses', status=200, json={ 'sub_analyses': [{ 'source': 'root', 'sub_analysis_id': 'ab', 'sha256': 'axaxaxax' }, { 'source': 'static_extraction', 'sub_analysis_id': 'ac', 'sha256': 'ba' }] }) analysis = FileAnalysis(file_hash='a' * 64) # Act analysis.send() analysis.get_root_analysis() # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.CREATED) self.assertEqual(len(analysis.get_sub_analyses()), 1) self.assertIsNotNone(analysis.get_root_analysis())
def analyze_by_hash_command(intezer_api: IntezerApi, args: Dict[str, str]) -> CommandResults: file_hash = args.get('file_hash') if not file_hash: raise ValueError('Missing file hash') analysis = FileAnalysis(file_hash=file_hash, api=intezer_api) try: analysis.send(requester=REQUESTER) analysis_id = analysis.analysis_id context_json = { 'ID': analysis.analysis_id, 'Status': 'Created', 'type': 'File' } return CommandResults( outputs_prefix='Intezer.Analysis', outputs_key_field='ID', outputs=context_json, readable_output='Analysis created successfully: {}'.format( analysis_id)) except HashDoesNotExistError: return _get_missing_file_result(file_hash) except AnalysisIsAlreadyRunning as error: return _get_analysis_running_result(response=error.response)
def test_analysis_check_status_before_send_raise_error(self): # Arrange analysis = FileAnalysis(file_hash='a') # Act + Assert with self.assertRaises(errors.IntezerError): analysis.check_status()
def analyze_threat(threat_id: str, threat: dict = None): _logger.info(f'incoming threat: {threat_id}') try: if not threat: threat = get_threat(threat_id) if not filter_threat(threat): _logger.info(f'threat {threat_id} is been filtered') return threat_info = threat['threatInfo'] file_hash = threat_info.get('sha256') or threat_info.get('sha1') or threat_info.get('md5') analysis = None if file_hash: _logger.debug(f'trying to analyze by hash {file_hash}') try: analysis = FileAnalysis(file_hash=file_hash) analysis.send() except errors.HashDoesNotExistError: _logger.debug(f'hash {file_hash} not found on server, fetching the file from endpoint') analysis = None if not analysis: analysis = analyze_by_file(threat_id) analysis.send(requester='s1') _logger.debug('waiting for analysis completion') analysis.wait_for_completion() _logger.debug('analysis completed') send_note(threat_id, analysis) except Exception as ex: _logger.exception(f'failed to process threat {threat_id}') send_failure_note(str(ex), threat_id)
def test_send_analysis_by_file_with_zip_password_adds_zip_extension(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) analysis = FileAnalysis(file_path='a', zip_password='******') with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send(wait=True) # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.FINISH) self.assertEqual(analysis.result(), 'report') request_body = mock.calls[0].request.body.decode() self.assertTrue( 'Content-Disposition: form-data; name="zip_password"\r\n\r\nasd' in request_body) self.assertTrue( 'Content-Disposition: form-data; name="file"; filename="a.zip"' in request_body)
def test_get_dynamic_ttps_raises_when_on_premise_on_21_11(self): # Arrange analysis = FileAnalysis(file_path='a') analysis.status = consts.AnalysisStatusCode.FINISH get_global_api().on_premise_version = OnPremiseVersion.V21_11 # Act and Assert with self.assertRaises(errors.UnsupportedOnPremiseVersionError): _ = analysis.dynamic_ttps
def test_send_analysis_by_sha256_that_dont_exist_raise_error(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze-by-hash', status=404) analysis = FileAnalysis(file_hash='a' * 64) # Act + Assert with self.assertRaises(errors.HashDoesNotExistError): analysis.send()
def test_send_analysis_that_running_on_server_raise_error(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze-by-hash', status=409, json={'result_url': 'a/sd/asd'}) analysis = FileAnalysis(file_hash='a' * 64) # Act + Assert with self.assertRaises(errors.AnalysisIsAlreadyRunningError): analysis.send()
def test_send_analysis_by_sha256_sent_analysis_and_sets_status(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze-by-hash', status=201, json={'result_url': 'a/sd/asd'}) analysis = FileAnalysis(file_hash='a' * 64) # Act analysis.send() # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.CREATED)
def collect_suspicious_and_malicious_analyses() -> list: malicious_and_suspicious_analyses_results = [] file_paths = [file for file in os.listdir(DIRECTORY_PATH)] analyses = [ FileAnalysis(os.path.join(DIRECTORY_PATH, path)) for path in file_paths if os.path.isfile(os.path.join(DIRECTORY_PATH, path)) ] for analysis in analyses: analysis_result = send_analysis(analysis) if analysis_result['verdict'] == 'suspicious' or analysis_result[ 'verdict'] == 'malicious': malicious_and_suspicious_analyses_results.append(analysis_result) return malicious_and_suspicious_analyses_results
def test_send_analysis_by_file_with_file_stream_sent_analysis(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) analysis = FileAnalysis(file_stream=__file__) # Act analysis.send() # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.CREATED)
def test_send_analysis_by_file_sent_analysis_and_sets_status(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) analysis = FileAnalysis(file_path='a') with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send() # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.CREATED)
def test_send_analysis_by_sha256_with_expired_jwt_token_doesnt_loop_indefinitley( self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze-by-hash', status=HTTPStatus.UNAUTHORIZED) mock.add('POST', url=self.full_url + '/get-access-token', status=HTTPStatus.OK, json={'result': 'newer-access-token'}) analysis = FileAnalysis(file_hash='a' * 64) # Act & Assert with self.assertRaises(errors.IntezerError): analysis.send() # analyze -> get_access token -> analyze -> 401Exception self.assertEqual(3, len(mock.calls))
def test_send_analysis_by_file_and_get_dynamic_ttps_handle_no_ttps(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) mock.add('GET', url=self.full_url + '/analyses/asd/dynamic-ttps', status=404) analysis = FileAnalysis(file_path='a') with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send(wait=True) self.assertIsNone(analysis.dynamic_ttps)
def test_analysis_check_status_after_analysis_finish_raise_error(self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) analysis = FileAnalysis(file_path='a') with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send(wait=True) # Assert with self.assertRaises(errors.IntezerError): analysis.check_status()
def analyze_by_uploaded_file_command(intezer_api: IntezerApi, args: dict) -> CommandResults: file_id = args.get('file_entry_id') file_data = demisto.getFilePath(file_id) try: analysis = FileAnalysis(file_path=file_data['path'], api=intezer_api) analysis.send(requester=REQUESTER) context_json = { 'ID': analysis.analysis_id, 'Status': 'Created', 'type': 'File' } return CommandResults( outputs_prefix='Intezer.Analysis', outputs_key_field='ID', outputs=context_json, readable_output='Analysis created successfully: {}'.format( analysis.analysis_id)) except AnalysisIsAlreadyRunning as error: return _get_analysis_running_result(response=error.response)
def test_send_analysis_by_file_sends_analysis_with_waits_to_compilation_when_requested( self): # Arrange with responses.RequestsMock() as mock: mock.add('POST', url=self.full_url + '/analyze', status=201, json={'result_url': 'a/sd/asd'}) mock.add('GET', url=self.full_url + '/analyses/asd', status=200, json={ 'result': 'report', 'status': 'succeeded' }) analysis = FileAnalysis(file_path='a') with patch(self.patch_prop, mock_open(read_data='data')): # Act analysis.send(wait=True) # Assert self.assertEqual(analysis.status, consts.AnalysisStatusCode.FINISH)
def analyze_by_file(threat_id: str): download_url, zipp_password = fetch_file(threat_id) file = download_file(download_url) _logger.debug('starting to analyze file') analysis = FileAnalysis(file_stream=file, file_name=f'{threat_id}.zip', zip_password=zipp_password) return analysis
def test_analysis_get_report_for_not_finish_analyze_raise_error(self): # Arrange analysis = FileAnalysis(file_hash='a') # Act + Assert with self.assertRaises(errors.ReportDoesNotExistError): analysis.result()
def test_analysis_by_sha256_and_file_sent_analysis_and_raise_value_error( self): # Assert with self.assertRaises(ValueError): FileAnalysis(file_hash='a', file_path='/test/test')
def test_analysis_raise_value_error_when_no_file_option_given(self): # Assert with self.assertRaises(ValueError): FileAnalysis()
def send_file_without_wait(file_path): api.set_global_api('<api_key>') analysis = FileAnalysis(file_path=file_path) analysis.send() analysis.wait_for_completion() pprint(analysis.result())
def send_file_with_wait(file_path): api.set_global_api('<api_key>') analysis = FileAnalysis(file_path=file_path) analysis.send(wait=True) pprint(analysis.result())
def test_analysis_by_file_wrong_code_item_type(self): # Act + Assert with self.assertRaises(ValueError): FileAnalysis(file_path='a', code_item_type='anderson_paak')