penetration testing

Performing Vulnerability Scanning with Nessus

Performs authenticated and unauthenticated vulnerability scanning using Tenable Nessus to identify known vulnerabilities, misconfigurations, default credentials, and missing patches across network infrastructure, servers, and applications. The scanner correlates findings with CVE databases and CVSS scores to produce prioritized remediation guidance. Activates for requests involving vulnerability scanning, Nessus assessment, patch compliance checking, or automated vulnerability detection.

cvenessuspatch-managementtenablevulnerability-scanning
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • Conducting initial vulnerability assessment during the reconnaissance phase of a penetration test
  • Performing periodic vulnerability scans to maintain compliance with PCI-DSS (requirement 11.2), HIPAA, or SOC 2 standards
  • Validating that remediation efforts have successfully addressed previously identified vulnerabilities
  • Establishing a baseline of known vulnerabilities before targeted manual exploitation
  • Auditing patch compliance and configuration drift across server and workstation fleets

Do not use as a substitute for manual penetration testing, against systems without written authorization, or against fragile systems (medical devices, legacy SCADA) where scanning may cause service disruption.

Prerequisites

  • Tenable Nessus Professional or Nessus Expert with current plugin updates (plugins should be less than 24 hours old)
  • Network connectivity to all target hosts on all ports (no firewall restrictions between scanner and targets)
  • Administrative credentials for authenticated scanning (domain admin or local admin for Windows, root/sudo for Linux, SNMP community strings for network devices)
  • Target IP ranges and hostnames documented in the scope agreement
  • Change management approval for scanning during authorized windows

Workflow

Step 1: Scan Configuration

Configure the Nessus scan policy based on engagement requirements:

  • Scan type selection: Choose "Advanced Scan" for full control over plugin families, or "Credentialed Patch Audit" for patch compliance. Avoid "Basic Network Scan" for penetration tests as it uses a limited plugin set.
  • Discovery settings: Configure port scanning to scan all 65,535 TCP ports and top 1,000 UDP ports. Set host discovery to use ARP (local), TCP SYN, and ICMP for maximum coverage.
  • Authentication: Add Windows credentials (domain account with local admin), SSH credentials (key-based preferred over password), SNMP credentials (v3 with authPriv preferred), and database credentials for database-specific checks.
  • Plugin configuration: Enable all plugin families relevant to the target environment. For penetration testing, ensure "Denial of Service" plugins are disabled unless explicitly authorized. Enable CGI scanning for web servers.
  • Performance settings: Set maximum concurrent hosts per scanner (default 30, reduce for sensitive networks), maximum concurrent checks per host (4-5 for production, higher for test environments), and network timeout values appropriate for the target network.

Step 2: Scan Execution and Monitoring

Launch the scan and monitor for issues:

  • Start the scan during the authorized testing window
  • Monitor scan progress through the Nessus web interface, checking for hosts timing out, authentication failures, or plugins causing errors
  • Watch for credential failures indicated by "Authentication Failure" results; these mean the authenticated scan fell back to unauthenticated mode, producing incomplete results
  • If specific hosts are crashing or becoming unresponsive, pause the scan, exclude those hosts, and report the issue to the client
  • For large networks (1,000+ hosts), consider splitting scans into smaller subnets to manage load and allow restartability

Step 3: Results Analysis and Validation

Analyze scan results to separate true positives from false positives:

  • Sort by severity: Start with Critical and High findings; these represent the most exploitable and impactful vulnerabilities
  • Validate authentication: Verify that plugin 19506 (Nessus Scan Information) shows "Credentialed checks: yes" for each host. Unauthenticated results miss local vulnerabilities.
  • Eliminate informational noise: Filter out informational findings unless they reveal useful information for manual testing (service banners, SSL certificate details, open ports)
  • Cross-reference CVEs: For each Critical/High finding, verify the CVE in the National Vulnerability Database. Check if the vulnerability has a public exploit (Exploit-DB, Metasploit module).
  • False positive identification: Common false positives include version-based detection where backported patches make the software appear vulnerable (common in RHEL/CentOS). Check rpm -q --changelog <package> on the target to verify.
  • Group by remediation: Organize findings by the action needed to fix them (e.g., "Apply Windows KB5034441" affects 47 hosts) rather than listing each instance individually

Step 4: Vulnerability Prioritization

