Configure and execute agentless vulnerability scanning using network protocols, cloud snapshot analysis, and API-based discovery to assess systems without installing endpoint agents.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Configure and execute agentless vulnerability scanning using network protocols, cloud snapshot analysis, and API-based discovery to assess systems without installing endpoint agents.
Agentless vulnerability scanning assesses systems for security weaknesses without requiring endpoint agent installation. This approach leverages existing network protocols (SSH for Linux, WMI for Windows), cloud provider APIs for snapshot-based analysis, and authenticated remote checks. Modern cloud platforms like Microsoft Defender for Cloud, Wiz, Datadog, and Tenable perform out-of-band analysis by taking disk snapshots and examining OS configurations and installed packages offline. The open-source tool Vuls provides agentless scanning based on NVD and OVAL data for Linux/FreeBSD systems. This skill covers configuring agentless scans across on-premises, cloud, and containerized environments.
When to Use
When conducting security assessments that involve performing agentless vulnerability scanning
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
SSH key-based authentication configured on Linux/Unix targets
WMI/WinRM access on Windows targets with appropriate credentials
Cloud provider API credentials (AWS IAM, Azure RBAC, GCP IAM)
Network access from scanner to target systems on required ports
Service account with read-only access to target system configurations
Python 3.8+ for custom scanning automation
Core Concepts
Agentless vs Agent-Based Scanning
Aspect
Agentless
Agent-Based
Deployment
No software installation needed
Agent install on every endpoint
Network dependency
Requires network connectivity
Works offline with cloud sync
Performance impact
Minimal on target systems
Light continuous overhead
Coverage depth
Depends on protocol/credentials
Deep local access
Cloud snapshot analysis
Native capability
Not applicable
Ideal for
Cloud VMs, IoT, legacy systems, OT
Managed endpoints, laptops
Agentless Scanning Methods
Method
Protocol
Target OS
Port
Use Case
SSH Remote Commands
SSH
Linux/Unix
22
Package enumeration, config audit
WMI Remote Query
WMI/DCOM
Windows
135, 445
Hotfix enumeration, registry checks
WinRM PowerShell
WS-Man
Windows
5985/5986
Remote command execution
SNMP Community
SNMP v2c/v3
Network devices
161
Device fingerprinting, firmware check
Cloud Snapshot
Provider API
Cloud VMs
N/A
Disk image analysis
Container Registry
HTTPS
Container images
443
Image vulnerability scanning
API-Based
REST/HTTPS
SaaS/Cloud
443
Configuration assessment
Cloud Snapshot Analysis Flow
1. Scanner requests disk snapshot via cloud API
2. Cloud provider creates snapshot of VM root + data disks
3. Scanner mounts snapshot in isolated analysis environment
4. Scanner examines OS packages, configurations, file system
5. Snapshot is deleted after analysis (no persistent copies)
6. Results sent to central management console
Workflow
Step 1: SSH-Based Agentless Scanning (Linux)
# Create dedicated scan SSH key pair
ssh-keygen -t ed25519 -f /opt/scanner/.ssh/scan_key -N "" \
-C "vuln-scanner@security.local"# Deploy public key to targets via Ansible# ansible-playbook deploy_scan_key.yml# Test connectivity to target
ssh -i /opt/scanner/.ssh/scan_key -o ConnectTimeout=10 \
scanner@target-host "cat /etc/os-release && dpkg -l 2>/dev/null || rpm -qa"
import paramiko
import json
classAgentlessLinuxScanner:
"""SSH-based agentless vulnerability scanner for Linux systems."""def__init__(self, key_path):
self.key_path = key_path
defconnect(self, hostname, username="scanner", port=22):
"""Establish SSH connection to target."""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
key = paramiko.Ed25519Key.from_private_key_file(self.key_path)
client.connect(hostname, port=port, username=username, pkey=key,
timeout=30, banner_timeout=30)
return client
defget_os_info(self, client):
"""Detect OS type and version."""
_, stdout, _ = client.exec_command("cat /etc/os-release", timeout=10)
os_release = stdout.read().decode()
info = {}
for line in os_release.strip().split("\n"):
if"="in line:
key, val = line.split("=", 1)
info[key] = val.strip('"')
return info
defget_installed_packages(self, client):
"""Enumerate installed packages."""# Try dpkg (Debian/Ubuntu)
_, stdout, _ = client.exec_command(
"dpkg-query -W -f='${Package}|${Version}|${Architecture}\\n'",
timeout=30
)
output = stdout.read().decode().strip()
if output:
packages = []
for line in output.split("\n"):
parts = line.split("|")
iflen(parts) >= 2:
packages.append({
"name": parts[0],
"version": parts[1],
"arch": parts[2] iflen(parts) > 2else"",
"manager": "dpkg"
})
return packages
# Try rpm (RHEL/CentOS/Fedora)
_, stdout, _ = client.exec_command(
"rpm -qa --queryformat '%{NAME}|%{VERSION}-%{RELEASE}|%{ARCH}\\n'",
timeout=30
)
output = stdout.read().decode().strip()
packages = []
for line in output.split("\n"):
parts = line.split("|")
iflen(parts) >= 2:
packages.append({
"name": parts[0],
"version": parts[1],
"arch": parts[2] iflen(parts) > 2else"",
"manager": "rpm"
})
return packages
defcheck_kernel_version(self, client):
"""Get running kernel version."""
_, stdout, _ = client.exec_command("uname -r", timeout=10)
return stdout.read().decode().strip()
defcheck_listening_ports(self, client):
"""Enumerate listening network services."""
_, stdout, _ = client.exec_command(
"ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null",
timeout=10
)
return stdout.read().decode().strip()
defscan_host(self, hostname, username="scanner"):
"""Perform full agentless scan of a host."""print(f"[*] Scanning {hostname}...")
client = self.connect(hostname, username)
result = {
"hostname": hostname,
"os_info": self.get_os_info(client),
"kernel": self.check_kernel_version(client),
"packages": self.get_installed_packages(client),
"listening_ports": self.check_listening_ports(client),
}
client.close()
print(f" [+] Found {len(result['packages'])} packages on {hostname}")
return result
Step 2: WinRM-Based Agentless Scanning (Windows)
import winrm
classAgentlessWindowsScanner:
"""WinRM-based agentless vulnerability scanner for Windows."""def__init__(self, username, password, domain=None):
self.username = username
self.password = password
self.domain = domain
defconnect(self, hostname, use_ssl=True):
"""Create WinRM session."""
port = 5986if use_ssl else5985
transport = "ntlm"
user = f"{self.domain}\\{self.username}"ifself.domain elseself.username
session = winrm.Session(
f"{'https'if use_ssl else'http'}://{hostname}:{port}/wsman",
auth=(user, self.password),
transport=transport,
server_cert_validation="ignore"
)
return session
defget_installed_hotfixes(self, session):
"""Get installed Windows updates/hotfixes."""
cmd = "Get-HotFix | Select-Object HotFixID,InstalledOn,Description | ConvertTo-Json"
result = session.run_ps(cmd)
if result.status_code == 0:
return json.loads(result.std_out.decode())
return []
defget_installed_software(self, session):
"""Enumerate installed software from registry."""
cmd = """
$paths = @(
'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*',
'HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*'
)
Get-ItemProperty $paths -ErrorAction SilentlyContinue |
Where-Object {$_.DisplayName} |
Select-Object DisplayName, DisplayVersion, Publisher |
ConvertTo-Json
"""
result = session.run_ps(cmd)
if result.status_code == 0:
return json.loads(result.std_out.decode())
return []
defget_os_info(self, session):
"""Get Windows OS details."""
cmd = "Get-CimInstance Win32_OperatingSystem | Select-Object Caption,Version,BuildNumber,OSArchitecture | ConvertTo-Json"
result = session.run_ps(cmd)
if result.status_code == 0:
return json.loads(result.std_out.decode())
return {}
defscan_host(self, hostname):
"""Perform full agentless scan of Windows host."""print(f"[*] Scanning {hostname} via WinRM...")
session = self.connect(hostname)
result = {
"hostname": hostname,
"os_info": self.get_os_info(session),
"hotfixes": self.get_installed_hotfixes(session),
"software": self.get_installed_software(session),
}
print(f" [+] Found {len(result['hotfixes'])} hotfixes, "f"{len(result['software'])} software entries")
return result
Step 3: Cloud Snapshot Scanning (AWS)
import boto3
import time
classAWSSnapshotScanner:
"""AWS EC2 agentless snapshot-based vulnerability scanner."""def__init__(self, region="us-east-1"):
self.ec2 = boto3.client("ec2", region_name=region)
defcreate_snapshot(self, volume_id, description="Security scan snapshot"):
"""Create EBS snapshot for analysis."""
snapshot = self.ec2.create_snapshot(
VolumeId=volume_id,
Description=description,
TagSpecifications=[{
"ResourceType": "snapshot",
"Tags": [
{"Key": "Purpose", "Value": "VulnScan"},
{"Key": "AutoDelete", "Value": "true"},
]
}]
)
snapshot_id = snapshot["SnapshotId"]
print(f" [*] Creating snapshot {snapshot_id} from {volume_id}...")
waiter = self.ec2.get_waiter("snapshot_completed")
waiter.wait(SnapshotIds=[snapshot_id])
print(f" [+] Snapshot {snapshot_id} ready")
return snapshot_id
defdelete_snapshot(self, snapshot_id):
"""Clean up snapshot after analysis."""self.ec2.delete_snapshot(SnapshotId=snapshot_id)
print(f" [+] Deleted snapshot {snapshot_id}")
defscan_instance(self, instance_id):
"""Scan an EC2 instance via snapshot analysis."""print(f"[*] Agentless scan of instance {instance_id}")
instance = self.ec2.describe_instances(
InstanceIds=[instance_id]
)["Reservations"][0]["Instances"][0]
root_volume = Nonefor bdm in instance.get("BlockDeviceMappings", []):
if bdm["DeviceName"] == instance.get("RootDeviceName"):
root_volume = bdm["Ebs"]["VolumeId"]
breakifnot root_volume:
print(" [!] No root volume found")
returnNone
snapshot_id = self.create_snapshot(root_volume)
try:
# Analysis would be performed here# Mount snapshot, examine packages, check configs
result = {
"instance_id": instance_id,
"snapshot_id": snapshot_id,
"root_volume": root_volume,
"platform": instance.get("Platform", "linux"),
"state": instance["State"]["Name"],
}
return result
finally:
self.delete_snapshot(snapshot_id)