The details below are geared towards Sys Admins who need to get details and trending on vulnerabilities Windows Server systems. I'm a Windows guy. So I started with filtering out the noise of our Linux, Cisco, etc. Some unfortunate soul will have to deal with those later (maybe I'll help them make a dashboard).
**I am by no means a Qualys expert**
There are probably alternative ways to get this detail. This is what I was able to do with very little support and no training.
Create Tagging for OSes and Vulnerability Matching
Hurdle number 1: Getting Groovy
You will need Groovy Scripting. I'm sure there are ways to do it with XML or something. But the Groovy syntax is better documented and more widely used in the community from what I saw.
**Caveat: Groovy Scriptlet must be enabled for your tenant if you are in the cloud.**
I was missing the option in the tag rule engine drop down when I started this process. Support had to turn this on. It took 2 phone calls and several emails to get enabled AND working.
Hurdle number 2: Tagging all Windows Servers
It's pretty simple to query for OS using basic regex. Qualys will give
you trouble though because of how it tags OS. Servers of the same
OS/template will show up with a different Operating System. Even two
network adapters on the same server may show differently. Short version:
Qualys gives a best guess.
See below: Do I really have 14 Windows Server "Operating Systems"? No. I probably have 5ish (leaving aside Datacenter vs. Standard).
Windows Server 2012 R2 Datacenter 64 bit Edition is the same as
Windows Server 2012 R2/8.1. Qualys just didn't get specific enough.
So we'll solve it by baking a little logic into the Groovy Script.
Go to your Tag page > New Tag:
Under Tag Rule > Rule Engine > Select Groovy Scriptlet
Windows Servers Query
###############################################################
if(asset.getAssetType()!=Asset.AssetType.HOST) return false;
if(asset.getOperatingSystem().contains("Windows Server")) return true;
if(asset.getOperatingSystem().contains("Windows 2008")) return true;
if(asset.getOperatingSystem().contains("Windows 2012")) return true;
if(asset.getOperatingSystem().contains("Windows 2016")) return true;
if(asset.getOperatingSystem().contains("Windows 2019")) return true;
###############################################################
Here we're returning false for anything that's not a host asset and true for all Windows Server OSes. But then we specifically search for all the variations of Windows 2008, 2012 and so on.
I opted not to use regex as stating "Windows" would return client OSes. Here's what that query looks like.
Windows Clients Query
###############################################################
if(asset.getAssetType()!=Asset.AssetType.HOST) return false;
if(asset.getOperatingSystem().contains("Windows 7")) return true;
if(asset.getOperatingSystem().contains("Windows 10")) return true;
###############################################################
Hurdle number 3: "But Shep, my server isn't showing up in the query."
I started with this well documented query. But we'll take it a bit further. This returns assets where the OS is null. Odds are, if you're not seeing an OS at all, you're missing credentials for root, local accounts, snmp, etc. Slightly harder to solve for non-Windows, domain joined systems.
NULL OS Query
###############################################################
if(asset.getAssetType()!=Asset.AssetType.HOST) return false;
return asset.getOperatingSystem()==null || asset.getOperatingSystem().trim().length()<=0;
###############################################################
I also created an "uncategorized" query so I could make sure I was capturing everything. i.e. show me everything I haven't expicitely tagged with an OS tag. In my case, this tag query would return Linux and Cisco. Eventually, when everything is tagged, this should return 0.
Uncategorized OS Query
###############################################################
if(asset.getAssetType()!=Asset.AssetType.HOST) return false;
if(asset.hasTag("Windows Server")) return false;
if(asset.hasTag("Windows Clients")) return false;
if(!asset.hasTag("No OS Found")) return true;
###############################################################
Note: we're using the "No OS Found" here. What we're saying is if the OS is NOT NOT found. i.e. there is actually an OS - just not Windows Server or Client.
Pro Tip: You can turn any query in Qualys into a not condition by placing "!" at the front.
Hurdle number 4: Getting systems with issues (Optional)
I say this step is optional because you can write these same queries into the dashboard widgets later. I find it easier to read and group with tags. The advantage is reusability. If you write the same query for severity 5s three times, you could have just made a tag and updated it once later when you want to add sev 4s.
Assets Based on Vulnerability Severity Query
###############################################################
if(asset.getAssetType()!=Asset.AssetType.HOST) return false;
return asset.hasVulnsWithSeverity(5)
###############################################################
Create a Dashboard
I think the biggest mental block for me was getting past the fact that Qualys treats Assets and Vulnerabilities differently. I was hoping to group, sort, filter assets AND vulnerabilities right on the Asset View page. Here we're strictly looking at Assets.
So go to your AssetView page
Actions > Create New Dashboard
Personally, I like to start with the 0-Day widget or an "Assets with..." widget. Anything that already has the conditional formatting already defined.
From there, you can drag and resize the various items. I opted stick with counts. I found the charts to be very limited.
This is where we start to leverage the tags. In the upper left, click the hamburger menu on the widget. Configure Widget.
Enter a Name
Enter a Query
Select "Compare with another reference query" (I leave defaults but it could be further refined)
Select "Collect trend data" (Collects history for this widget only)
Example Query
All Windows Servers with Zero Days
###############################################################
vulnerabilities.vulnerability.threatIntel.zeroDay:true and tags.name: Windows Server
###############################################################