vulnerability management

Performing Authenticated Vulnerability Scan

Authenticated (credentialed) vulnerability scanning uses valid system credentials to log into target hosts and perform deep inspection of installed software, patches, configurations, and security settings. Compared to unauthenticated scanning, credentialed scans detect 45-60% more vulnerabilities with significantly fewer false positives because they can directly query installed packages, registry keys, and file system contents.

authenticated-scanningcredentialscvenessusqualysriskvulnerability-management
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Authenticated (credentialed) vulnerability scanning uses valid system credentials to log into target hosts and perform deep inspection of installed software, patches, configurations, and security settings. Compared to unauthenticated scanning, credentialed scans detect 45-60% more vulnerabilities with significantly fewer false positives because they can directly query installed packages, registry keys, and file system contents.

When to Use

  • When conducting security assessments that involve performing authenticated vulnerability scan
  • When following incident response procedures for related security events
  • When performing scheduled security testing or auditing activities
  • When validating security controls through hands-on testing

Prerequisites

  • Vulnerability scanner (Nessus, Qualys, OpenVAS, Rapid7 InsightVM)
  • Service accounts with appropriate privileges on target systems
  • Secure credential storage (vault integration preferred)
  • Network access from scanner to target management ports
  • Written authorization from system owners

Core Concepts

Why Authenticated Scanning

Unauthenticated scanning can only assess externally visible services and banners, often leading to:

  • Missed vulnerabilities in locally installed software
  • Inaccurate version detection from banner changes
  • Inability to check patch levels, configurations, or local policies
  • Higher false positive rates due to inference-based detection

Authenticated scanning resolves these by directly querying the target OS.

Credential Types by Platform

Linux/Unix Systems

  • SSH Key Authentication: RSA/Ed25519 key pairs (recommended)
  • SSH Username/Password: Fallback for systems without key-based auth
  • Sudo/Su Elevation: Non-root user with sudo privileges
  • Certificate-based SSH: X.509 certificates for enterprise environments

Windows Systems

  • SMB (Windows): Domain or local admin credentials
  • WMI: Windows Management Instrumentation queries
  • WinRM: Windows Remote Management (HTTPS preferred)
  • Kerberos: Domain authentication with service tickets

Network Devices

  • SNMP v3: USM with authentication and privacy (AES-256)
  • SSH: For Cisco IOS, Juniper JunOS, Palo Alto PAN-OS
  • API Tokens: REST API for modern network platforms

Databases

  • Oracle: SYS/SYSDBA credentials or TNS connection
  • Microsoft SQL Server: Windows auth or SQL auth
  • PostgreSQL: Role-based authentication
  • MySQL: User/password with SELECT privileges

Workflow

Step 1: Create Dedicated Service Accounts

# Linux: Create scan service account
sudo useradd -m -s /bin/bash -c "Vulnerability Scanner Service Account" nessus_svc
sudo usermod -aG sudo nessus_svc
 
# Configure sudo for passwordless specific commands
echo 'nessus_svc ALL=(ALL) NOPASSWD: /usr/bin/dpkg -l, /usr/bin/rpm -qa, \
/bin/cat /etc/shadow, /usr/sbin/dmidecode, /usr/bin/find' | sudo tee /etc/sudoers.d/nessus_svc
 
# Generate SSH key pair
sudo -u nessus_svc ssh-keygen -t ed25519 -f /home/nessus_svc/.ssh/id_ed25519 -N ""
 
# Distribute public key to targets
for host in $(cat target_hosts.txt); do
    ssh-copy-id -i /home/nessus_svc/.ssh/id_ed25519.pub nessus_svc@$host
