Metrics Library

This is a community-led space where Liongard users can come to teach and learn from one another. Share custom Metrics, get inspired and see what’s trending in the Pride.
Microsoft 365: ConnectWise Cloud Backup and Cloud Management Apps Present
Huntress has confirmed unauthorized access tied to ConnectWise Cloud Backup (formerly SkyKick Backup) and the ConnectWise Cloud Management apps. Per Huntress, the Cloud Management apps self-assigned directory roles (mostly Exchange Administrator, Global Administrator in one tenant) and added client secrets to other apps. Huntress recommends DISABLING the apps, not deleting them, because deleting removes consent. The apps were renamed, so searching by the SkyKick name can miss them; these metrics match on Application ID, with a name fallback for older tenants. Finding an app does not mean a tenant was accessed, but it does mean the app is installed and should be reviewed. App IDs covered: ConnectWise Cloud Backup: 506e08f9-6e9a-4da4-942b-a099a03644ae Cloud Management: 2399d300-6fca-4e6a-a686-399fefe75b83 Cloud Management - MS Teams: 24205314-2b89-4e07-a2a4-579e898a5640 Cloud Management - Exchange Online: b78f6a77-d4e5-46fb-87e5-d1648bd02519 Cloud Management - MS Graph: 0de14c77-b9b0-4137-9360-34878a929827 Cloud Management - Partner Center: 412dcf96-176d-4b3a-a1b0-4981ad66971e Cloud Management - SharePoint Online: b2b55f5b-7758-4719-8d8f-88ae172e6bdb Metric 6: Microsoft 365: ConnectWise Cloud Backup and Cloud Management Apps Present Description: Lists installed ConnectWise Cloud Backup (formerly SkyKick) and Cloud Management apps with enabled state. Matches by Application ID, with a name fallback. Query: ServicePrincipals[?contains(['506e08f9-6e9a-4da4-942b-a099a03644ae','2399d300-6fca-4e6a-a686-399fefe75b83','24205314-2b89-4e07-a2a4-579e898a5640','b78f6a77-d4e5-46fb-87e5-d1648bd02519','0de14c77-b9b0-4137-9360-34878a929827','412dcf96-176d-4b3a-a1b0-4981ad66971e','b2b55f5b-7758-4719-8d8f-88ae172e6bdb'], appId || '') || contains(displayName || '', 'SkyKick') || contains(displayName || '', 'ConnectWise Cloud') || contains(publisherName || '', 'ConnectWise S-K')].{App: displayName, Publisher: publisherName, AppId: appId, Enabled: accountEnabled, Created: createdDateTime} Metric 7: Microsoft 365: Count of ConnectWise Cloud Apps Present Description: Count of ConnectWise Cloud Backup and Cloud Management apps present in any state. Alert above 0. Query: length(ServicePrincipals[?contains(['506e08f9-6e9a-4da4-942b-a099a03644ae','2399d300-6fca-4e6a-a686-399fefe75b83','24205314-2b89-4e07-a2a4-579e898a5640','b78f6a77-d4e5-46fb-87e5-d1648bd02519','0de14c77-b9b0-4137-9360-34878a929827','412dcf96-176d-4b3a-a1b0-4981ad66971e','b2b55f5b-7758-4719-8d8f-88ae172e6bdb'], appId || '') || contains(displayName || '', 'SkyKick') || contains(displayName || '', 'ConnectWise Cloud') || contains(publisherName || '', 'ConnectWise S-K')] || `[]`) Metric 8: Microsoft 365: Count of Enabled ConnectWise Cloud Apps Description: Count of ConnectWise Cloud Backup and Cloud Management apps that are still enabled. Alert above 0, then disable (don't delete) the apps. Query: length(ServicePrincipals[?(contains(['506e08f9-6e9a-4da4-942b-a099a03644ae','2399d300-6fca-4e6a-a686-399fefe75b83','24205314-2b89-4e07-a2a4-579e898a5640','b78f6a77-d4e5-46fb-87e5-d1648bd02519','0de14c77-b9b0-4137-9360-34878a929827','412dcf96-176d-4b3a-a1b0-4981ad66971e','b2b55f5b-7758-4719-8d8f-88ae172e6bdb'], appId || '') || contains(displayName || '', 'SkyKick') || contains(displayName || '', 'ConnectWise Cloud') || contains(publisherName || '', 'ConnectWise S-K')) && accountEnabled==`true`] || `[]`) What to do: alert on a count above 0, then disable the apps in Entra (Enterprise applications > Properties > Enabled for users to sign-in? set to No). Do not delete them, and do not re-enable them until ConnectWise confirms credentials have been reset. Disabling does not remove credentials that were already added to other apps, so also review credentials and role assignments in each affected tenant (see the related metrics in this library). Follow Huntress and ConnectWise for current guidance.
0
·
Microsoft 365
Microsoft 365: ConnectWise or SkyKick Apps Holding Directory Roles
Huntress reports that the compromised ConnectWise Cloud Management apps assigned themselves directory roles in affected tenants, mostly Exchange Administrator and Global Administrator in one tenant. Disabling the apps does not remove a role assignment, so check which roles they hold. This metric lists directory roles that have a ConnectWise Cloud or SkyKick service principal as a member. Role members are matched by display name because role membership does not include the Application ID. A match doesn't mean a tenant was accessed, but any ConnectWise or SkyKick app holding a role should be reviewed immediately. Metric 1: Microsoft 365: ConnectWise or SkyKick Apps Holding Directory Roles Description: Lists directory roles held by a ConnectWise Cloud or SkyKick service principal. Alert above 0, then review in the Entra audit log and disable (don't delete) the app. Query: Roles[?Members[?isServicePrincipal==`true` && (contains(displayName || '', 'SkyKick') || contains(displayName || '', 'ConnectWise Cloud'))]].{Role: displayName, Apps: Members[?isServicePrincipal==`true` && (contains(displayName || '', 'SkyKick') || contains(displayName || '', 'ConnectWise Cloud'))].displayName} Metric 2: Microsoft 365: Count of ConnectWise or SkyKick Apps Holding Directory Roles Description: Count of directory roles held by a ConnectWise Cloud or SkyKick service principal. Alert above 0, then review in the Entra audit log and disable (don't delete) the app. Query: length(Roles[?Members[?isServicePrincipal==`true` && (contains(displayName || '', 'SkyKick') || contains(displayName || '', 'ConnectWise Cloud'))]] || `[]`) Metric 3: Microsoft 365: Service Principals Holding Directory Roles Description: Lists all service principals (apps) holding any directory role. Use to review non-human role assignments. Query: Roles[?Members[?isServicePrincipal==`true`]].{Role: displayName, ServicePrincipals: Members[?isServicePrincipal==`true`].displayName} What to do: alert on a count above 0. Review when each role was assigned using the Entra audit log (Add member to role), remove the assignment if it is unexpected, and disable the app rather than deleting it. Do not re-enable it until ConnectWise confirms credentials have been reset. Follow Huntress and ConnectWise for current guidance.
0
·
Microsoft 365
Microsoft 365: App Registrations With Recently Added Credentials
Huntress reports that the compromised ConnectWise Cloud Management apps added client secrets to other applications in affected tenants, including a Huntress app. Disabling the ConnectWise apps does not remove credentials that were already added, so each tenant needs a separate credential review. This metric lists app registrations that have had a client secret or certificate added in the last 30 days, with a count of each, so you can spot credentials nobody on your team created. Expect some benign matches, such as Microsoft Entra Connect Sync rotating its certificate. Review each result against your own change records. A match doesn't mean a tenant was accessed. Metric 4: Microsoft 365: App Registrations With Recently Added Credentials Description: Lists app registrations with a client secret or certificate added in the last 30 days. Some matches are benign (e.g. Entra Connect Sync certificate rotation), so verify against change records. Query: Applications[?passwordCredentials[?time_until(startDateTime, `days`) >= `-30`] || keyCredentials[?time_until(startDateTime, `days`) >= `-30`]].{App: displayName, AppId: appId, SecretsAdded: length(passwordCredentials[?time_until(startDateTime, `days`) >= `-30`] || `[]`), CertificatesAdded: length(keyCredentials[?time_until(startDateTime, `days`) >= `-30`] || `[]`)} Metric 5: Microsoft 365: Count of App Registrations With Recently Added Credentials Description: Count of app registrations with a client secret or certificate added in the last 30 days. Alert above 0. Query: length(Applications[?passwordCredentials[?time_until(startDateTime, `days`) >= `-30`] || keyCredentials[?time_until(startDateTime, `days`) >= `-30`]] || `[]`) What to do: for each result, confirm someone on your team added the credential. Remove any secret or certificate you can't account for, and check the app's owners and permissions. Change the 30 in both queries to widen or narrow the window. Follow Huntress and ConnectWise for current guidance.
0
·
Microsoft 365
Cisco Meraki Metric Request
Summary The Cisco Meraki Inspector does not collect the MX Threat Protection settings found under Security & SD-WAN → Configure → Threat protection in the Meraki dashboard. This means Advanced Malware Protection (AMP) and Intrusion Detection/Prevention (IDS/IPS) state cannot be alerted on, reported on, or tracked for change in Liongard. These are two of the highest-value security controls on an MX, and both can be disabled by a single dropdown change in the dashboard with no other visible side effect. Today that change is invisible to Liongard. Current behavior The current data print returns the following per network under Configuration.Networks[]: VLANs, FirewallRules, InboundFirewallRules, L7FirewallRules, SSIDs, AccessPolicies, StaticRoutes, VPNs, NAT, QOS, PortForwardingRules, GroupPolicies, Interfaces, FirmwareUpgrades, Devices, AirMarshals, Traffic There is no security/threat-protection node. A search of the full data print for malware, intrusion, threat, ruleset, prevention, and balanced returns no matches. Content filtering is also absent. Requested data Two read-only Dashboard API calls, both already within the scope of the API key the inspector uses today: GET /networks/{networkId}/appliance/security/malware json { "mode": "enabled", "allowedUrls": [ { "url": " example.org ", "comment": "..." } ], "allowedFiles": [ { "sha256": "...", "comment": "..." } ] } mode is enabled or disabled. GET /networks/{networkId}/appliance/security/intrusion json { "mode": "prevention", "idsRulesets": "balanced", "protectedNetworks": { "useDefault": false, "includedCidr": [ "10.0.0.0/8" ], "excludedCidr": [ "10.0.100.0/24" ] } } mode is disabled, detection, or prevention. idsRulesets is connectivity, balanced, or security. Suggested data print placement Nesting under the existing network object keeps it consistent with how VPNs, NAT, and QOS are already structured: Configuration.Networks[].Security.Malware.Mode Configuration.Networks[].Security.Malware.AllowedUrls[] Configuration.Networks[].Security.Malware.AllowedFiles[] Configuration.Networks[].Security.Intrusion.Mode Configuration.Networks[].Security.Intrusion.IdsRulesets Configuration.Networks[].Security.Intrusion.ProtectedNetworks Rolled-up org-level summary fields, in the style of the existing Firewall.Count and Users.Privileged.Count fields, would also be useful for at-a-glance metrics: Configuration.Security .AMPDisabled.Count Configuration.Security .IDSDisabled.Count Configuration.Security .IDSDetectionOnly.Count Implementation notes Both endpoints are MX-only. Calling them against a switch-only or wireless-only network returns an error, so the collection should be gated on productTypes containing appliance. In our environments that reduces the call volume substantially — most organizations have far fewer appliance networks than total networks. These are per-network calls, so the added cost is 2 × (appliance network count) per inspection. For a typical SMB organization of 1–5 appliance networks that is 2–10 additional requests. Both are GET only. No additional API scope or permission level is required beyond what the inspector already holds. If per-network call volume is a concern for very large organizations, collecting these behind an optional inspector toggle (similar to how per-device licensing data is handled) would still be far better than no coverage. Why this matters Security control drift is exactly the problem Liongard solves. AMP and IDS/IPS are licensed features customers pay for through Advanced Security. When a technician sets IDS to Detection while troubleshooting a false positive and never sets it back, or disables AMP to test a download, nothing in the dashboard flags it. The MX keeps passing traffic and the dashboard keeps looking healthy. As an MSP we have no way to detect that today short of manually opening every customer's Threat protection page. Detection-only mode is a silent failure. An MX with IDS set to Detection still generates security events, so the security center looks populated and active — while nothing is being blocked. This is arguably worse than fully disabled, because it looks fine. A metric that distinguishes prevention from detection would surface it immediately. Compliance and cyber insurance evidence. We are increasingly asked to attest that IPS and malware protection are enabled at the perimeter across a customer's sites. Right now that attestation is a manual screenshot exercise. With this data in the data print it becomes a standing metric with historical change evidence attached. Ruleset downgrades go unnoticed. Moving idsRulesets from Security or Balanced down to Connectivity materially weakens inspection and is a one-click change. What we would build with it Once the fields exist, this becomes a single metric and a single alert per customer: Metric — Meraki Networks With Threat Protection Off (Number): jmespath length(Configuration.Networks[?contains(productTypes, 'appliance') && (Security.Malware.Mode != 'enabled' || Security.Intrusion.Mode != 'prevention')][]) Metric — Meraki Threat Protection Offenders (String): jmespath Configuration.Networks[?contains(productTypes, 'appliance') && (Security.Malware.Mode != 'enabled' || Security.Intrusion.Mode != 'prevention')].name | join(', ', @) Alert: Number Greater Than 0, evaluated on change, with the offender list in the notification body. Secondary request If the security data node is being added anyway, content filtering (GET /networks/{networkId}/appliance/contentFiltering) has the same gap and the same justification — blocked URL categories and allow/block lists are also absent from the current data print.
0
·
Cisco Meraki
Load More
→