npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
无代理漏洞扫描(Agentless vulnerability scanning)无需在端点安装 Agent 即可评估系统安全弱点。该方法利用现有网络协议(Linux 使用 SSH、Windows 使用 WMI)、云服务商 API 进行基于快照的分析,以及经身份验证的远程检查。Microsoft Defender for Cloud、Wiz、Datadog 和 Tenable 等现代云平台通过获取磁盘快照并离线检查操作系统配置和已安装软件包,实现带外分析(out-of-band analysis)。开源工具 Vuls 基于 NVD 和 OVAL 数据为 Linux/FreeBSD 系统提供无代理扫描。本技能涵盖在本地、云端和容器化环境中配置无代理扫描。
Configure and execute agentless vulnerability scans using SSH/WMI protocols, cloud APIs/snapshots, and tools like Vuls/Tenable for on-prem/cloud/container systems.
Configures and executes agentless vulnerability scans via SSH, WMI/WinRM, cloud APIs, and snapshots for Linux, Windows, and cloud systems without endpoint agents.
Deploys and configures Rapid7 InsightVM Security Console and Scan Engines for authenticated/unauthenticated vulnerability scanning in enterprise networks. Useful for vulnerability management setups.
Share bugs, ideas, or general feedback.
无代理漏洞扫描(Agentless vulnerability scanning)无需在端点安装 Agent 即可评估系统安全弱点。该方法利用现有网络协议(Linux 使用 SSH、Windows 使用 WMI)、云服务商 API 进行基于快照的分析,以及经身份验证的远程检查。Microsoft Defender for Cloud、Wiz、Datadog 和 Tenable 等现代云平台通过获取磁盘快照并离线检查操作系统配置和已安装软件包,实现带外分析(out-of-band analysis)。开源工具 Vuls 基于 NVD 和 OVAL 数据为 Linux/FreeBSD 系统提供无代理扫描。本技能涵盖在本地、云端和容器化环境中配置无代理扫描。
| 对比维度 | 无代理扫描 | 基于 Agent 扫描 |
|---|---|---|
| 部署方式 | 无需安装软件 | 需在每个端点安装 Agent |
| 网络依赖 | 需要网络连接 | 可离线运行并通过云同步 |
| 性能影响 | 对目标系统影响极小 | 持续轻量级开销 |
| 覆盖深度 | 取决于协议/凭据 | 深度本地访问 |
| 云快照分析 | 原生支持 | 不适用 |
| 适用场景 | 云虚拟机、IoT、遗留系统、OT | 受管端点、笔记本电脑 |
| 方法 | 协议 | 目标操作系统 | 端口 | 适用场景 |
|---|---|---|---|---|
| SSH 远程命令 | SSH | Linux/Unix | 22 | 软件包枚举、配置审计 |
| WMI 远程查询 | WMI/DCOM | Windows | 135, 445 | 热补丁枚举、注册表检查 |
| WinRM PowerShell | WS-Man | Windows | 5985/5986 | 远程命令执行 |
| SNMP 团体字 | SNMP v2c/v3 | 网络设备 | 161 | 设备指纹识别、固件检查 |
| 云快照 | 云服务商 API | 云虚拟机 | N/A | 磁盘镜像分析 |
| 容器镜像仓库 | HTTPS | 容器镜像 | 443 | 镜像漏洞扫描 |
| 基于 API | REST/HTTPS | SaaS/Cloud | 443 | 配置评估 |
1. 扫描器通过云 API 请求磁盘快照
2. 云服务商为虚拟机根磁盘和数据磁盘创建快照
3. 扫描器在隔离分析环境中挂载快照
4. 扫描器检查操作系统软件包、配置和文件系统
5. 分析完成后删除快照(不保留持久副本)
6. 结果发送到中央管理控制台
# 创建专用扫描 SSH 密钥对
ssh-keygen -t ed25519 -f /opt/scanner/.ssh/scan_key -N "" \
-C "vuln-scanner@security.local"
# 通过 Ansible 将公钥部署到目标
# ansible-playbook deploy_scan_key.yml
# 测试与目标的连通性
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
class AgentlessLinuxScanner:
"""基于 SSH 的 Linux 系统无代理漏洞扫描器。"""
def __init__(self, key_path):
self.key_path = key_path
def connect(self, hostname, username="scanner", port=22):
"""与目标建立 SSH 连接。"""
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
def get_os_info(self, client):
"""检测操作系统类型和版本。"""
_, 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
def get_installed_packages(self, client):
"""枚举已安装的软件包。"""
# 尝试 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("|")
if len(parts) >= 2:
packages.append({
"name": parts[0],
"version": parts[1],
"arch": parts[2] if len(parts) > 2 else "",
"manager": "dpkg"
})
return packages
# 尝试 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("|")
if len(parts) >= 2:
packages.append({
"name": parts[0],
"version": parts[1],
"arch": parts[2] if len(parts) > 2 else "",
"manager": "rpm"
})
return packages
def check_kernel_version(self, client):
"""获取运行中的内核版本。"""
_, stdout, _ = client.exec_command("uname -r", timeout=10)
return stdout.read().decode().strip()
def check_listening_ports(self, client):
"""枚举正在监听的网络服务。"""
_, stdout, _ = client.exec_command(
"ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null",
timeout=10
)
return stdout.read().decode().strip()
def scan_host(self, hostname, username="scanner"):
"""对主机执行完整的无代理扫描。"""
print(f"[*] 正在扫描 {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" [+] 在 {hostname} 上发现 {len(result['packages'])} 个软件包")
return result
import winrm
class AgentlessWindowsScanner:
"""基于 WinRM 的 Windows 系统无代理漏洞扫描器。"""
def __init__(self, username, password, domain=None):
self.username = username
self.password = password
self.domain = domain
def connect(self, hostname, use_ssl=True):
"""创建 WinRM 会话。"""
port = 5986 if use_ssl else 5985
transport = "ntlm"
user = f"{self.domain}\\{self.username}" if self.domain else self.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
def get_installed_hotfixes(self, session):
"""获取已安装的 Windows 更新/热补丁。"""
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 []
def get_installed_software(self, session):
"""从注册表枚举已安装的软件。"""
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 []
def get_os_info(self, session):
"""获取 Windows 操作系统详情。"""
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 {}
def scan_host(self, hostname):
"""对 Windows 主机执行完整的无代理扫描。"""
print(f"[*] 通过 WinRM 扫描 {hostname}...")
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" [+] 发现 {len(result['hotfixes'])} 个热补丁,"
f"{len(result['software'])} 个软件条目")
return result
import boto3
import time
class AWSSnapshotScanner:
"""基于 AWS EC2 EBS 快照的无代理漏洞扫描器。"""
def __init__(self, region="us-east-1"):
self.ec2 = boto3.client("ec2", region_name=region)
def create_snapshot(self, volume_id, description="安全扫描快照"):
"""创建用于分析的 EBS 快照。"""
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" [*] 正在从 {volume_id} 创建快照 {snapshot_id}...")
waiter = self.ec2.get_waiter("snapshot_completed")
waiter.wait(SnapshotIds=[snapshot_id])
print(f" [+] 快照 {snapshot_id} 已就绪")
return snapshot_id
def delete_snapshot(self, snapshot_id):
"""分析完成后清理快照。"""
self.ec2.delete_snapshot(SnapshotId=snapshot_id)
print(f" [+] 已删除快照 {snapshot_id}")
def scan_instance(self, instance_id):
"""通过快照分析扫描 EC2 实例。"""
print(f"[*] 对实例 {instance_id} 执行无代理扫描")
instance = self.ec2.describe_instances(
InstanceIds=[instance_id]
)["Reservations"][0]["Instances"][0]
root_volume = None
for bdm in instance.get("BlockDeviceMappings", []):
if bdm["DeviceName"] == instance.get("RootDeviceName"):
root_volume = bdm["Ebs"]["VolumeId"]
break
if not root_volume:
print(" [!] 未找到根卷")
return None
snapshot_id = self.create_snapshot(root_volume)
try:
# 此处执行分析
# 挂载快照,检查软件包,核查配置
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)
# /etc/vuls/config.toml - 无代理扫描的 Vuls 配置
[servers]
[servers.web-server-01]
host = "192.168.1.10"
port = "22"
user = "vuls"
keyPath = "/opt/vuls/.ssh/scan_key"
scanMode = ["fast"]
[servers.db-server-01]
host = "192.168.1.20"
port = "22"
user = "vuls"
keyPath = "/opt/vuls/.ssh/scan_key"
scanMode = ["fast-root"]
[servers.db-server-01.optional]
[servers.db-server-01.optional.sudo]
password = ""
[servers.container-host-01]
host = "192.168.1.30"
port = "22"
user = "vuls"
keyPath = "/opt/vuls/.ssh/scan_key"
scanMode = ["fast"]
containersIncluded = ["${running}"]
# 运行 Vuls 无代理扫描
vuls scan
# 生成报告
vuls report -format-json -to-localfile
# 查看结果
vuls tui