Rank validated vulnerabilities for remediation using risk-based prioritization:

  • CVSS score: Use the CVSS v3.1 base score as the starting point. Scores 9.0-10.0 are Critical, 7.0-8.9 High, 4.0-6.9 Medium, 0.1-3.9 Low.
  • Exploit availability: Increase priority for vulnerabilities with publicly available exploit code, especially Metasploit modules or weaponized PoCs
  • Network exposure: A critical vulnerability on an internet-facing system is higher priority than the same vulnerability on an isolated internal server
  • Asset criticality: Consider the business value of the affected system. Domain controllers, databases with PII, and payment processing systems warrant higher priority.
  • Compensating controls: Reduce priority if the vulnerability is mitigated by network segmentation, WAF rules, or EDR protections (document the compensating control)

Step 5: Report Generation

Generate a comprehensive vulnerability scan report:

  • Export the Nessus report in both executive (PDF) and detailed (CSV/HTML) formats
  • Create a custom report that includes only validated findings with false positives removed
  • Include a remediation priority matrix mapping each vulnerability to its recommended fix, affected hosts, and timeline
  • Add context from manual validation (e.g., "This finding was confirmed exploitable during the penetration test")
  • Include scan metadata: date/time, scanner version, plugin set date, scan policy used, authentication success rate

Key Concepts

Term Definition
Authenticated Scan A vulnerability scan that uses valid credentials to log into target hosts and perform local checks, detecting significantly more vulnerabilities than unauthenticated scanning
Plugin A Nessus script that checks for a specific vulnerability, misconfiguration, or compliance item; Nessus maintains over 200,000 plugins updated daily
CVSS Common Vulnerability Scoring System; a standardized framework for rating the severity of vulnerabilities from 0.0 to 10.0 based on exploitability and impact metrics
False Positive A vulnerability reported by the scanner that does not actually exist on the target, often caused by version-based detection without exploit verification
Credentialed Patch Audit A scan type focused specifically on identifying missing operating system and application patches by comparing installed versions against known vulnerability databases
Plugin Family A logical grouping of Nessus plugins by category (e.g., Windows, Ubuntu Local Security Checks, Web Servers, Databases)

Tools & Systems

  • Nessus Professional: Commercial vulnerability scanner by Tenable with over 200,000 plugins covering CVEs, misconfigurations, and compliance checks
  • Nessus Expert: Extended version including external attack surface scanning, IaC scanning, and cloud infrastructure assessment
  • Tenable.io: Cloud-hosted vulnerability management platform for enterprise deployments with asset tracking, trend analysis, and prioritization
  • OpenVAS (Greenbone): Open-source alternative vulnerability scanner with community-maintained vulnerability tests for comparison scanning

Common Scenarios

Scenario: Quarterly PCI-DSS Vulnerability Scan for a Retail Company

Context: A retailer processes credit card payments and must comply with PCI-DSS requirement 11.2, which mandates quarterly internal and external vulnerability scans. The cardholder data environment (CDE) consists of 200 servers across 3 VLANs. All hosts run either Windows Server 2019/2022 or RHEL 8/9.

Approach:

  1. Configure authenticated scan with domain service account for Windows and SSH key for Linux hosts
  2. Use the PCI-DSS scan policy template with all relevant plugin families enabled
  3. Scan all 200 CDE hosts during the Saturday maintenance window (02:00-06:00)
  4. Identify 847 findings: 12 Critical, 34 High, 189 Medium, 612 Low/Informational
  5. Validate Critical findings: 3 are false positives (backported patches on RHEL), 9 are confirmed vulnerabilities
  6. Group remaining findings by remediation action: 6 require Windows patches, 2 require Apache upgrades, 1 requires TLS configuration hardening
  7. Generate PCI-compliant report showing no Critical or High vulnerabilities remain unaddressed (after remediation and rescan)

Pitfalls:

  • Running unauthenticated scans and missing the majority of local vulnerabilities, producing an incomplete compliance report
  • Not updating Nessus plugins before scanning, missing recently published CVEs
  • Scanning fragile legacy systems without reducing scan intensity, causing crashes or service disruption
  • Accepting Nessus results at face value without manually validating critical findings for false positives

Output Format

## Vulnerability Scan Summary - CDE Environment
 
**Scan Date**: 2025-11-15 02:00-05:47 UTC
**Scanner**: Nessus Professional 10.8.3 (Plugins: 2025-11-14)
**Hosts Scanned**: 200 (198 authenticated, 2 authentication failed)
**Scan Policy**: PCI-DSS Internal Scan
 
### Findings Summary
| Severity | Count | Validated |
|----------|-------|-----------|
| Critical | 12    | 9 (3 FP)  |
| High     | 34    | 31 (3 FP) |
| Medium   | 189   | 178       |
| Low/Info | 612   | N/A       |
 
### Top Critical Findings
 