done
# Windows: Create scan service account via PowerShell
New-ADUser -Name "SVC_VulnScan" `
    -SamAccountName "SVC_VulnScan" `
    -UserPrincipalName "SVC_VulnScan@domain.local" `
    -Description "Vulnerability Scanner Service Account" `
    -PasswordNeverExpires $true `
    -CannotChangePassword $true `
    -Enabled $true `
    -AccountPassword (Read-Host -AsSecureString "Enter Password")
 
# Add to local Administrators group on targets via GPO or:
Add-ADGroupMember -Identity "Domain Admins" -Members "SVC_VulnScan"
# For least privilege, use a dedicated GPO for local admin rights instead
 
# Enable WinRM on targets
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Service\AllowRemote -Value $true
winrm set winrm/config/service '@{AllowUnencrypted="false"}'

Step 2: Configure Scanner Credentials

Nessus Configuration

{
  "credentials": {
    "add": {
      "Host": {
        "SSH": [{
          "auth_method": "public key",
          "username": "nessus_svc",
          "private_key": "/path/to/id_ed25519",
          "elevate_privileges_with": "sudo",
          "escalation_account": "root"
        }],
        "Windows": [{
          "auth_method": "Password",
          "username": "DOMAIN\\SVC_VulnScan",
          "password": "stored_in_vault",
          "domain": "domain.local"
        }],
        "SNMPv3": [{
          "username": "nessus_snmpv3",
          "security_level": "authPriv",
          "auth_algorithm": "SHA-256",
          "auth_password": "stored_in_vault",
          "priv_algorithm": "AES-256",
          "priv_password": "stored_in_vault"
        }]
      }
    }
  }
}

Step 3: Validate Credential Access

# Test SSH connectivity
ssh -i /path/to/key -o ConnectTimeout=10 nessus_svc@target_host "uname -a && sudo dpkg -l | head -5"
 
# Test WinRM connectivity
python3 -c "
import winrm
s = winrm.Session('target_host', auth=('DOMAIN\\\\SVC_VulnScan', 'password'), transport='ntlm')
r = s.run_cmd('systeminfo')
print(r.std_out.decode())
"
 
# Test SNMP v3 connectivity
snmpwalk -v3 -u nessus_snmpv3 -l authPriv -a SHA-256 -A authpass -x AES-256 -X privpass target_host sysDescr.0

Step 4: Run Authenticated Scan

Configure and launch the scan using the Nessus API:

# Create scan with credentials
curl -k -X POST https://nessus:8834/scans \
  -H "X-Cookie: token=$TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "uuid": "'$TEMPLATE_UUID'",
    "settings": {
      "name": "Authenticated Scan - Production",
      "text_targets": "192.168.1.0/24",
      "launch": "ON_DEMAND"
    },
    "credentials": {
      "add": {
        "Host": {
          "SSH": [{"auth_method": "public key", "username": "nessus_svc", "private_key": "/keys/id_ed25519"}],
          "Windows": [{"auth_method": "Password", "username": "DOMAIN\\SVC_VulnScan", "password": "vault_ref"}]
        }
      }
    }
  }'

Step 5: Verify Credential Success

After scan completion, check credential verification results:

  • Plugin 19506 (Nessus Scan Information): Shows credential status
  • Plugin 21745 (OS Security Patch Assessment): Confirms local checks
  • Plugin 117887 (Local Security Checks): Credential verification
  • Plugin 110385 (Nessus Credentialed Check): Target-level auth status

Credential Security Best Practices

  1. Use a secrets vault (HashiCorp Vault, CyberArk, AWS Secrets Manager) for credential storage
  2. Rotate credentials every 90 days or after personnel changes
  3. Principle of least privilege - only grant minimum required access
  4. Audit credential usage - monitor service account login events
  5. Encrypt in transit - use SSH keys over passwords, WinRM over HTTPS
  6. Separate accounts per scanner - never share credentials across tools
  7. Disable interactive login for scan service accounts where possible
  8. Log all authentication events for scan accounts in SIEM

Common Pitfalls

  • Using domain admin accounts instead of least-privilege service accounts
  • Storing credentials in plaintext scan configurations
  • Not testing credentials before scan launch (leads to wasted scan windows)
  • Forgetting to configure sudo/elevation for Linux targets
  • Windows UAC blocking remote credentialed checks
  • Firewall rules blocking WMI/WinRM/SSH between scanner and targets
  • Credential lockout from multiple failed authentication attempts
Source materials

References and resources

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

References 3

api-reference.md2.0 KB

Authenticated Vulnerability Scan — API Reference

Libraries

Library Install Purpose
requests pip install requests Nessus REST API client

Nessus REST API Authentication

Header: X-ApiKeys: accessKey=<key>; secretKey=<key>

Nessus API Endpoints

Method Endpoint Description
GET /scans List all scans
GET /scans/{id} Scan details with results
GET /scans/{id}/hosts/{host_id} Per-host vulnerability details
POST /scans Create new scan
POST /scans/{id}/launch Launch existing scan
POST /scans/{id}/export Export results (nessus/csv/html)
GET /policies List scan policies
GET /credentials List stored credentials

Severity Levels

Index Name 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 Informational

Credential Types for Authenticated Scans

Type Protocol Checks Enabled
SSH Linux/macOS Package versions, file permissions, configs
SMB Windows Patch levels, registry, installed software
ESXi VMware Hypervisor patches, VM configurations
SNMP Network devices Device firmware, community string audit
Database SQL Server/Oracle DB-level patches, user permissions

Key Nessus Plugin Families

Family Description
Windows: Microsoft Bulletins Microsoft security patches
Ubuntu Local Security Checks Ubuntu package vulnerabilities
CGI abuses Web application vulnerabilities
Misc. Miscellaneous security checks
Service detection Network service identification

External References

standards.md2.2 KB

Standards and References - Authenticated Vulnerability Scanning

Industry Standards

  • NIST SP 800-115: Technical Guide to Information Security Testing and Assessment
  • NIST SP 800-53 RA-5: Vulnerability Scanning (requires credentialed scanning for compliance)
  • CIS Controls v8 Control 7.5: Perform automated vulnerability scans of internal assets on a quarterly basis using authenticated scanning
  • PCI DSS v4.0 Req 11.3.1: Internal vulnerability scans must use authenticated scanning
  • DISA STIG: Requires credentialed scanning for compliance validation

Credential Management Standards

  • NIST SP 800-63B: Digital Identity Guidelines - Authentication and Lifecycle Management
  • CIS Controls v8 Control 5: Account Management
  • OWASP Credential Storage Cheat Sheet: Secure credential handling best practices

Scanner Documentation

Verification Plugins (Nessus)

Plugin ID Name Purpose
19506 Nessus Scan Information Shows scan metadata and credential status
21745 OS Security Patch Assessment Confirms local security checks enabled
117887 Local Security Checks Enabled Per-host credential verification
110385 Nessus Credentialed Check Detailed credential success/failure
10394 Microsoft Windows SMB Log In Possible Windows SMB auth verification
10180 Ping the Remote Host Host reachability confirmation

Minimum Privileges Required

Platform Minimum Privilege Notes
Linux Root or sudo user Sudo with NOPASSWD for specific commands
Windows Local Administrator Or domain account with local admin GPO
Cisco IOS Privilege 15 Enable mode access required
SNMP Read-only (v3 authPriv) SNMPv3 with encryption
Oracle DB SELECT ANY DICTIONARY Minimum for audit queries
PostgreSQL pg_read_all_settings Read-only role sufficient
workflows.md3.3 KB

Workflows - Authenticated Vulnerability Scanning

Workflow 1: Credential Preparation and Validation

┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│ Create Service   │────>│ Configure Least  │────>│ Test Credentials │
│ Accounts         │     │ Privilege Access  │     │ on Sample Hosts  │
└──────────────────┘     └──────────────────┘     └──────────────────┘

        ┌────────────────────────────────────────────────┘
        v
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│ Store in Secrets │────>│ Configure Scanner│────>│ Validate Auth    │
│ Vault            │     │ Credentials      │     │ Success Rate     │
└──────────────────┘     └──────────────────┘     └──────────────────┘

Workflow 2: Authenticated Scan Execution

  1. Pre-scan: Verify credentials, check network connectivity, confirm scan window
  2. Discovery: Host enumeration to identify live targets
  3. Authentication: Scanner authenticates to each target host
  4. Local Enumeration: Query installed packages, patches, configurations
  5. Vulnerability Assessment: Match local data against vulnerability database
  6. Report Generation: Compile findings with credential success metrics
  7. Post-scan: Verify no service disruption, archive results

Workflow 3: Credential Success Monitoring

Scan Completion

    ├──> Check Plugin 117887 (Local Security Checks)
    │        │
    │        ├──> SUCCESS: Proceed to analyze findings
    │        └──> FAILURE: Investigate cause
    │                 │
    │                 ├──> Network connectivity issue
    │                 ├──> Credential expired or changed
    │                 ├──> Firewall blocking management ports
    │                 ├──> Account locked out
    │                 └──> Insufficient privileges

    └──> Calculate Credential Success Rate

             ├──> Target: >95% authenticated hosts
             ├──> Alert if <90% success rate
             └──> Document exceptions for failed hosts

Workflow 4: Credential Lifecycle Management

Phase Action Frequency
Provisioning Create accounts with least privilege One-time
Distribution Deploy keys/passwords to scanner One-time
Validation Test connectivity before scans Per scan
Rotation Change passwords, rotate keys 90 days
Monitoring Audit login events in SIEM Continuous
Deprovisioning Remove accounts when scanner retired As needed

Scripts 2

agent.py6.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Authenticated vulnerability scan orchestration agent using Nessus API."""

import json
import os
import sys
import argparse
from datetime import datetime

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


class NessusClient:
    """Client for Tenable Nessus REST API."""

    def __init__(self, url, access_key, secret_key):
        self.base_url = url.rstrip("/")
        self.headers = {
            "X-ApiKeys": f"accessKey={access_key}; secretKey={secret_key}",
            "Content-Type": "application/json",
        }

    def _get(self, path, params=None):
        resp = requests.get(f"{self.base_url}{path}", headers=self.headers,
                            params=params,
                            verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
        resp.raise_for_status()
        return resp.json()

    def _post(self, path, data=None):
        resp = requests.post(f"{self.base_url}{path}", headers=self.headers,
                             json=data,
                             verify=not os.environ.get("SKIP_TLS_VERIFY", "").lower() == "true", timeout=30)  # Set SKIP_TLS_VERIFY=true for self-signed certs in lab environments
        resp.raise_for_status()
        return resp.json()

    def list_scans(self):
        return self._get("/scans").get("scans", [])

    def get_scan_details(self, scan_id):
        return self._get(f"/scans/{scan_id}")

    def list_policies(self):
        return self._get("/policies").get("policies", [])

    def list_credentials(self):
        return self._get("/credentials").get("credentials", [])

    def get_scan_results(self, scan_id):
        details = self.get_scan_details(scan_id)
        hosts = details.get("hosts", [])
        vulns = details.get("vulnerabilities", [])
        return {"hosts": hosts, "vulnerabilities": vulns, "info": details.get("info", {})}

    def get_host_vulnerabilities(self, scan_id, host_id):
        return self._get(f"/scans/{scan_id}/hosts/{host_id}")

    def export_scan(self, scan_id, fmt="nessus"):
        data = {"format": fmt}
        resp = self._post(f"/scans/{scan_id}/export", data)
        return resp.get("file", 0)


def analyze_scan_results(results):
    """Analyze scan results and categorize findings."""
    vulns = results.get("vulnerabilities", [])
    severity_map = {0: "Info", 1: "Low", 2: "Medium", 3: "High", 4: "Critical"}
    severity_counts = {"Critical": 0, "High": 0, "Medium": 0, "Low": 0, "Info": 0}

    categorized = []
    for v in vulns:
        sev = severity_map.get(v.get("severity", 0), "Info")
        severity_counts[sev] += 1
        categorized.append({
            "plugin_id": v.get("plugin_id", 0),
            "plugin_name": v.get("plugin_name", ""),
            "severity": sev,
            "severity_index": v.get("severity", 0),
            "count": v.get("count", 0),
            "family": v.get("plugin_family", ""),
        })

    categorized.sort(key=lambda x: x["severity_index"], reverse=True)
    return {"severity_counts": severity_counts, "vulnerabilities": categorized}


def audit_credential_coverage(results):
    """Check if authenticated scan achieved credential coverage."""
    findings = []
    hosts = results.get("hosts", [])
    for host in hosts:
        host_info = host.get("info", {})
        credentialed = host.get("credentialed_checks_running", "")
        if not credentialed or credentialed == "no":
            findings.append({
                "host": host.get("hostname", host.get("host_id", "")),
                "issue": "Credentialed checks not running — scan is unauthenticated",
                "severity": "HIGH",
                "detail": "Configure valid credentials for this host",
            })
    return findings


def compare_auth_vs_unauth(auth_results, unauth_results):
    """Compare authenticated vs unauthenticated scan finding counts."""
    auth_vulns = len(auth_results.get("vulnerabilities", []))
    unauth_vulns = len(unauth_results.get("vulnerabilities", []))
    improvement = ((auth_vulns - unauth_vulns) / max(unauth_vulns, 1)) * 100
    return {
        "authenticated_findings": auth_vulns,
        "unauthenticated_findings": unauth_vulns,
        "improvement_pct": round(improvement, 1),
        "additional_findings": auth_vulns - unauth_vulns,
    }


def run_audit(args):
    """Execute authenticated vulnerability scan audit."""
    print(f"\n{'='*60}")
    print(f"  AUTHENTICATED VULNERABILITY SCAN AUDIT")
    print(f"  Generated: {datetime.utcnow().isoformat()} UTC")
    print(f"{'='*60}\n")

    client = NessusClient(args.nessus_url, args.access_key, args.secret_key)
    report = {}

    scans = client.list_scans()
    report["total_scans"] = len(scans) if scans else 0
    print(f"--- AVAILABLE SCANS ({report['total_scans']}) ---")
    for s in (scans or [])[:10]:
        print(f"  [{s.get('status','')}] {s.get('name','')}: {s.get('id','')}")

    if args.scan_id:
        results = client.get_scan_results(args.scan_id)
        analysis = analyze_scan_results(results)
        report["analysis"] = analysis
        counts = analysis["severity_counts"]
        print(f"\n--- SCAN RESULTS (ID: {args.scan_id}) ---")
        print(f"  Critical: {counts['Critical']} | High: {counts['High']} | "
              f"Medium: {counts['Medium']} | Low: {counts['Low']}")
        print(f"\n--- TOP VULNERABILITIES ---")
        for v in analysis["vulnerabilities"][:15]:
            print(f"  [{v['severity']}] {v['plugin_name'][:70]} (x{v['count']})")

        cred_check = audit_credential_coverage(results)
        report["credential_coverage"] = cred_check
        if cred_check:
            print(f"\n--- CREDENTIAL COVERAGE ISSUES ({len(cred_check)}) ---")
            for c in cred_check:
                print(f"  [{c['severity']}] {c['host']}: {c['issue']}")
        else:
            print(f"\n  Credential coverage: All hosts authenticated")

    return report


def main():
    parser = argparse.ArgumentParser(description="Authenticated Vulnerability Scan Agent")
    parser.add_argument("--nessus-url", required=True, help="Nessus server URL")
    parser.add_argument("--access-key", required=True, help="Nessus API access key")
    parser.add_argument("--secret-key", required=True, help="Nessus API secret key")
    parser.add_argument("--scan-id", type=int, help="Scan ID to analyze results")
    parser.add_argument("--output", help="Save report to JSON file")
    args = parser.parse_args()

    report = run_audit(args)
    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2, default=str)
        print(f"\n[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
process.py14.2 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Authenticated Vulnerability Scan Credential Validator and Manager

Pre-validates scanner credentials against target hosts before launching
vulnerability scans to ensure maximum authenticated coverage.

Requirements:
    pip install paramiko pywinrm pysnmp pandas

Usage:
    python process.py validate --targets targets.txt --creds creds.json
    python process.py report --nessus-file scan_results.nessus
"""

import argparse
import json
import socket
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from pathlib import Path

import pandas as pd

try:
    import paramiko
except ImportError:
    paramiko = None

try:
    import winrm
except ImportError:
    winrm = None


class CredentialValidator:
    """Validate scanner credentials against target hosts."""

    def __init__(self, timeout: int = 10):
        self.timeout = timeout
        self.results = []

    def check_port(self, host: str, port: int) -> bool:
        """Check if a TCP port is open on the target host."""
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(self.timeout)
            result = sock.connect_ex((host, port))
            sock.close()
            return result == 0
        except (socket.error, OSError):
            return False

    def validate_ssh(self, host: str, username: str, password: str = None,
                     key_file: str = None, port: int = 22) -> dict:
        """Validate SSH credentials against a target host."""
        result = {
            "host": host, "protocol": "SSH", "port": port,
            "username": username, "status": "UNKNOWN", "details": ""
        }

        if not paramiko:
            result["status"] = "SKIP"
            result["details"] = "paramiko not installed"
            return result

        if not self.check_port(host, port):
            result["status"] = "FAIL"
            result["details"] = f"Port {port} not reachable"
            return result

        try:
            client = paramiko.SSHClient()
            client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

            connect_kwargs = {
                "hostname": host, "port": port, "username": username,
                "timeout": self.timeout, "allow_agent": False, "look_for_keys": False
            }

            if key_file:
                connect_kwargs["key_filename"] = key_file
            elif password:
                connect_kwargs["password"] = password
            else:
                result["status"] = "FAIL"
                result["details"] = "No password or key file provided"
                return result

            client.connect(**connect_kwargs)

            # Test command execution
            _, stdout, stderr = client.exec_command("id && uname -a", timeout=10)
            output = stdout.read().decode().strip()
            error = stderr.read().decode().strip()

            # Test sudo access
            _, stdout_sudo, stderr_sudo = client.exec_command(
                "sudo -n id 2>&1", timeout=10
            )
            sudo_output = stdout_sudo.read().decode().strip()

            has_sudo = "uid=0" in sudo_output
            client.close()

            result["status"] = "SUCCESS"
            result["details"] = f"Auth OK. Sudo: {'Yes' if has_sudo else 'No'}. {output[:100]}"
            result["has_sudo"] = has_sudo

        except paramiko.AuthenticationException:
            result["status"] = "FAIL"
            result["details"] = "Authentication failed - invalid credentials"
        except paramiko.SSHException as e:
            result["status"] = "FAIL"
            result["details"] = f"SSH error: {str(e)[:100]}"
        except Exception as e:
            result["status"] = "FAIL"
            result["details"] = f"Connection error: {str(e)[:100]}"

        return result

    def validate_winrm(self, host: str, username: str, password: str,
                       port: int = 5985, use_ssl: bool = False) -> dict:
        """Validate WinRM credentials against a Windows target."""
        result = {
            "host": host, "protocol": "WinRM", "port": port,
            "username": username, "status": "UNKNOWN", "details": ""
        }

        if not winrm:
            result["status"] = "SKIP"
            result["details"] = "pywinrm not installed"
            return result

        check_port = 5986 if use_ssl else port
        if not self.check_port(host, check_port):
            result["status"] = "FAIL"
            result["details"] = f"Port {check_port} not reachable"
            return result

        try:
            scheme = "https" if use_ssl else "http"
            session = winrm.Session(
                f"{scheme}://{host}:{check_port}/wsman",
                auth=(username, password),
                transport="ntlm",
                server_cert_validation="ignore" if use_ssl else "validate"
            )
            r = session.run_cmd("whoami")
            output = r.std_out.decode().strip()

            # Check admin privileges
            r_admin = session.run_cmd("net", ["localgroup", "Administrators"])
            admin_output = r_admin.std_out.decode()

            is_admin = username.split("\\")[-1].lower() in admin_output.lower()

            result["status"] = "SUCCESS"
            result["details"] = f"Auth OK as {output}. Admin: {'Yes' if is_admin else 'No'}"
            result["is_admin"] = is_admin

        except Exception as e:
            result["status"] = "FAIL"
            result["details"] = f"WinRM error: {str(e)[:150]}"

        return result

    def validate_smb(self, host: str, username: str, password: str,
                     domain: str = "", port: int = 445) -> dict:
        """Validate SMB credentials against a Windows target."""
        result = {
            "host": host, "protocol": "SMB", "port": port,
            "username": username, "status": "UNKNOWN", "details": ""
        }

        if not self.check_port(host, port):
            result["status"] = "FAIL"
            result["details"] = f"Port {port} not reachable"
            return result

        try:
            from impacket.smbconnection import SMBConnection
            conn = SMBConnection(host, host, sess_port=port)
            conn.login(username, password, domain)
            shares = conn.listShares()
            share_names = [s["shi1_netname"].rstrip("\x00") for s in shares]
            conn.logoff()

            result["status"] = "SUCCESS"
            result["details"] = f"Auth OK. Shares: {', '.join(share_names[:5])}"

        except ImportError:
            result["status"] = "SKIP"
            result["details"] = "impacket not installed"
        except Exception as e:
            result["status"] = "FAIL"
            result["details"] = f"SMB error: {str(e)[:150]}"

        return result

    def validate_snmpv3(self, host: str, username: str, auth_password: str,
                        priv_password: str, port: int = 161) -> dict:
        """Validate SNMPv3 credentials against a target."""
        result = {
            "host": host, "protocol": "SNMPv3", "port": port,
            "username": username, "status": "UNKNOWN", "details": ""
        }

        try:
            from pysnmp.hlapi import (
                SnmpEngine, UsmUserData, UdpTransportTarget,
                ContextData, ObjectType, ObjectIdentity, getCmd,
                usmHMACSHAAuthProtocol, usmAesCfb128Protocol
            )

            iterator = getCmd(
                SnmpEngine(),
                UsmUserData(username, auth_password, priv_password,
                            authProtocol=usmHMACSHAAuthProtocol,
                            privProtocol=usmAesCfb128Protocol),
                UdpTransportTarget((host, port), timeout=self.timeout),
                ContextData(),
                ObjectType(ObjectIdentity("SNMPv2-MIB", "sysDescr", 0))
            )

            errorIndication, errorStatus, errorIndex, varBinds = next(iterator)

            if errorIndication:
                result["status"] = "FAIL"
                result["details"] = f"SNMP error: {errorIndication}"
            elif errorStatus:
                result["status"] = "FAIL"
                result["details"] = f"SNMP status: {errorStatus.prettyPrint()}"
            else:
                for varBind in varBinds:
                    result["status"] = "SUCCESS"
                    result["details"] = f"Auth OK. sysDescr: {str(varBind[1])[:100]}"

        except ImportError:
            result["status"] = "SKIP"
            result["details"] = "pysnmp not installed"
        except Exception as e:
            result["status"] = "FAIL"
            result["details"] = f"SNMP error: {str(e)[:150]}"

        return result

    def validate_all(self, targets: list, credentials: dict, max_workers: int = 20) -> list:
        """Validate credentials against all targets in parallel."""
        self.results = []
        tasks = []

        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            for target in targets:
                host = target.strip()
                if not host:
                    continue

                # SSH validation
                if "ssh" in credentials:
                    cred = credentials["ssh"]
                    tasks.append(executor.submit(
                        self.validate_ssh, host, cred["username"],
                        cred.get("password"), cred.get("key_file"),
                        cred.get("port", 22)
                    ))

                # WinRM validation
                if "winrm" in credentials:
                    cred = credentials["winrm"]
                    tasks.append(executor.submit(
                        self.validate_winrm, host, cred["username"],
                        cred["password"], cred.get("port", 5985),
                        cred.get("use_ssl", False)
                    ))

                # SMB validation
                if "smb" in credentials:
                    cred = credentials["smb"]
                    tasks.append(executor.submit(
                        self.validate_smb, host, cred["username"],
                        cred["password"], cred.get("domain", ""),
                        cred.get("port", 445)
                    ))

                # SNMPv3 validation
                if "snmpv3" in credentials:
                    cred = credentials["snmpv3"]
                    tasks.append(executor.submit(
                        self.validate_snmpv3, host, cred["username"],
                        cred["auth_password"], cred["priv_password"],
                        cred.get("port", 161)
                    ))

            for future in as_completed(tasks):
                try:
                    result = future.result()
                    self.results.append(result)
                    status_icon = "[+]" if result["status"] == "SUCCESS" else "[-]"
                    print(f"  {status_icon} {result['host']}:{result['port']} "
                          f"({result['protocol']}) - {result['status']}: {result['details'][:80]}")
                except Exception as e:
                    print(f"  [!] Validation error: {e}")

        return self.results

    def generate_report(self, output_path: str = None) -> pd.DataFrame:
        """Generate validation report."""
        df = pd.DataFrame(self.results)

        if df.empty:
            print("[-] No validation results to report")
            return df

        print("\n" + "=" * 70)
        print("CREDENTIAL VALIDATION SUMMARY")
        print("=" * 70)

        total = len(df)
        success = len(df[df["status"] == "SUCCESS"])
        fail = len(df[df["status"] == "FAIL"])
        skip = len(df[df["status"] == "SKIP"])

        print(f"Total Checks:  {total}")
        print(f"  SUCCESS:     {success} ({success/total*100:.1f}%)")
        print(f"  FAIL:        {fail} ({fail/total*100:.1f}%)")
        print(f"  SKIPPED:     {skip} ({skip/total*100:.1f}%)")

        if success / max(total, 1) < 0.90:
            print("\n[WARNING] Credential success rate below 90% - investigate failures before scanning")

        # Protocol breakdown
        print("\nBy Protocol:")
        for proto in df["protocol"].unique():
            proto_df = df[df["protocol"] == proto]
            proto_success = len(proto_df[proto_df["status"] == "SUCCESS"])
            print(f"  {proto}: {proto_success}/{len(proto_df)} "
                  f"({proto_success/len(proto_df)*100:.1f}%)")

        # Failed hosts
        failures = df[df["status"] == "FAIL"]
        if not failures.empty:
            print(f"\nFailed Hosts ({len(failures)}):")
            for _, row in failures.iterrows():
                print(f"  {row['host']}:{row['port']} ({row['protocol']}): {row['details'][:80]}")

        if output_path:
            df.to_csv(output_path, index=False)
            print(f"\n[+] Report saved to: {output_path}")

        return df


def main():
    parser = argparse.ArgumentParser(description="Authenticated Scan Credential Validator")
    subparsers = parser.add_subparsers(dest="command")

    # Validate command
    val_parser = subparsers.add_parser("validate", help="Validate credentials against targets")
    val_parser.add_argument("--targets", required=True, help="File with target IPs (one per line)")
    val_parser.add_argument("--creds", required=True, help="JSON file with credentials")
    val_parser.add_argument("--output", default=None, help="Output CSV report path")
    val_parser.add_argument("--workers", type=int, default=20, help="Max parallel workers")
    val_parser.add_argument("--timeout", type=int, default=10, help="Connection timeout seconds")

    args = parser.parse_args()

    if args.command == "validate":
        with open(args.targets) as f:
            targets = [line.strip() for line in f if line.strip() and not line.startswith("#")]

        with open(args.creds) as f:
            credentials = json.load(f)

        print(f"[*] Validating credentials against {len(targets)} targets")
        print(f"[*] Protocols: {', '.join(credentials.keys())}")

        validator = CredentialValidator(timeout=args.timeout)
        validator.validate_all(targets, credentials, max_workers=args.workers)

        output = args.output or f"cred_validation_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
        validator.generate_report(output)

    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.3 KB
Keep exploring