def __init__(self, config=None): self.logger = logging.getLogger('qualysWhisperAPI') self.config = config try: self.qgc = qualysapi.connect(config, 'qualys_web') self.logger.info('Connected to Qualys at {}'.format(self.qgc.server)) except Exception as e: self.logger.error('Could not connect to Qualys: {}'.format(str(e))) self.headers = { "content-type": "text/xml"} self.config_parse = qcconf.QualysConnectConfig(config) try: self.template_id = self.config_parse.get_template_id() except: self.logger.error('Could not retrieve template ID')
def connect_api(): if not os.path.isfile(os.getcwd() + '/.qcrc'): # create the qcrc, enter your qualys credentials print 'creating .qcrc in ' + folder + ', enter your qualysguard credentials below;' qgs = qualysapi.connect(remember_me=True) else: # connect using existing .qcrc qgs = qualysapi.connect() # connect to the API and list reports as an XML ret = qgs.request('/api/2.0/fo/report', {'action': 'list'}) root = xmltodict.parse(ret) # iterate over available reports for your account, parse timestamps in epoch for x in root['REPORT_LIST_OUTPUT']['RESPONSE']['REPORT_LIST']['REPORT']: y1 = x['LAUNCH_DATETIME'] y2 = datetime.datetime.strptime(str(y1), '%Y-%m-%dT%H:%M:%SZ').strftime('%s') z1 = x['EXPIRATION_DATETIME'] z2 = datetime.datetime.strptime(str(z1), '%Y-%m-%dT%H:%M:%SZ').strftime('%s') a = x['ID'] + ',' + y1 + ',' + y2 + ',' + z1 + ',' + z2 + ',' + x[ 'USER_LOGIN'] + ',' + x['OUTPUT_FORMAT'] + ',' + x['SIZE'] print a result.append(str(a) + '\n') resid.append(int(x['ID'])) print '' # check for reports that arent downloaded yet, else skip tmp = [] tmp.append(glob.glob(os.getcwd() + '/results/*csv')) for x in resid: found = False for y in tmp: if re.search(str(x), str(y)): found = True fname = str(x) + '_' + str(y2) + '.csv' if found == False: print 'downloading ' + fname download_report(x, fname) else: print 'skipping ' + fname # write an overview of report metadata to a csv f = open(os.getcwd() + '/reports.csv', 'wb') for x in result: f.write(x) f.close
def connect_api(): if not os.path.isfile(os.getcwd()+'/.qcrc'): # create the qcrc, enter your qualys credentials print 'creating .qcrc in '+folder+', enter your qualysguard credentials below;' qgs = qualysapi.connect(remember_me=True) else: # connect using existing .qcrc qgs = qualysapi.connect() # connect to the API and list reports as an XML ret = qgs.request('/api/2.0/fo/report', {'action': 'list'}) root = xmltodict.parse(ret) # iterate over available reports for your account, parse timestamps in epoch for x in root['REPORT_LIST_OUTPUT']['RESPONSE']['REPORT_LIST']['REPORT']: y1 = x['LAUNCH_DATETIME'] y2 = datetime.datetime.strptime(str(y1), '%Y-%m-%dT%H:%M:%SZ').strftime('%s') z1 = x['EXPIRATION_DATETIME'] z2 = datetime.datetime.strptime(str(z1), '%Y-%m-%dT%H:%M:%SZ').strftime('%s') a = x['ID']+','+y1+','+y2+','+z1+','+z2+','+x['USER_LOGIN']+','+x['OUTPUT_FORMAT']+','+x['SIZE'] print a result.append(str(a)+'\n') resid.append(int(x['ID'])) print '' # check for reports that arent downloaded yet, else skip tmp = [] tmp.append(glob.glob(os.getcwd()+'/results/*csv')) for x in resid: found = False for y in tmp: if re.search(str(x), str(y)): found = True fname = str(x)+'_'+str(y2)+'.csv' if found == False: print 'downloading '+fname download_report(x, fname) else: print 'skipping '+fname # write an overview of report metadata to a csv f = open(os.getcwd()+'/reports.csv', 'wb') for x in result: f.write(x) f.close
def __init__(self, qsub='test'): self.filename = config_dict[qsub] try: self.api = qualysapi.connect(self.filename) except: print "Config file missing or connect failed." user = raw_input("Enter user: "******"Enter pass: "******"qualys.server.com") except: print "Could not connect. Quitting..." print "Loading asset groups..." print "\nCVS-Qualys Instance Asset Groups as of " + str(datetime.now()) self.update_asset_groups() self.build_asset_dict()
def __init__(self, qsub='test'): self.filename = self.config_dict[qsub] self.fullpath = os.getcwd() #full_config_filepath = self.fullpath.replace("\\", "\\\\") + "\\\\" + self.filename #print self.filename try: self.api = qualysapi.connect(self.filename) # Full path names and the config file? WTF yo self.qsub_v = qsub except: print "\n[!] Please Authenticate: " #user = raw_input("Enter user: "******"Enter pass: "******"qualys.server.com") except: print "Could not connect. Quitting..."
def add_ip(self): a = qualysapi.connect('config.ini') #conexion a la API de Qualys reportScans = a.request('/api/2.0/fo/asset/ip/', { 'action': 'add', 'details': 'All', 'ips': (self.ip), 'enable_vm': '1' })
def __init__(self, config=None): self.config = config try: self.qgc = qualysapi.connect(config) print('[SUCCESS] - Connected to Qualys at %s' % self.qgc.server) except Exception as e: print('[ERROR] Could not connect to Qualys - %s' % e) self.headers = {"content-type": "text/xml"}
def download_report(rid, fname): qgs = qualysapi.connect() ret = qgs.request('/api/2.0/fo/report', {'action': 'fetch', 'id': rid}) # write the report as csv to disk with the id and timestamp in fname f = open(str(folder+fname), 'wb') f.write(ret) f.close
def download_report(rid, fname): qgs = qualysapi.connect() ret = qgs.request('/api/2.0/fo/report', {'action': 'fetch', 'id': rid}) # write the report as csv to disk with the id and timestamp in fname f = open(str(folder + fname), 'wb') f.write(ret) f.close
def main(args): # Setup connection to QualysGuard API. qgc = qualysapi.connect(args.qualys_config) current_time = datetime.datetime.now().strftime("%Y%m%d%H%M") logger.debug('Current Time: %s', current_time) webapp_id = update_scan_url(qgc, current_time, args) scan_id = scan_report(qgc, current_time, args, webapp_id) generate_report(qgc, args, scan_id)
def __init__(self, config=None): self.config = config try: self.qgc = qualysapi.connect(config) # Fail early if we can't make a request or auth is incorrect self.qgc.request('about.php') print('[SUCCESS] - Connected to Qualys at %s' % self.qgc.server) except Exception as e: print('[ERROR] Could not connect to Qualys - %s' % e) exit(1)
def __init__(self, config=None): self.logger = logging.getLogger('qualysWhisperAPI') self.config = config try: self.qgc = qualysapi.connect(config, 'qualys_vuln') # Fail early if we can't make a request or auth is incorrect self.qgc.request('about.php') self.logger.info('Connected to Qualys at {}'.format(self.qgc.server)) except Exception as e: self.logger.error('Could not connect to Qualys: {}'.format(str(e))) # FIXME: exit(1) does not exist: either it's exit() or sys.exit(CODE) exit(1)
def __init__(self, config=None): self.config = config try: self.qgc = qualysapi.connect(config) print('[SUCCESS] - Connected to Qualys at %s' % self.qgc.server) except Exception as e: print('[ERROR] Could not connect to Qualys - %s' % e) self.headers = {"content-type": "text/xml"} self.config_parse = qcconf.QualysConnectConfig(config) try: self.template_id = self.config_parse.get_template_id() except: print('ERROR - Could not retrieve template ID')
def query(url=None, params=None, username=None, password=None, remember_me=False, max_retries=_max_retries): _pc_scans_suffix = '/api/2.0/fo/scan/compliance' _pc_scans_list_dtd = '' if url is None or '': return False if params is None or '': return False if username is None or '': return False if password is None or '': return False else: _username = str(username) _password = str(password) try: ''' Create the API request if _suffix is valid based on API type''' with api.connect(hostname=url, username=_username, password=_password, remember_me=remember_me, max_retries=max_retries) as cnn: try: ''' Send the crafted API request ''' with cnn.request(api_call=url, data=params, api_version='2.0', http_method='post') as response: # TODO: Validate XML Reponse with DTD here # If ok, pass response, response.status return etree.fromstring(response.encode('utf-8')), \ response.status except Exception as ex: log.exception(f'Could not submit request to the Qualys API: ' f'{str(ex)}') return False except Exception as ex: log.exception(f'Could not use qualysapi to connect to Qualys API: ' f'{str(ex)}') return False
def handle_command(command, channel): """ Executes bot command if the command is known """ # Default response is help text for the user default_response = "Not sure what you mean. Try *{}*.".format( EXAMPLE_COMMAND) # Finds and executes the given command, filling in response response = None # This is where you start to implement more commands! if command.startswith(EXAMPLE_COMMAND): q = qualysapi.connect() r = q.request('/api/2.0/fo/scan/', { 'action': 'list', 'state': 'Running' }) root = objectify.fromstring(bytes(r, encoding='utf-8')) try: # Iterate scans and store scan references. for scan in root.RESPONSE.SCAN_LIST.SCAN: response = f'Canceling {scan.TITLE.text}: {scan.REF.text}...' # Sends the response back to the channel slack_client.api_call("chat.postMessage", channel=channel, text=response or default_response) r = q.request('/api/2.0/fo/scan/', { 'action': 'cancel', 'scan_ref': scan.REF.text }) response = 'Failed to cancel scan, or scan has already been canceled.' if '<TEXT>Canceling scan</TEXT>' in r: response = 'Successfully canceled scan.' slack_client.api_call("chat.postMessage", channel=channel, text=response or default_response) except AttributeError: response = 'No scans running.' slack_client.api_call("chat.postMessage", channel=channel, text=response or default_response)
def delete_ip(self): try: a = qualysapi.connect('config.ini') #conexion a la API de Qualys #reportScans = a.request('/api/2.0/fo/asset/host/',{'action':'purge','echo_request':'1','ips':(self.ip)}) reportScans = a.request('/api/2.0/fo/asset/host/', { 'action': 'purge', 'ips': (self.ip) }) ### solo para debuging #print (reportScans) root = objectify.fromstring(reportScans.encode('utf-8')) print(root.RESPONSE.BATCH_LIST.BATCH.ID_SET.ID) except AttributeError: print("++++++++++++++++++++++++++++++++++++++++" '\n') print("Error Code " + root.RESPONSE.BATCH_LIST.BATCH.CODE.text) print("Description " + root.RESPONSE.BATCH_LIST.BATCH.TEXT.text + '\n') print("++++++++++++++++++++++++++++++++++++++++") else: for host in root.RESPONSE.BATCH_LIST.BATCH: print(host.TEXT.text) print(host.ID_SET.ID.text)
def search_ip(self): try: a = qualysapi.connect('config.ini') #conexion a la API de Qualys reportScans = a.request('/api/2.0/fo/asset/host/', { 'action': 'list', 'details': 'All', 'ips': (self.ip) }) #print (reportScans)# Activar solo para troubleshoting root = objectify.fromstring(reportScans.encode('utf-8')) print(root.RESPONSE.HOST_LIST.HOST) except AttributeError: print('\n' "++++++++++++++++++++++++++++++++++++++++" '\n') print("host " + self.ip + " is not on Qualys") print('\n' "++++++++++++++++++++++++++++++++++++++++" '\n') else: for host in root.RESPONSE.HOST_LIST.HOST: print("++++++++++++++++++++++++++++++++++++++++" '\n') print("Server Information " '\n') print("----------------------------------------") print("IP: " + host.IP.text) try: # Validar DNS print("DNS: " + host.DNS.text) except AttributeError: print("No DNS") print("OS: " + host.OS.text) try: # Validar hostname print("NETBIOS: " + host.NETBIOS.text) except AttributeError: print("No Netbios") print("ID: " + host.ID.text) try: # validad ultimo scan print("LAST VULN SCAN: " + host.LAST_VULN_SCAN_DATETIME.text) except AttributeError: print("No last vuln info") print("----------------------------------------") print('\n' "++++++++++++++++++++++++++++++++++++++++" '\n')
def purge(days): try: a = qualysapi.connect('config.ini') assets = a.request('/api/2.0/fo/asset/host/',{'action':'list','details':'All/AGs','no_vm_scan_since':days}) #print(assets) root = objectify.fromstring(assets.encode('utf-8')) file = open("ips.csv","w+") file.write ("******************************************************"+'\n') file.write (" "+'\n') file.write (" Vulnerabilty Management Team "+'\n') file.write (" "+'\n') file.write ("******************************************************"'\n') file.write("IP , NETBIOS ,Last vuln scan"'\n') for host in root.RESPONSE.HOST_LIST.HOST: #ipList = (host.DNS.text+host.IP.text+","+host.LAST_VULN_SCAN_DATETIME.text+'\n') print ('\n'"++++++++++++++++++++++++++++++++++++++++"'\n') print ("ID: "+host.ID.text) print ("IP: "+host.IP.text) file.write(host.IP.text+",") try: print ("DNS: "+host.DNS.text) file.write(host.DNS.text+",") except AttributeError: print ("NO DNS ") file.write("NO HOSTNAME"+",") try: print ("OS: "+host.OS.text) except AttributeError: print ("No OS") print ("Last day scanned: "+host.LAST_VULN_SCAN_DATETIME.text) file.write(host.LAST_VULN_SCAN_DATETIME.text+'\n') try: print ("Asset group: "+host.ASSET_GROUP_IDS.text) except AttributeError: print ("No Asset group") print ('\n'"++++++++++++++++++++++++++++++++++++++++"'\n') file.close() except AttributeError: print("error", "I don't find data for host not scanned sice "+ days)
netbios = str(host.NETBIOS) except AttributeError, e: logging.debug("%s: No NetBIOS." % (ip, str(e))) # Grab OS. os = "" try: os = str(host.OS) except AttributeError, e: logging.debug("%s: No OS." % (ip, str(e))) # Write to CSV. csvwriter.writerow([ip, hostname, netbios, os]) # Increment number of hosts found. count += 1 # Store ip in set. subscribe_me.add(ip) # All data stored. Print out to files. print "Number of live, not scannable hosts found: %s" % str(count) print "Host details successfully written to %s." % args.file_ip_list # Subscribe IPs, if requested. if not args.subscribe: exit() if c_args.config: qgc = qualysapi.connect(c_args.config) else: qgc = qualysapi.connect() # Combine IPs to comma-delimited string. formatted_ips_to_subscribe = ",".join(subscribe_me) # Subscribe IPs. qgc = qualysapi.connect("asset_ip.php", {"action": "add", "host_ips": formatted_ips_to_subscribe}) exit()
import qualysapi from lxml import objectify q = qualysapi.connect() response = q.request('/api/2.0/fo/scan/', { 'action': 'list', 'state': 'Running' }) root = objectify.fromstring(bytes(response, encoding='utf-8')) # Iterate scans and store scan references. try: for scan in root.RESPONSE.SCAN_LIST.SCAN: print(f'Canceling {scan.TITLE.text}: {scan.REF.text}...') response = q.request('/api/2.0/fo/scan/', { 'action': 'cancel', 'scan_ref': scan.REF.text }) if '<TEXT>Canceling scan</TEXT>' in response: print('Successfully canceled scan.') except AttributeError: print('No scans running.')
#!/usr/bin/env python import logging import qualysapi if __name__ == '__main__': # Basic command line processing. # Set the MAXIMUM level of log messages displayed @ runtime. logging.basicConfig(level=logging.DEBUG) # Call helper that creates a connection w/ HTTP-Basic to QualysGuard v1 API qgs = qualysapi.connect('qualys.ini') # Logging must be set after instanciation of connector class. logger = logging.getLogger('qualysapi.connector') logger.setLevel(logging.DEBUG) # Log to sys.out. logger_console = logging.StreamHandler() logger_console.setLevel(logging.DEBUG) formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') logging.getLogger(__name__).addHandler(logger) # Formulate a request to the QualysGuard V1 API # docs @ # https://community.qualys.com/docs/DOC-1324 # http://www.qualys.com/docs/QualysGuard_API_User_Guide.pdf # # ret = qgs.request('/api/2.0/fo/asset/vhost/', {'action':'list'}) ret = qgs.listVirtualHosts() for vhost in ret:
if c_args.debug: # Enable debug level of logging. print "Logging level set to debug." logging.basicConfig(filename = LOG_FILENAME, format = '%(asctime)s %(message)s', level = logging.DEBUG) else: logging.basicConfig(filename = LOG_FILENAME, format = '%(asctime)s %(message)s', level = logging.INFO) # Validate arguments. if not ((c_args.all_apps or c_args.tag or c_args.Tags_file)): parser.print_help() logging.error('Invalid run parameters.') exit(1) # Configure Qualys API connector. if c_args.config: qgc = qualysapi.connect(c_args.config) else: qgc = qualysapi.connect() # There may be more than 1000 apps so start with first possible record, # 0. last_record = '0' apps_to_update = [] print 'Downloading list of applications.' while True: # Get list of web apps. query_uri = '/search/was/webapp' if c_args.all_apps: data = ''' <ServiceRequest> <filters> <Criteria field="createdDate" operator="GREATER">2000-02-21T00:00:00Z</Criteria> <Criteria field="id" operator="GREATER">%s</Criteria>
def run(job, logger, **kwargs): start = time.time() state = 'success' scan_type = '{{Scan_Type}}' template_id = scan_type requestor_email = job.owner.user.email # Allow the user to have the PDF report sent to additional email addresses cc_list = '{{Email_List}}' # Allow the user to add custom text to the bottom of the email extra_body = '{{Email_Extra_Body}}' # Verify Cloudbolt know the email address of the requestor if requestor_email is None or requestor_email == '': return "FAILURE", "Please update your email in your user profile.", "" server = job.server_set.first() job_id = job.id session = qualysapi.connect() call = 'scan.php' ipaddr = '' error_code = '' # Build an array to capture a dictionary of Qualys Scanner, Server names and IPs # And Build and array of the scanners svr_info = [] scanner_list = [] for server in job.server_set.all(): if str(server.status) == 'ACTIVE': svrinfo = { 'scanner': str(server.environment.qualys_scanner), 'ipaddress': str(server.ip), 'name': str(server) } svr_info.append(svrinfo) scanner_list.append(str(server.environment.qualys_scanner)) # Find the unique scanners scanners = set(scanner_list) for scanner in scanners: # build the list of IPs for this scanner ipaddr = '' svr_string = '' for svr in svr_info: if svr['scanner'] == scanner: svr_string = svr_string + svr['name'] + ' : ' + svr[ 'ipaddress'] + '\n' if ipaddr == '': ipaddr = svr['ipaddress'] else: ipaddr = ipaddr + ',' + svr['ipaddress'] parameters = { 'scan_title': 'Scan of ' + str(ipaddr) + ': Initiated via Cloudbolt job ' + str(job.id) + ' on Scanner ' + scanner, 'iscanner_name': scanner, 'ip': str(ipaddr), 'option': "!IHG - Internal - Authenticated Scan - Full TCP", 'save_report': 'yes' } logger.debug('Request parameters: ' + str(parameters)) set_progress("- Running Qualys Scan...") xml_output = session.request(call, parameters, concurrent_scans_retries=2, concurrent_scans_retry_delay=300) root = objectify.fromstring(xml_output) if hasattr(root, 'IP'): logger.debug('Root Attrib: ' + str(root.attrib)) gen_pdf_report = session.request( '/api/2.0/fo/report', { 'action': 'launch', 'template_id': template_id, 'report_title': 'Cloudbolt report for job ' + str(job.id), 'report_type': 'Scan', 'output_format': 'pdf', 'report_refs': root.attrib['value'] }) gen_pdf = objectify.fromstring(gen_pdf_report) pdf_report_id = gen_pdf.RESPONSE.ITEM_LIST.ITEM['VALUE'] gen_xml_report = session.request( '/api/2.0/fo/report', { 'action': 'launch', 'template_id': template_id, 'report_title': 'Cloudbolt report for job ' + str(job.id), 'report_type': 'Scan', 'output_format': 'xml', 'report_refs': root.attrib['value'] }) gen_xml = objectify.fromstring(gen_xml_report) xml_report_id = gen_xml.RESPONSE.ITEM_LIST.ITEM['VALUE'] logger.debug('Waiting for XML Report to be Generated') retries = 40 sleepseconds = 15 count = 1 while count <= retries: time.sleep(sleepseconds) xml_status_request = session.request('/api/2.0/fo/report', { 'action': 'list', 'id': xml_report_id }) xml_status = objectify.fromstring(xml_status_request) logger.debug(xml_status) if hasattr(xml_status.RESPONSE, 'REPORT_LIST') and xml_status.RESPONSE.REPORT_LIST[ 0].REPORT.STATUS['STATE'] == 'Finished': count = retries * 2 + 10 count += 1 xml_report = session.request('/api/2.0/fo/report', { 'action': 'fetch', 'id': xml_report_id }) report = objectify.fromstring(xml_report) sum_vuls = 0 sev1 = 0 sev2 = 0 sev3 = 0 sev4 = 0 sev5 = 0 if hasattr(report, 'IP'): logger.debug('report Attrib: ' + str(report.attrib)) for svrip in report.IP: svrname = svrip.attrib['name'] if hasattr(svrip, 'VULNS'): for x in svrip.VULNS.CAT: sum_vuls += len(x.VULN) for vul in x.VULN: set_progress('Server: ' + svrname + ' , Severity: ' + vul.attrib['severity'] + ' , QID: ' + vul.attrib['number'] + ' , VULNERBILITY: ' + vul.TITLE) if vul.attrib['severity'] == '1': sev1 += 1 if vul.attrib['severity'] == '2': sev2 += 1 if vul.attrib['severity'] == '3': sev3 += 1 if vul.attrib['severity'] == '4': sev4 += 1 if vul.attrib['severity'] == '5': sev5 += 1 else: logger.debug('NO Vulnerabilites found for ' + str(svrname)) sum_3_5 = sev3 + sev4 + sev5 sum_1_2 = sev1 + sev2 set_progress( str(sum_3_5) + ' Critical Vunerabilites Found. Sev 5: ' + str(sev5) + ', Sev 4: ' + str(sev4) + ', Sev 3: ' + str(sev3)) if sum_1_2 > 0: set_progress( str(sum_1_2) + ' Non-Critical Vunerabilites Found. Sev 2: ' + str(sev2) + ', Sev 1: ' + str(sev1)) if sum_3_5 > 0: state = 'warning' del_xml = session.request('/api/2.0/fo/report', { 'action': 'delete', 'id': xml_report_id }) logger.debug('Waiting for PDF Report to be Generated') count = 1 while count <= retries: time.sleep(sleepseconds) pdf_status_request = session.request('/api/2.0/fo/report', { 'action': 'list', 'id': pdf_report_id }) pdf_status = objectify.fromstring(pdf_status_request) if pdf_status.RESPONSE.REPORT_LIST[0].REPORT.STATUS[ 'STATE'] == 'Finished': count = retries * 2 + 10 count += 1 pdf_report = session.request('/api/2.0/fo/report', { 'action': 'fetch', 'id': pdf_report_id }) filename = '/tmp/' + str(job.id) + '.pdf' with open(filename, 'wb') as f: f.write(pdf_report) f.close subject = 'Qualys Report for Cloudbolt job ' + str(job.id) if extra_body and extra_body != '': body = subject + '\n\nScanned Servers\n' + svr_string + extra_body else: body = subject + '\n\nScanned Servers\n' + svr_string sender = requestor_email recipient = [requestor_email] if cc_list and cc_list != '': ccs = cc_list.split(',') recipient.extend(ccs) attach = [(filename, 'application/pdf')] mail.send_mail(subject, body, sender, recipient, attachments=attach, filter_recipients=False) os.remove(filename) else: logger.debug('Error Code: ' + str(root.ERROR.attrib['number'])) state = 'fail' error_code = root.ERROR.attrib['number'] done = time.time() restoreduration = "%.2f" % (done - start) logger.debug("Qualys Scan duration(secs): " + restoreduration) if state == 'success': return "SUCCESS", "Qualys Scan successfully completed. Check your email for PDF reports", "" elif state == 'warning': return "WARNING", "Qualys Scan found vulneribilities", "" else: if error_code == '3007': return "FAILURE", "Too many concurrent scans running at this time. Please try again later.", "" elif error_code == '3003': return "FAILURE", "Not Allowed to scan these IPs.", "" else: logger.debug('xml return from Qualys: ' + xml_output) return "FAILURE", "Qualys Scan request failed with unknown error", ""
#! /usr/bin/python """ Licence : BeerWare """ import sys, qualysapi login = qualysapi.connect(remember_me_always=True)
import qualysapi # Questions? See: # https://bitbucket.org/uWaterloo_IST_ISS/python-qualysconnect if __name__ == '__main__': # Basic command line processing. if len(sys.argv) != 2: print 'A single IPv4 address is expected as the only argument' sys.exit(2) # Set the MAXIMUM level of log messages displayed @ runtime. logging.basicConfig(level=logging.INFO) # Call helper that creates a connection w/ HTTP-Basic to QualysGuard API. qgs=qualysapi.connect() # Logging must be set after instanciation of connector class. logger = logging.getLogger('qualysapi.connector') logger.setLevel(logging.DEBUG) # Log to sys.out. logger_console = logging.StreamHandler() logger_console.setLevel(logging.DEBUG) formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') logging.getLogger(__name__).addHandler(logger) # Formulate a request to the QualysGuard V1 API. # docs @ # https://community.qualys.com/docs/DOC-1324 # http://www.qualys.com/docs/QualysGuard_API_User_Guide.pdf
from defusedxml.ElementTree import fromstring from qualysapi import connect # API url to pull data from. See qualys docs for a list of APIs api_url = "/api/2.0/fo/asset/host/" # Options for API request. See qualys docs for a list of all options params = { 'action': 'list', 'truncation_limit': '10', } # Create a connection object used to pull data from Qualys conn = connect( username="******", # Qualys Username password="******", # Qualys Password hostname="<hostname>", # Optional api host url max_retries="<#>", # Optional # of retries ) # Perform API request resp = conn.request(api_url, params) print(resp) # Raw text response from Qualys # Parse the response string and convert to an xml object xml = fromstring(resp.encode('utf-8')) for host in xml.iter(tag='HOST'): id = host.find('./ID').text ip = host.find('./DNS').text print(id + ": " + ip)
__author__ = 'Parag Baxi <*****@*****.**>' __license__ = 'Apache License 2.0' import qualysapi from lxml import objectify from lxml.builder import E # Setup connection to QualysGuard API. qgc = qualysapi.connect('config.txt') # # API v1 call: Scan the New York & Las Vegas asset groups # The call is our request's first parameter. call = 'scan.php' # The parameters to append to the url is our request's second parameter. parameters = { 'scan_title': 'Go big or go home', 'asset_groups': 'New York&Las Vegas', 'option': 'Initial+Options' } # Note qualysapi will automatically convert spaces into plus signs for API v1 & v2. # Let's call the API and store the result in xml_output. xml_output = qgc.request(call, parameters, concurrent_scans_retries=2, concurrent_scans_retry_delay=600) # concurrent_retries: Retry the call this many times if your subscription hits the concurrent scans limit. # concurrent_retries: Delay in seconds between retrying when subscription hits the concurrent scans limit. # Example XML response when this happens below: # <?xml version="1.0" encoding="UTF-8"?> # <ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://localhost:50205/qps/rest/app//xsd/3.0/was/wasscan.xsd"> # <responseCode>INVALID_REQUEST</responseCode>
__author__ = 'Parag Baxi <*****@*****.**>' __license__ = 'Apache License 2.0' import qualysapi from lxml import objectify from lxml.builder import E # Setup connection to QualysGuard API. qgc = qualysapi.connect('config.txt', 'qualys_vuln') # # API v1 call: Scan the New York & Las Vegas asset groups # The call is our request's first parameter. call = 'scan.php' # The parameters to append to the url is our request's second parameter. parameters = { 'scan_title': 'Go big or go home', 'asset_groups': 'New York&Las Vegas', 'option': 'Initial+Options' } # Note qualysapi will automatically convert spaces into plus signs for API v1 & v2. # Let's call the API and store the result in xml_output. xml_output = qgc.request(call, parameters, concurrent_scans_retries=2, concurrent_scans_retry_delay=600) # concurrent_retries: Retry the call this many times if your subscription hits the concurrent scans limit. # concurrent_retries: Delay in seconds between retrying when subscription hits the concurrent scans limit. # Example XML response when this happens below: # <?xml version="1.0" encoding="UTF-8"?> # <ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://localhost:50205/qps/rest/app//xsd/3.0/was/wasscan.xsd"> # <responseCode>INVALID_REQUEST</responseCode>
# logger_qc.addHandler(logger_file) # logger_qc.addHandler(logger_console) # Validate arguments. if (not (c_args.all_vulns_template_id or c_args.all_vulns_xml) and (c_args.exclude_non_running_kernel_vulns_report_template_id or c_args.exclude_non_running_kernel_vulns_xml)): # if (not (c_args.all_vulns_xml and c_args.exclude_non_running_kernel_vulns_xml)): print 'One of each report is required.' parser.print_help() exit(1) # Configure Qualys API connector. if (c_args.mark_remediation_tickets_resolved_ignore or c_args.all_vulns_template_id or c_args.exclude_non_running_kernel_vulns_report_template_id): if c_args.config: qgc = qualysapi.connect(c_args.config) else: qgc = qualysapi.connect() # # Read in XML report including non-running kernels. if c_args.all_vulns_xml: # Read in XML file. tree = etree.parse(c_args.all_vulns_xml) else: # Grab XML from QualysGuard. tree = etree.parse(load_scan(c_args.all_vulns_template_id, c_args.title)) # Find all TICKET_NUMBER elements that contain associated remediation ticket numbers. all_vulns = tree.findall(".//TICKET_NUMBER") # Read in XML report excluding non-running kernels. if c_args.exclude_non_running_kernel_vulns_xml: # Read in XML file.
try: netbios = str(host.NETBIOS) except AttributeError, e: logging.debug('%s: No NetBIOS.' % (ip, str(e))) # Grab OS. os = '' try: os = str(host.OS) except AttributeError, e: logging.debug('%s: No OS.' % (ip, str(e))) # Write to CSV. csvwriter.writerow([ip, hostname, netbios, os]) # Increment number of hosts found. count += 1 # Store ip in set. subscribe_me.add(ip) # All data stored. Print out to files. print 'Number of live, not scannable hosts found: %s' % str(count) print 'Host details successfully written to %s.' % args.file_ip_list # Subscribe IPs, if requested. if not args.subscribe: exit() if c_args.config: qgc = qualysapi.connect(c_args.config) else: qgc = qualysapi.connect() # Combine IPs to comma-delimited string. formatted_ips_to_subscribe = ','.join(subscribe_me) # Subscribe IPs. qgc = qualysapi.connect('asset_ip.php',{'action': 'add', 'host_ips': formatted_ips_to_subscribe}) exit()
__author__ = 'Parag Baxi <*****@*****.**>' __license__ = 'Apache License 2.0' import qualysapi from lxml import objectify from lxml.builder import E # Setup connection to QualysGuard API. qgc = qualysapi.connect('config.txt', 'qualys_vuln') # # API v1 call: Scan the New York & Las Vegas asset groups # The call is our request's first parameter. call = 'scan.php' # The parameters to append to the url is our request's second parameter. parameters = {'scan_title': 'Go big or go home', 'asset_groups': 'New York&Las Vegas', 'option': 'Initial+Options'} # Note qualysapi will automatically convert spaces into plus signs for API v1 & v2. # Let's call the API and store the result in xml_output. xml_output = qgc.request(call, parameters, concurrent_scans_retries=2, concurrent_scans_retry_delay=600) # concurrent_retries: Retry the call this many times if your subscription hits the concurrent scans limit. # concurrent_retries: Delay in seconds between retrying when subscription hits the concurrent scans limit. # Example XML response when this happens below: # <?xml version="1.0" encoding="UTF-8"?> # <ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://localhost:50205/qps/rest/app//xsd/3.0/was/wasscan.xsd"> # <responseCode>INVALID_REQUEST</responseCode> # <responseErrorDetails> # <errorMessage>You have reached the maximum number of concurrent running scans (10) for your account</errorMessage> # <errorResolution>Please wait until your previous scans have completed</errorResolution> # </responseErrorDetails> # print(xml_output) #
__author__ = 'pbaxi' import csv import qualysapi from lxml import objectify, etree from collections import defaultdict # Connect to QualysGuard API. qgc = qualysapi.connect() # Create request and download XML. request = '/msp/scheduled_scans.php' parameters = {'list': 'all'} print 'Downloading list of scheduled scans...' xml_output = qgc.request(request, parameters) # Process XML. root = objectify.fromstring(xml_output) # Combine IPs being scanned. # Combine asset groups max_number_of_scanners = 0 max_number_of_asset_groups = 0 orphan_scanners = [] asset_groups = defaultdict(list) scanners = defaultdict(list) # Parse XML. list_of_scanners = [] for appliance in root.RESPONSE.APPLIANCE_LIST.APPLIANCE: try: for asset_group in appliance.ASSET_GROUP_LIST.ASSET_GROUP: # For sorted by scanners. asset_groups[asset_group.NAME.text].append(appliance.NAME.text) max_number_of_scanners = max(len(asset_groups[asset_group.NAME.text])+1, max_number_of_scanners)
from qualysapi import connect from lxml import objectify, etree from file_integrity_monitor import * import sys from port_scanning import * def get_number(call): xml = qualysConnection.request(call) xml = xml.encode('UTF-8') doc = etree.XML(xml) return doc.find('count').text try: qualysConnection = qualysapi.connect('config.ini') while (True): choice = int( input( "1. File Integrity Monitoring 2. Scan Ports 3. Show number of webapps hosted 4. Show number of scans scheduled 5. Show number of reports generated 6. Show number of times scanned 7. Stop\nEnter choice: " )) if choice == 1: fim() elif choice == 2: target_host = input("Enter the hostname to be scanned: ") scanPorts(target_host) elif choice == 3: print("Number of webapps:", get_number('/count/was/webapp'), '\n') elif choice == 4: print("Number of scan scheduled:", get_number('/count/was/wasscanschedule'), '\n')
__author__ = 'Parag Baxi <*****@*****.**>' __license__ = 'Apache License 2.0' import qualysapi from lxml import objectify from lxml.builder import E # Setup connection to QualysGuard API. qgc = qualysapi.connect('config.txt') # # API v1 call: Scan the New York & Las Vegas asset groups # The call is our request's first parameter. call = 'scan.php' # The parameters to append to the url is our request's second parameter. parameters = {'scan_title': 'Go big or go home', 'asset_groups': 'New York&Las Vegas', 'option': 'Initial+Options'} # Note qualysapi will automatically convert spaces into plus signs for API v1 & v2. # Let's call the API and store the result in xml_output. xml_output = qgc.request(call, parameters, concurrent_scans_retries=2, concurrent_scans_retry_delay=600) # concurrent_retries: Retry the call this many times if your subscription hits the concurrent scans limit. # concurrent_retries: Delay in seconds between retrying when subscription hits the concurrent scans limit. # Example XML response when this happens below: # <?xml version="1.0" encoding="UTF-8"?> # <ServiceResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://localhost:50205/qps/rest/app//xsd/3.0/was/wasscan.xsd"> # <responseCode>INVALID_REQUEST</responseCode> # <responseErrorDetails> # <errorMessage>You have reached the maximum number of concurrent running scans (10) for your account</errorMessage> # <errorResolution>Please wait until your previous scans have completed</errorResolution> # </responseErrorDetails> # print xml_output #
#!/usr/bin/env python3 # Use the defusedxml package for all xml parsing. See bandit docs: # https://bandit.readthedocs.io/en/latest/blacklists/blacklist_imports.html#b405-import-xml-etree from defusedxml.ElementTree import fromstring from qualysapi import connect # Config settings delimiter = "|" api_url = "/api/2.0/fo/asset/group" out_file = "out-asset-groups-list.csv" # Connect to Qualys API conn = connect() # Options for API request. See qualys docs for a list of all options params = {'action': 'list', 'truncation_limit': '0'} # Perform API request resp = conn.request(api_url, params) # Parse the response string and convert to an xml object xml = fromstring(resp.encode('utf-8')) ags = {} with open(out_file, "w+") as f: f.write('id' + delimiter + 'title' + delimiter + 'network_id' + delimiter + \ 'ip_ranges' + '\n') for ag in xml.iter(tag='ASSET_GROUP'): # Get the ID for the asset group