**1. CVE-2024-21762 - Fortinet FortiOS Out-of-Bounds Write (CVSS 9.8)**
- Affected Hosts: fw-cde-01.corp.example.com (10.50.1.1)
- Exploit Available: Yes (Metasploit module)
- Remediation: Upgrade FortiOS to 7.4.3 or later
- Priority: Immediate - internet-facing device protecting CDE
 
**2. CVE-2024-6387 - OpenSSH regreSSHion (CVSS 8.1)**
- Affected Hosts: 14 Linux servers (see Appendix A)
- Exploit Available: Yes (public PoC)
- Remediation: Upgrade OpenSSH to 9.8p1 or later
- Priority: Within 7 days - authenticated remote code execution
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md2.4 KB

API Reference: Vulnerability Scanning with Nessus Agent

Overview

Manages Tenable Nessus vulnerability scans via the REST API: scan creation, launch, monitoring, result analysis, and CSV/PDF export.

Dependencies

Package Version Purpose
requests >= 2.28 HTTP client for Nessus REST API
urllib3 >= 1.26 TLS warning suppression

NessusAPI Class

Constructor

NessusAPI(url="https://localhost:8834", access_key=None, secret_key=None)

Authentication via X-ApiKeys header with access/secret key pair.

Methods

Method Description Returns
get_server_status() Check Nessus server readiness dict
list_scans() List all scans with id, name, status list[dict]
get_scan_details(scan_id) Full scan results with severity counts and top vulns dict
create_scan(name, targets, policy_id, template) Create new scan configuration dict
launch_scan(scan_id) Start a configured scan dict
get_scan_status(scan_id) Poll scan status str
wait_for_scan(scan_id, poll_interval, timeout) Block until scan completes bool
export_scan(scan_id, fmt) Export results as csv, html, or pdf bytes
check_auth_status(scan_id) Verify authenticated scanning via plugin 19506 list[dict]

Nessus REST API Endpoints

Endpoint Method Purpose
/server/status GET Server health check
/scans GET List all scans
/scans POST Create new scan
/scans/{id} GET Scan details and results
/scans/{id}/launch POST Launch scan
/scans/{id}/export POST Initiate report export
/scans/{id}/export/{file_id}/download GET Download exported report
/editor/scan/templates GET Available scan templates

Environment Variables

