def report_ope(ope, scan_id, file_id): # インスタンス初期化 client = TenableIOClient() # 一時レポートCSVファイル名 todaynow = datetime.today().strftime('%Y%m%d%H%M%S') tenable_csv_folder = 'csv_report/' tenable_csv_file = tenable_csv_folder + str(todaynow) + '_scanid_' + str(scan_id) + '.csv' # ローカル環境適用 #if os.path.isdir(tenable_csv_folder): # pass #else: # os.makedirs(tenable_csv_folder) if ope == 'status': request_uri = 'scans/' + str(scan_id) + '/export/' + str(file_id) + '/status' resp = client.get(request_uri, path_params={'scan_id':scan_id, 'file_id':file_id}) obj_msg = json.loads(resp.text) str_msg = obj_msg.get('status') return render_template('index.html', message=str_msg) elif ope == 'download': request_uri = 'scans/' + str(scan_id) + '/export/' + str(file_id) + '/download' resp = client.get(request_uri, path_params={'scan_id':scan_id, 'file_id':file_id}, stream=True) # ローカル環境適用 #iter_content = resp.iter_content(chunk_size=1024) #with open(tenable_csv_file, mode='wb') as fd: # for ck in iter_content: # fd.write(ck) #str_msg = u'https://tenable-io.herokuapp.com/' + tenable_csv_file #return render_template('index.html', message=str_msg) # AWS S3に保存する s3 = S3Api() response = s3.response(tenable_csv_file, resp.text) return response #return render_template('index.html', message=resp.text) else: return render_template('index.html', message=u"REPORT_OPE|不正アクセスを記録しました。")
def s3_api(scan_id, file_id): # インスタンス初期化 client = TenableIOClient() request_uri = 'scans/' + str(scan_id) + '/export/' + str(file_id) + '/download' resp = client.get(request_uri, path_params={'scan_id':scan_id, 'file_id':file_id}, stream=True) s3 = S3Api() response = s3.response('20170213_tenable.csv', resp.text) return response
def downloadVulnsFromTio(filename, cust): DEBUG = True #Open the connection to Tio for the particular customer print("Connecting to Tenable.io for:", cust['name']) try: tioconn = TenableIOClient(access_key=cust['_id'], secret_key=cust['secretkey']) except: print("Problem connecting to Tenable.io") return (False) #Download a CSV file # Make the request for the file. requesturl = "workbenches/export?format=csv&report=vulnerabilities&chapter=vuln_by_plugin&date_range=0" resp = tioconn.get(requesturl) if DEBUG: print("Raw response text:", resp.text) respdata = json.loads(resp.text) downloadid = "" try: downloadid = str(respdata['file']) except: print("Unable to start download") return (False) statusurl = "workbenches/export/" + downloadid + "/status" downloadurl = "workbenches/export/" + downloadid + "/download" if DEBUG: print("Waiting for download ID", downloadid) print("status URL :", statusurl) downloadstatus = "" while (downloadstatus != "ready"): resp = tioconn.get(statusurl) respdata = json.loads(resp.text) downloadstatus = respdata['status'] if DEBUG: print("Raw response", resp.text) time.sleep(2) resp = tioconn.get(downloadurl) if DEBUG: print("Raw response", resp) with open(filename, 'wb') as fp: for chunk in resp.text: fp.write(chunk.encode('utf-8')) fp.close() sys.stdout.flush() return (True)
def report_request(scan_id): if scan_id: # インスタンス初期化 client = TenableIOClient() # レポートRAWデータをCSV形式で出力する要求をする request_uri = 'scans/' + str(scan_id) + '/export' resp = client.post(request_uri, ScanExportRequest(format=u'csv'), path_params={'scan_id':scan_id}) if resp.status_code == 200: obj_msg = json.loads(resp.text) str_msg = str(obj_msg.get('file')) + u'|レポート要求が正常に受信できました。' return render_template('index.html', message=str_msg) else: return render_template('index.html', message=u"REPORT_REQUEST_ERROR|レポート要求時エラーが発生しています。") else: return render_template('index.html', message=u"REPORT_REQUEST|不正アクセスを記録しました。")
def perform_nessus_scan(target, outpath): logger.info("[+] Attempting to run Nessus scan on the target...") domain = urlparse(target[0]).netloc # Reference file: https://github.com/tenable/Tenable.io-SDK-for-Python/blob/master/examples/scans.py try: # According to documentation TenableIO client can be initialised # in a number of ways. I choose here the environment variable option. # On the same tty, the user needs to set TENABLEIO_ACCESS_KEY and # TENABLEIO_SECRET_KEY variables. I prefer this over storing keys # in a config file on disk. client = TenableIOClient() # Run a basic network scan nessus_scan = client.scan_helper.create(name='Scan_for_ ' + target[0], text_targets=target[0], template='basic') # Let's allow up to 45 minutes for the scan to run and finish nessus_scan.launch().wait_or_cancel_after(45) # Downloading the results in .nessus format # We will likely need to post this to somewhere else too nessus_scan.download(os.path.join(outpath, domain + '.nessus'), nessus_scan.histories()[0].history_id, format=ScanExportRequest.FORMAT_NESSUS) except TenableIOApiException as TIOException: logger.warning("[!] Nessus scan could not run. Make sure you have " "provided API keys to communicate with Tenable.io.") return False return True
def scan(self, hostname): # If not passed at the time of object instantiation if not self.tio_access_key or not self.tio_secret_key: try: # See if we can load the API keys from SSM self.tio_access_key, self.tio_secret_key = self.__getAPIKey() except Exception: self.logger.error( "Cannot obtain Tenable.io API key(s), skipping Tenable.io scan" ) return False # Here, we have the keys, either from SSM or from instantiation self.client = TenableIOClient(access_key=self.tio_access_key, secret_key=self.tio_secret_key) # Reference: https://github.com/tenable/Tenable.io-SDK-for-Python/blob/master/examples/scans.py try: # Run a basic network scan on the target scan_name = "VA for " + hostname nscan = self.client.scan_helper.create(name=scan_name, text_targets=hostname, template='basic') return nscan except Exception as TIOException: self.logger.error( "Tenable.io scan failed: {}".format(TIOException)) return False
def test_nessus(): req_data = request.get_json() testUrl = req_data['url'] scanName = req_data['name'] device_token = req_data['reg_token'] hashToken = hashlib.md5(device_token).hexdigest() testIp = gethostbyname(testUrl) reportName = scanName + ".pdf" reportName = hashToken + '_' + reportName path_report = "/home/tejas/Desktop/website/" + reportName client = TenableIOClient( access_key= '135b739644f7f56f6e39fa6f45d00ccdc199fb15793ddf324a7ad0e4526e1b95', secret_key= 'ff6d61f566c11479154f68dc8f0a6ebf35aa961d65329a01a41349638face336') scan = client.scan_helper.create(name=scanName, text_targets=testIp, template='basic') scan.launch().download(path_report, scan.histories()[0].history_id) #path_from_pdf="/home/ubuntu/website/"+reportName path_to_pdf = "/home/tejas/Desktop/website/static/reports/nessus/" + reportName subprocess.call(["mv", path_report, path_to_pdf]) push_service = FCMNotification( api_key="AIzaSyB4BBdlKyxQaB9ZBL1U4ynZz3nDNW9vsmo") data = { "title": "Nessus Report", "message": "Your report " + req_data['name'] + " for Nessus has been generated" } #message_title = "Nessus Report" #message_body = "Your report has been generated" result = push_service.notify_single_device(registration_id=device_token, data_message=data) return jsonify(reportGenerated=True)
def example(test_file): # Generate unique name and file. test_vulns_json_file = test_file(u'example_export_vulns_%(chunk_id)s.json') test_assets_json_file = test_file( u'example_export_assets_%(chunk_id)s.json') ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Export and download vulnerabilities. Note: The file name can be optionally parameterized with "%(chunk_id)s" to allow multiple chunks. Otherwise the chunk ID will be append to the file name. ''' chunks_available = client.export_helper.download_vulns( test_vulns_json_file) for chunk_id in chunks_available: chunk_file = test_vulns_json_file % {'chunk_id': chunk_id} assert os.path.isfile(chunk_file) os.remove(chunk_file) ''' Export and download assets. Note: The file name can be optionally parameterized with "%(chunk_id)s" to allow multiple chunks. Otherwise the chunk ID will be append to the file name. ''' chunks_available = client.export_helper.download_assets( test_assets_json_file, chunk_size=100) for chunk_id in chunks_available: chunk_file = test_assets_json_file % {'chunk_id': chunk_id} assert os.path.isfile(chunk_file) os.remove(chunk_file)
def example(): test_asset_file = u'asset.nessus' test_vulnerability_file = u'vulnerability.nessus' date_range = 7 ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Get recent assets in the past 7 days. Note: assets returns an iterator. An iterator that return pages of assets. ''' assets_iter = client.workbench_helper.assets(date_range) assets = [a for page in assets_iter for a in page] ''' Get recent vulnerabilities in the past 7 days. Note: vulnerabilities returns an iterator. An iterator that return pages of vulnerabilities. ''' vulnerabilities_iter = client.workbench_helper.vulnerabilities(date_range) vulnerabilities = [v for page in vulnerabilities_iter for v in page] if len(vulnerabilities) < 1: return ''' Get recent assets found for a plugin. ''' plugin_id = vulnerabilities[0].plugin_id vulnerability_assets_iter = client.workbench_helper.assets(date_range, plugin_id=plugin_id) vulnerability_assets = [a for page in vulnerability_assets_iter for a in page] assert len(vulnerability_assets) > 0 assert plugin_id in [v.plugin_id for v in vulnerability_assets[0].vulnerabilities] ''' Get recent vulnerabilities found for an asset. ''' asset_id = vulnerability_assets[0].asset.host_uuid asset_vulnerabilities_iter = client.workbench_helper.vulnerabilities(date_range, asset_id=asset_id) asset_vulnerabilities = [v for page in asset_vulnerabilities_iter for v in page] assert len(asset_vulnerabilities) > 0 assert plugin_id in [v.plugin_id for v in asset_vulnerabilities] ''' Export reports for a given asset or vulnerability. ''' client.workbench_helper.export(test_asset_file, asset_id=assets[0].asset.host_uuid) client.workbench_helper.export(test_vulnerability_file, plugin_id=vulnerabilities[0].plugin_id) assert os.path.isfile(test_asset_file) assert os.path.isfile(test_vulnerability_file) os.remove(test_asset_file) os.remove(test_vulnerability_file)
def test_client_retries(self): mock_error = Mock(side_effect=TenableIORetryableApiException(Mock())) retry_mock_error = TenableIOClient._retry(mock_error) retry_header = {u'X-Tio-Retry-Count': '3'} with pytest.raises(TenableIOApiException): retry_mock_error() assert mock_error.call_count == int(TenableIOClient._TOTAL_RETRIES) + 1, \ u'Invalid retry count: ' + str(mock_error.call_count) mock_error.assert_called_with(headers=retry_header)
def example(test_name, test_file): # Generate unique file. policy_name = test_name(u'my test policy') test_file_output = test_file(u'my_exported_policy.tenable_io') ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Create a policy. ''' policy = client.policy_helper.create(name=policy_name, template='discovery') assert policy.name() == policy_name ''' Export a policy into a NESSUS file. ''' policy.download(test_file_output) assert os.path.isfile(test_file_output) ''' Import a policy from a NESSUS file and get the detail. ''' imported_policy = client.policy_helper.import_policy(test_file_output) assert imported_policy.details().uuid == policy.details().uuid os.remove(test_file_output) ''' Create a new policy by copying a policy. ''' policy_copy = policy.copy() assert policy_copy.id != policy.id ''' Delete policies. ''' policy.delete() imported_policy.delete() policy_copy.delete() try: policy.details() assert False except TenableIOApiException: pass try: imported_policy.details() assert False except TenableIOApiException: pass try: policy_copy.details() assert False except TenableIOApiException: pass
def GenerateAssetCSV(accesskey, secretkey, filename): #Create the connection to Tenable.io client = TenableIOClient(access_key=accesskey, secret_key=secretkey) #Gather the list of assets resp = client.get("assets") respdata = json.loads(resp.text) #Open the file that will become a CSV with open(filename, "w") as csvfile: #Create the header of the CSV file fieldnames = [ 'id', 'has_agent', 'last_seen', 'sources', 'ipv4', 'ipv6', 'fqdn', 'netbios_name', 'operating_system' ] #Create a CSV writer and associate with the file handle writer = csv.DictWriter(csvfile, fieldnames=fieldnames) #Write the CSV headers writer.writeheader() #Loop through all the downloaded assets and write them into the CSV file for i in respdata['assets']: rowdict = { 'id': i['id'], 'has_agent': i['has_agent'], 'last_seen': i['last_seen'], 'sources': i['sources'], 'ipv4': i['ipv4'], 'ipv6': i['ipv6'], 'fqdn': i['fqdn'], 'netbios_name': i['netbios_name'], 'operating_system': i['operating_system'] } writer.writerow(rowdict) #Close the file csvfile.close() return (True)
def test_s3(scan_id, file_id): # インスタンス初期化 client = TenableIOClient() request_uri = 'scans/' + str(scan_id) + '/export/' + str(file_id) + '/download' resp = client.get(request_uri, path_params={'scan_id':scan_id, 'file_id':file_id}, stream=True) #iter_content = resp.iter_content() S3_BUCKET = os.environ.get('S3_BUCKET') s3 = boto3.resource('s3') bucket = s3.Bucket(S3_BUCKET) PUT_OBJECT_KEY_NAME = '20170212_test.csv' obj = bucket.Object(PUT_OBJECT_KEY_NAME) response = obj.put( Body=resp.text, ContentEncoding='utf-8', ContentType='text/csv' ) return jsonify(response)
def test_client_retries(self): # Function that throws TenableIORetryableException mock_response = mock.Mock() foo = mock.Mock( side_effect=TenableIORetryableApiException(mock_response)) # Function decoration retried_foo = TenableIOClient._retry(foo) with pytest.raises(TenableIOApiException): retried_foo() assert foo.call_count == 4, u'Should be tried 4 times (retried 3 times).'
def test_tenable_auth_success(self): # See if the keys are available as env variables try: a_key = os.environ["TIOA"] s_key = os.environ["TIOS"] except Exception: assert False # See if we can use those keys to successfully # authenticate to Tenable.io, should be True try: TenableIOClient(a_key, s_key).session_api.get() assert True except TenableIOApiException as e: assert e.code is TenableIOErrorCode.UNAUTHORIZED
def example(test_file): # Generate a file with an unique name. upload_file = test_file(u'example_upload', u'example content') ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Upload a file (usually used along with another API resource method that requires a file). ''' uploaded_file_name = client.file_helper.upload(upload_file) assert uploaded_file_name os.remove(upload_file)
def example(test_domain): test_user_name = u'example_test_user_{}'.format(random.randint(1, 100)) test_user_username = u'{}@{}'.format(test_user_name, test_domain) ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Create a new Standard User ''' user_create_request = UserCreateRequest( username=test_user_username, password='******'.format(random.randint(1, 100)), permissions=Permissions.User.PERMISSION_STANDARD, name=test_user_name, email=test_user_username, type=User.LOCAL) std_user_id = client.users_api.create(user_create_request) assert std_user_id ''' Fetch user details ''' std_user = client.users_api.details(std_user_id) assert isinstance(std_user, User) assert std_user.permissions == Permissions.User.PERMISSION_STANDARD ''' Check that new user is included in user list ''' user_list = client.users_api.list() assert any([u.id for u in user_list.users if u.id == std_user_id]) ''' Edit user ''' user_edit_request = UserEditRequest( permissions=Permissions.User.PERMISSION_SCAN_MANAGER) edited_std_user = client.users_api.edit(std_user_id, user_edit_request) assert isinstance(edited_std_user, User) assert edited_std_user.permissions == Permissions.User.PERMISSION_SCAN_MANAGER ''' Delete user ''' assert client.users_api.delete(std_user_id) ''' Check that deleted user is not included in user list ''' user_list = client.users_api.list() assert not any([u.id for u in user_list.users if u.id == std_user_id])
def __createClient(self): # If not passed at the time of object instantiation if not self.tio_access_key or not self.tio_secret_key: try: # See if we can load the API keys from SSM self.tio_access_key, self.tio_secret_key = self.__getAPIKey() except Exception: self.logger.error( "Cannot obtain Tenable.io API key(s), skipping Tenable.io scan." ) return False # Here, we have the keys, either from SSM or from instantiation client = TenableIOClient(access_key=self.tio_access_key, secret_key=self.tio_secret_key) return client
def host_reg(hostname, template): if len(hostname) != 0: # インスタンス初期化 client = TenableIOClient() # 新規診断対象を登録する scan = client.scan_helper.create( name=hostname, text_targets=hostname, template=template ) # assert scan.name() = scan_name msg = str(scan.id) + "|" + scan.name() + u"が正常に登録できました。" return render_template('index.html', message=msg) else: return render_template('index.html', message=u"HOST_REG|不正アクセスを記録しました。")
def example(test_file): # Generate unique name and file. test_vulns_json_file = test_file(u'example_export_vulns_%(chunk_id)s.json') test_assets_json_file = test_file(u'example_export_assets_%(chunk_id)s.json') ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Export and load vulnerabilities to memory. ''' vuln_list = client.export_helper.download_vulns() for vuln in vuln_list: assert isinstance(vuln, VulnsExport) ''' Export and download vulnerabilities to disk. Note: The file name can be optionally parameterized with "%(chunk_id)s" to allow multiple chunks. Otherwise the chunk ID will be append to the file name. ''' chunks_available = client.export_helper.download_vulns(path=test_vulns_json_file) for chunk_id in chunks_available: chunk_file = test_vulns_json_file % {'chunk_id': chunk_id} assert os.path.isfile(chunk_file) os.remove(chunk_file) ''' Export and load assets to memory. ''' asset_list = client.export_helper.download_assets() for asset in asset_list: assert isinstance(asset, AssetsExport) ''' Export and download assets to disk. Note: The file name can be optionally parameterized with "%(chunk_id)s" to allow multiple chunks. Otherwise the chunk ID will be append to the file name. ''' chunks_available = client.export_helper.download_assets(path=test_assets_json_file) for chunk_id in chunks_available: chunk_file = test_assets_json_file % {'chunk_id': chunk_id} assert os.path.isfile(chunk_file) os.remove(chunk_file)
def scan_ope(ope, id): if ope == 'status': # インスタンス初期化 client = TenableIOClient() # 診断対象のID或は登録名が入力画面もしくは入力パラメータから渡される # 診断IDより診断対象取得 scan_b = client.scan_helper.id(id) return render_template('index.html', message=str(scan_b.status())) elif ope == 'launch': # インスタンス初期化 client = TenableIOClient() # 診断対象のID或は登録名が入力画面もしくは入力パラメータから渡される # 診断IDより診断対象取得 scan_b = client.scan_helper.id(id) scan_b.launch(id) return render_template('index.html', message=str(scan_b.status())) elif ope == 'pause': # インスタンス初期化 client = TenableIOClient() # 診断対象のID或は登録名が入力画面もしくは入力パラメータから渡される client.scans_api.pause(id) # 診断IDより診断対象取得 scan_b = client.scan_helper.id(id) return render_template('index.html', message=str(scan_b.status())) elif ope == 'stop': # インスタンス初期化 client = TenableIOClient() # 診断対象のID或は登録名が入力画面もしくは入力パラメータから渡される client.scans_api.stop(id) # 診断IDより診断対象取得 scan_b = client.scan_helper.id(id) return render_template('index.html', message=str(scan_b.status())) elif ope == 'resume': # インスタンス初期化 client = TenableIOClient() # 診断対象のID或は登録名が入力画面もしくは入力パラメータから渡される client.scans_api.resume(id) # 診断IDより診断対象取得 scan_b = client.scan_helper.id(id) return render_template('index.html', message=str(scan_b.status())) elif ope == 'delete': # インスタンス初期化 client = TenableIOClient() # 診断対象のID或は登録名が入力画面もしくは入力パラメータから渡される resp = client.scans_api.delete(id) # 削除結果を確認する if resp is True: return render_template('index.html', message=u"診断対象を正しく削除できました。") else: return render_template('index.html', message=u"診断対象を削除できませんでした。") else: return render_template('index.html', message=u"SCAN_OPE|不正アクセスを記録しました。")
def runNessusScan(self): # First, check to see if we are provided with API keys if self.tio_access_key == "" or self.tio_secret_key == "": logger.warning("[!] Tenable.io API key(s) not provided, skipping " "Tenable.io scan. Perform the scan manually.") return False else: self.client = TenableIOClient(access_key=self.tio_access_key, secret_key=self.tio_secret_key) # Reference: https://github.com/tenable/Tenable.io-SDK-for-Python/blob/master/examples/scans.py # Note no subprocess call is required here try: # Run a basic network scan on the target # Need to check if a recent scan was fired recently scan_name = "VA for " + self.tasktarget.targetdomain # We will check with both host IP and FQDN activities = self.client.scan_helper.activities( targets=self.tasktarget.targetdomain, date_range=15) if len(activities) > 0: logger.warning( "[!] The target has recently been scanned by Tenable.io, retrieving results..." ) old_nscans = self.client.scan_helper.scans(name=scan_name) for old in old_nscans: if old.status() == Scan.STATUS_COMPLETED: self.downloadReport(old) break return old else: # This target was not scanned before, scan it # We don't want this blocking, so don't wait new_nscan = self.client.scan_helper.create( name=scan_name, text_targets=self.tasktarget.targetdomain, template="basic") new_nscan.launch(wait=False) return new_nscan except TenableIOApiException as TIOException: logger.error("[-] Tenable.io scan failed: ".format(TIOException)) return False
def example(): date_range = 7 ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Get recent assets in the past 7 days. Note: assets returns an iterator. An iterator that return pages of assets. ''' assets_iter = client.workbench_helper.assets(date_range) assets = [a for page in assets_iter for a in page] ''' Get recent vulnerabilities in the past 7 days. Note: vulnerabilities returns an iterator. An iterator that return pages of vulnerabilities. ''' vulnerabilities_iter = client.workbench_helper.vulnerabilities(date_range) vulnerabilities = [v for page in vulnerabilities_iter for v in page] if len(vulnerabilities) > 0: ''' Get recent assets found for a plugin. ''' plugin_id = vulnerabilities[0].plugin_id vulnerability_assets_iter = client.workbench_helper.assets(date_range, plugin_id=plugin_id) vulnerability_assets = [a for page in vulnerability_assets_iter for a in page] assert len(vulnerability_assets) > 0 assert plugin_id in [v.plugin_id for v in vulnerability_assets[0].vulnerabilities] ''' Get recent vulnerabilities found for an asset. ''' asset_id = vulnerability_assets[0].asset.host_uuid asset_vulnerabilities_iter = client.workbench_helper.vulnerabilities(date_range, asset_id=asset_id) asset_vulnerabilities = [v for page in asset_vulnerabilities_iter for v in page] assert len(asset_vulnerabilities) > 0 assert plugin_id in [v.plugin_id for v in asset_vulnerabilities]
def test_nessus(): req_data = request.get_json() testUrl = req_data['url'] scanName = req_data['name'] testIp = gethostbyname(testUrl) reportName = scanName + ".pdf" client = TenableIOClient( access_key= '135b739644f7f56f6e39fa6f45d00ccdc199fb15793ddf324a7ad0e4526e1b95', secret_key= 'ff6d61f566c11479154f68dc8f0a6ebf35aa961d65329a01a41349638face336') scan = client.scan_helper.create(name=scanName, text_targets=testIp, template='basic') scan.launch().download(reportName, scan.histories()[0].history_id) path_from_pdf = "/home/ubuntu/website/" + reportName path_to_pdf = "/home/ubuntu/website/reports/nessus/" + reportName subprocess.call(["mv", path_from_pdf, path_to_pdf]) return 'Your report has been generated'
def test_client_throwing_retryable_exception(self): responses = [ [{ 'status_code': 200 }, False], [{ 'status_code': 429 }, True], [{ 'status_code': 501 }, True], [{ 'status_code': 502 }, True], [{ 'status_code': 503 }, True], [{ 'status_code': 504 }, True], ] # Function that returns Responses with above status codes. foo = mock.Mock( side_effect=[mock.Mock(**response[0]) for response in responses]) # Method decoration foo = TenableIOClient._error_handler(foo) for (response, retry) in responses: if retry: with pytest.raises(TenableIORetryableApiException): foo() else: try: foo() except TenableIORetryableApiException: assert False, u'Response %s should not be retry-able.' % response
def test_client_bad_keys(self): try: TenableIOClient('bad', 'key').session_api.get() assert False, u'TenableIOApiException should be raised for bad api and secret keys.' except TenableIOApiException as e: assert e.code is TenableIOErrorCode.UNAUTHORIZED, u'Appropriate exception is raised.'
def main(): options, parser = get_config() # logger = configure_logging(options.log_file_name) logging.config.fileConfig('log.ini') logger = logging.getLogger() logger.info('Started') # Log where each of our values has come from (command line, environment, # config file, default) logger.debug(get_redacted_parser_values(parser)) client = TenableIOClient(access_key=options.tio_access_key, secret_key=options.tio_secret_key) ''' Export and download vulnerabilities. Note: The file name can be optionally parameterized with "%(chunk_id)s" to allow multiple chunks. Otherwise the chunk ID will be append to the file name. ''' file_name = os.path.join(options.temp_file_dir, options.temp_file_name) # The tenable_io library looks for the chunk_id paramater and adds it if # if we do that here instead it will be consistent when we try to open the # files nexy # create a version of the filename that matches the tenable_io library if file_name % {'chunk_id': 1} == file_name: file_name += '_%(chunk_id)s' logger.info( 'About to export vulnerabilities from tenable.io (this may take a few moments)...' ) try: # Use one of the tenbale_io library helper functions to start the # export and download each of the result files chunks_available = client.export_helper.download_vulns( path=file_name, state=options.vuln_state, severity=options.vuln_severity) except Exception: logger.error('Failed to download vulnerability data', exc_info=True) return logger.info('completed vulnerabilities export from tenable.io') df = '' for chunk_id in chunks_available: logger.info('Loading chunk number {0}'.format(chunk_id)) # using old style string formatting because that's what the tenable_io # library expects chunk_file = file_name % {'chunk_id': chunk_id} assert (os.path.isfile(chunk_file)) logger.info('Loading data file {0}'.format(chunk_file)) with open(chunk_file) as data_file: if (df == ''): df = json_normalize(json.load(data_file)) else: df.append(json_normalize(json.load(data_file))) if (options.keep_temp_files == False): os.remove(chunk_file) # replace lists of CVE with strings in semi-colon delimited format # requested by the spec df = df.applymap(collapse_list) if options.csv_replace_newline_character is not None: #df = df.replace('\n',options.csv_replace_newline_character, regex=True) df = df.replace('(\n|\r|\r\n)', options.csv_replace_newline_character, regex=True) if options.csv_header_row == True: if options.csv_column_names is None: header = True else: header = options.csv_column_names else: header = False df.to_csv(os.path.abspath(options.output_file_name), columns=options.csv_columns, header=header, index=False, line_terminator=options.csv_newline_character, quotechar=options.csv_quote_char, sep=options.csv_delimiter, quoting=csv.QUOTE_ALL if options.csv_quote_everything == True else csv.QUOTE_MINIMAL, na_rep=options.csv_null_value) logger.info('Exported {0} vulnerabilities to {1}'.format( len(df), os.path.abspath(options.output_file_name))) logger.info('Finished')
def example(test_name, test_file, test_targets): # Generate unique name and file. scan_name = test_name(u'example scan') test_nessus_file = test_file(u'example_report.nessus') test_pdf_file = test_file(u'example_report.pdf') ''' Instantiate an instance of the TenableIOClient. ''' client = TenableIOClient() ''' Create a scan. ''' scan = client.scan_helper.create(name=scan_name, text_targets=test_targets, template='basic') assert scan.name() == scan_name ''' Retrieve a scan by ID. ''' scan_b = client.scan_helper.id(scan.id) assert scan_b is not scan assert scan_b.name() == scan_name ''' Select scans by name. ''' scans = client.scan_helper.scans(name=scan_name) assert scans[0].name() == scan_name ''' Select scans by name with regular expression. ''' scans = client.scan_helper.scans(name_regex=r'.*example scan.*') assert len(scans) > 0 ''' Launch a scan, then download when scan is completed. Note: The `download` method blocks until the scan is completed and the report is downloaded. ''' scan.launch().download(test_pdf_file) assert os.path.isfile(test_pdf_file) os.remove(test_pdf_file) ''' Launch a scan, pause it, resume it, then stop it. ''' scan.launch().pause() assert scan.status() == Scan.STATUS_PAUSED scan.resume().stop() assert scan.status() == Scan.STATUS_CANCELED ''' Stop a running scan if it does not complete within a specific duration. ''' start = time() scan.launch().wait_or_cancel_after(10) assert time() - start >= 10 ''' Retrieve the history of a scan since a specific date or all. Note: The `since` argument is optional, all the history if omitted. ''' histories = scan.histories(since=datetime(2016, 12, 1)) assert len(histories) > 0 ''' Download the report for a specific scan in history. ''' scan.download(test_pdf_file, history_id=histories[0].history_id) assert os.path.isfile(test_pdf_file) os.remove(test_pdf_file) ''' Create a new scan by copying a scan. ''' scan_copy = scan.copy() assert scan_copy.id != scan.id assert scan_copy.status() == Scan.STATUS_EMPTY ''' Export a scan into a NESSUS file. ''' scan.download(test_nessus_file, format=ScanExportRequest.FORMAT_NESSUS) assert os.path.isfile(test_nessus_file) ''' Create a new scan by importing a NESSUS file. ''' imported_scan = client.scan_helper.import_scan(test_nessus_file) assert imported_scan.details().info.name == scan.details().info.name os.remove(test_nessus_file) ''' Stop all scans. Note: Use with caution as this will stop all ongoing scans (including any automated test). ''' # client.scan_helper.stop_all() ''' Check if a target has recently been scanned (including running scans). ''' activities = client.scan_helper.activities(test_targets) last_history_id = scan.last_history().history_id assert [a for a in activities if last_history_id == a.history_id] ''' Delete scans. ''' scan.delete() scan_copy.delete() imported_scan.delete() try: scan.details() assert False except TenableIOApiException: pass try: scan_copy.details() assert False except TenableIOApiException: pass try: imported_scan.details() assert False except TenableIOApiException: pass
def test_tenable_auth_fail(self): try: TenableIOClient('test', 'test').session_api.get() assert False except TenableIOApiException as e: assert e.code is TenableIOErrorCode.UNAUTHORIZED
def main(): """ Main func for automatic vulnerability scan by Tenable.io of Company GCP and Cloudflare resources :return: none """ parser = argparse.ArgumentParser(description='Provide all arguments for successful Vulnerability scan') parser.add_argument("-all", dest="tg_all", action="store_true", help="Scan All supported infrastructures") parser.add_argument("-cloudflare", dest="tg_cloudflare", action="store_true", help="Scan GCP infrastructure") parser.add_argument("-gcp", dest="tg_gcp", action="store_true", help="Scan Cloudflare infrastructure") parser.add_argument("-aws", dest="tg_aws", action="store_true", help="Scan AWS infrastructures") parser.add_argument("-linode", dest="tg_linode", action="store_true", help="Scan Linode infrastructures") parser.add_argument("-others", dest="tg_others", action="store_true", help="Scan rest of SaaS: DO, Linode, etc") parser.add_argument("-schedule", dest="tg_schedule", action="store_true", help="Schedule scans by Tenable.io") parser.set_defaults(tg_all=False) parser.set_defaults(tg_cloudflare=False) parser.set_defaults(tg_gcp=False) parser.set_defaults(tg_aws=False) parser.set_defaults(tg_linode=False) parser.set_defaults(tg_others=False) parser.set_defaults(tg_schedule=False) args = parser.parse_args() # Create dirs gen.create_dirs() # Set configuration file location main_script_abs = os.path.dirname(os.path.abspath(__file__)) settings_obj = configparser.ConfigParser() settings_obj.read(main_script_abs + '/conf/conf.cfg') # Initiate an instance of TenableIOClient. settings = settings_obj._sections.copy() tenable_client = TenableIOClient(access_key=settings['TENABLE.IO']['access_key'], secret_key=settings['TENABLE.IO']['secret_key']) logger.info('Successfully authenticated to Tenable.io') # Set scheduled scan time scan_time = datetime.now() # Set time delta if you need to launch scanning job right now if not args.tg_schedule: for section in settings.keys(): if 'time_delta' in settings[section].keys(): settings[section]['time_delta'] = 0 # Launch scan jobs in Tenable.io against GCP resources if args.tg_gcp or args.tg_all: # Set GCP credentials environment logger.info('Parsing google credentials and set ENV variables') gcp_api_key_json = settings_obj.get('GCP', 'gcp-api-key-json') # Set Service account env variable and form path to json file os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = main_script_abs + gcp_api_key_json # Configure credentials for Google API authentication credentials = GoogleCredentials.get_application_default() compute = discovery.build('compute', 'v1', credentials=credentials) sql = discovery.build('sqladmin', 'v1beta4', credentials=credentials) logger.info('Successfully authenticated to GCP services') # Get list of all projects via GCP Resource manager resource_client = resource_manager.Client() projects_list = list(resource_client.list_projects()) logger.info('Successfully extracted list GCP projects and public IP addresses') # Retrieve all GCP organization public IP address target_ip_addresses = gcp.get_organization_public_ip(compute, sql, projects_list) # # In case you need to read from local copy of saved projects # target_ip_addresses = gen.read_json_file('json/20181006T104414-gcp_addresses.json') logger.info('Trying to create scan jobs in Tenable.io for all GCP projects') # Launch scan against GCP resources scan_time = tnb.create_tenable_scan(scan_target='TENABLE_GCP_SCAN', client=tenable_client, target=target_ip_addresses, settings=settings, logger=logger, scan_time=scan_time) logger.info('Successfully created scan jobs in Tenable.io') if args.tg_cloudflare or args.tg_all: # Parse CF credentials environment logger.info('Parsing Cloudflare credentials') cf_email = settings_obj.get('CLOUDFLARE', 'cf_email') cf_api_key = settings_obj.get('CLOUDFLARE', 'cf_api_key') # Create Cloudflare connection object cf_client = CloudFlare.CloudFlare(email=cf_email, token=cf_api_key) # Create targets for scanning job target_hostnames = cf.get_cf_website_dns(cf_client=cf_client) # # Test purposes (comment please when test will be finished) # target_hostnames = gen.read_json_file('json/20181005T185623-cf_addresses.json') # scan_time += timedelta(hours=90) cf.create_firewall_access_rule(cf_client=cf_client, settings=settings, zones=target_hostnames) scan_time = tnb.create_tenable_scan(scan_target='TENABLE_CF_SCAN', client=tenable_client, target=target_hostnames, settings=settings, logger=logger, scan_time=scan_time) if args.tg_aws or args.tg_all: # Create Cloudflare connection object target_assets = aws.get_tenables_assets(client=tenable_client) scan_time = tnb.create_tenable_scan(scan_target='TENABLE_AWS_SCAN', client=tenable_client, target=target_assets, settings=settings, logger=logger, scan_time=scan_time) if args.tg_linode or args.tg_all: # Get Linode targets linode_client = LinodeClient(settings['LINODE']['lin_api_key']) linode_targets = lin.get_linode_targets(client=linode_client) scan_time = tnb.create_tenable_scan(scan_target='TENABLE_LINODE_SCAN', client=tenable_client, target=linode_targets, settings=settings, logger=logger, scan_time=scan_time) if args.tg_others or args.tg_all: # Launch scan of Other targets target_assets = others.prepare_other_targets(settings['TENABLE_OTHERS_SCAN']) scan_time = tnb.create_tenable_scan(scan_target='TENABLE_OTHERS_SCAN', client=tenable_client, target=target_assets, settings=settings, logger=logger, scan_time=scan_time) logger.info('Vulnerability scan will be finished at {0}'.format(scan_time.strftime('%Y%m%dT%H%M%S'))) logger.info('######################################## END ########################################')