Qualys offers an option via the Asset Search Report to export the list of assets within your subscription. The limitation with this method is that the IPs in the Asset Search Report are the IPs that have been scanned at least once. This means that even if you launch a search with the option "not scanned in the last x days", the search results will still return assets only if they've been scanned at least once in the past.
In some cases what you are really interested in seeing is the IPs that have been added to your subscription but never scanned even once. You can see under the host assets section of the subscription the list of all your assets, so you can deduct with this and with the Asset Search report the list of assets actually never scanned. If you have a large number of hosts though, that can be a very tedious process. Moreover, the host assets list doesn't offer the possibility to extend scope written under the form "xx.xx.xx.xx-yy.yy.yy.yy", making it harder to read.
As a workaround I've developed a small Python script that allows you to get the actual list of your IPs that were never scanned. The script takes as a input the list of IPs from your Asset Search report, and the list of IPs in your subscription. The steps from the whole process are as follow:
Get the list of IPs within your subscription
To do so go to Assets>Host assets>New>Download
Generate a Asset Search Report
Go to Assets>Asset search, select "All" in "Asset Groups", and click on search. This will launch a pop-up windows, click on File>Download.
After this stage what we are aiming to have is two comma separated list. The list from the first step will probably be something like:
192.168.1.1, 192.168.1.5-192.168.1.15, 192.168.1.75 etc. As you can see we'll have to find a way to expand the scopes.
Launch a script to get the IPs never scanned
Going from there, here is what the script looks like. I'm pretty sure it can be greatly enhanced so you should feel free to modify it:
#Function to expand the IP scope, courtesy of Stack overflow, link below
def findIPs(start, end):
ipstruct = struct.Struct('>I')
start, = ipstruct.unpack(socket.inet_aton(start))
end, = ipstruct.unpack(socket.inet_aton(end))
return [socket.inet_ntoa(ipstruct.pack(i)) for i in range(start, end+1)]
#Step 1: Deal with the list of IPs from your list of assets.
for element in newlist:
if regex.match(element): #i.e., if the element is a scope
#at that stage you have the expanded list of IPs in your subscription in the list object "finallist"
#Step 2: Insert your Asset Search List in a list object for the comparison
#Step 3: Compare the two lists extract the diff
ipneverscanned=list(set(finallist) - set(newlistasr))
#Writing the list of IPs never scanned in a comma separated format
for i in ipneverscanned:
I hope this will be useful, as mentioned the script might not be the best written script but it's getting the job done.
Thanks to Istvan Herczeg for his help in understanding the concept behind the different searches.