Variable Required Description
NESSUS_URL No Nessus server URL (default: https://localhost:8834)
NESSUS_ACCESS_KEY Yes API access key
NESSUS_SECRET_KEY Yes API secret key

Severity Mapping

Value Label CVSS Range
4 Critical 9.0-10.0
3 High 7.0-8.9
2 Medium 4.0-6.9
1 Low 0.1-3.9
0 Info N/A

Usage

export NESSUS_ACCESS_KEY="your-access-key"
export NESSUS_SECRET_KEY="your-secret-key"
python agent.py

Scripts 1

agent.py7.0 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Vulnerability scanning agent using the Nessus REST API."""

import json
import sys
import time
import os
import urllib3

try:
    import requests
except ImportError:
    print("Install: pip install requests")
    sys.exit(1)

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


class NessusAPI:
    def __init__(self, url=None, access_key=None, secret_key=None):
        url = url or os.environ.get("NESSUS_URL", "https://localhost:8834")
        self.url = url.rstrip("/")
        self.session = requests.Session()
        self.session.verify = False
        if access_key and secret_key:
            self.session.headers.update({
                "X-ApiKeys": f"accessKey={access_key}; secretKey={secret_key}"
            })

    def _get(self, endpoint):
        resp = self.session.get(f"{self.url}{endpoint}", timeout=30)
        resp.raise_for_status()
        return resp.json()

    def _post(self, endpoint, data=None):
        resp = self.session.post(f"{self.url}{endpoint}", json=data, timeout=30)
        resp.raise_for_status()
        return resp.json()

    def _put(self, endpoint, data=None):
        resp = self.session.put(f"{self.url}{endpoint}", json=data, timeout=30)
        resp.raise_for_status()
        return resp.json()

    def get_server_status(self):
        return self._get("/server/status")

    def list_scans(self):
        data = self._get("/scans")
        scans = []
        for scan in data.get("scans", []):
            scans.append({
                "id": scan["id"], "name": scan["name"],
                "status": scan["status"],
                "folder_id": scan.get("folder_id"),
            })
        return scans

    def get_scan_details(self, scan_id):
        data = self._get(f"/scans/{scan_id}")
        info = data.get("info", {})
        hosts = data.get("hosts", [])
        vulns = data.get("vulnerabilities", [])
        return {
            "scan_id": scan_id,
            "name": info.get("name"),
            "status": info.get("status"),
            "host_count": info.get("hostcount", len(hosts)),
            "targets": info.get("targets"),
            "start_time": info.get("scanner_start"),
            "end_time": info.get("scanner_end"),
            "policy": info.get("policy"),
            "severity_counts": {
                "critical": sum(1 for v in vulns if v.get("severity") == 4),
                "high": sum(1 for v in vulns if v.get("severity") == 3),
                "medium": sum(1 for v in vulns if v.get("severity") == 2),
                "low": sum(1 for v in vulns if v.get("severity") == 1),
                "info": sum(1 for v in vulns if v.get("severity") == 0),
            },
            "vulnerabilities": [
                {
                    "plugin_id": v["plugin_id"],
                    "name": v["plugin_name"],
                    "severity": v["severity"],
                    "count": v["count"],
                    "family": v.get("plugin_family"),
                }
                for v in sorted(vulns, key=lambda x: -x.get("severity", 0))[:50]
            ],
        }

    def create_scan(self, name, targets, policy_id=None, template="advanced"):
        templates = self._get("/editor/scan/templates")
        template_uuid = None
        for t in templates.get("templates", []):
            if t["name"] == template:
                template_uuid = t["uuid"]
                break
        if not template_uuid:
            template_uuid = templates["templates"][0]["uuid"]
        scan_config = {
            "uuid": template_uuid,
            "settings": {
                "name": name,
                "text_targets": targets,
                "launch_now": False,
            },
        }
        if policy_id:
            scan_config["settings"]["policy_id"] = policy_id
        return self._post("/scans", scan_config)

    def launch_scan(self, scan_id):
        return self._post(f"/scans/{scan_id}/launch")

    def get_scan_status(self, scan_id):
        data = self._get(f"/scans/{scan_id}")
        return data.get("info", {}).get("status", "unknown")

    def wait_for_scan(self, scan_id, poll_interval=30, timeout=7200):
        elapsed = 0
        while elapsed < timeout:
            status = self.get_scan_status(scan_id)
            if status == "completed":
                return True
            if status in ("canceled", "aborted"):
                return False
            time.sleep(poll_interval)
            elapsed += poll_interval
        return False

    def export_scan(self, scan_id, fmt="csv"):
        data = self._post(f"/scans/{scan_id}/export", {"format": fmt})
        file_id = data.get("file")
        if not file_id:
            return None
        while True:
            status = self._get(f"/scans/{scan_id}/export/{file_id}/status")
            if status.get("status") == "ready":
                break
            time.sleep(5)
        resp = self.session.get(f"{self.url}/scans/{scan_id}/export/{file_id}/download", timeout=30)
        return resp.content

    def check_auth_status(self, scan_id):
        """Check if authenticated scanning succeeded per host."""
        data = self._get(f"/scans/{scan_id}")
        auth_results = []
        for host in data.get("hosts", []):
            host_id = host["host_id"]
            host_detail = self._get(f"/scans/{scan_id}/hosts/{host_id}")
            auth_info = None
            for vuln in host_detail.get("vulnerabilities", []):
                if vuln["plugin_id"] == 19506:
                    auth_info = vuln
                    break
            auth_results.append({
                "hostname": host.get("hostname"),
                "host_id": host_id,
                "critical": host.get("critical", 0),
                "high": host.get("high", 0),
                "authenticated": auth_info is not None,
            })
        return auth_results


def print_scan_report(details):
    print("Vulnerability Scan Report")
    print("=" * 50)
    print(f"Scan: {details['name']}")
    print(f"Status: {details['status']}")
    print(f"Hosts: {details['host_count']}")
    print(f"Targets: {details['targets']}")
    sev = details["severity_counts"]
    print(f"\nSeverity Summary:")
    print(f"  Critical: {sev['critical']}")
    print(f"  High:     {sev['high']}")
    print(f"  Medium:   {sev['medium']}")
    print(f"  Low:      {sev['low']}")
    print(f"  Info:     {sev['info']}")
    print(f"\nTop Vulnerabilities:")
    for v in details["vulnerabilities"][:15]:
        sev_label = {4: "CRIT", 3: "HIGH", 2: "MED", 1: "LOW", 0: "INFO"}.get(v["severity"], "?")
        print(f"  [{sev_label}] {v['name']} (plugin {v['plugin_id']}, count: {v['count']})")


if __name__ == "__main__":
    nessus_url = os.environ.get("NESSUS_URL", "https://localhost:8834")
    access_key = os.environ.get("NESSUS_ACCESS_KEY", "")
    secret_key = os.environ.get("NESSUS_SECRET_KEY", "")
    api = NessusAPI(nessus_url, access_key, secret_key)
    scans = api.list_scans()
    if scans:
        details = api.get_scan_details(scans[0]["id"])
        print_scan_report(details)
    else:
        print("No scans found. Create one with api.create_scan()")
Keep exploring