performing-ics-asset-discovery-with-claroty

使用Claroty xDome平台执行全面的ICS/OT资产发现,利用被动监控、Claroty Edge主动查询和集成生态系统,在Purdue模型各级别获得对工业控制系统资产(包括PLC、RTU、HMI和网络基础设施)的完整可见性。

9 stars

Best use case

performing-ics-asset-discovery-with-claroty is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

使用Claroty xDome平台执行全面的ICS/OT资产发现,利用被动监控、Claroty Edge主动查询和集成生态系统,在Purdue模型各级别获得对工业控制系统资产(包括PLC、RTU、HMI和网络基础设施)的完整可见性。

Teams using performing-ics-asset-discovery-with-claroty should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/performing-ics-asset-discovery-with-claroty/SKILL.md --create-dirs "https://raw.githubusercontent.com/killvxk/cybersecurity-skills-zh/main/skills/performing-ics-asset-discovery-with-claroty/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/performing-ics-asset-discovery-with-claroty/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How performing-ics-asset-discovery-with-claroty Compares

Feature / Agentperforming-ics-asset-discovery-with-clarotyStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

使用Claroty xDome平台执行全面的ICS/OT资产发现,利用被动监控、Claroty Edge主动查询和集成生态系统,在Purdue模型各级别获得对工业控制系统资产(包括PLC、RTU、HMI和网络基础设施)的完整可见性。

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# 使用Claroty执行ICS资产发现

## 适用场景

- 对资产未知或记录不完整的OT环境进行初始可见性建立时
- 准备需要完整资产清单的IEC 62443风险评估时
- 将Claroty xDome引入棕地工业环境时
- 根据实际网络通信验证现有资产清单时
- 识别控制网络中的影子OT设备或未授权连接时

**不适用于**仅IT资产发现(使用Nessus或Qualys等工具)、未经供应商批准对敏感PLC网络进行主动扫描,或未部署Claroty的环境(参见implementing-ot-network-traffic-analysis-with-nozomi)。

## 前置条件

- Claroty xDome SaaS订阅或本地部署
- 在OT网络边界(Purdue模型1-3级)配置的网络TAP或SPAN端口
- 部署Claroty Edge采集器用于安全主动查询难以到达的网段
- CMDB工具(ServiceNow、BMC)的集成凭据(如使用)
- 显示VLAN、交换机和防火墙区域的网络架构图

## 工作流程

### 步骤 1:配置被动网络监控

在SPAN端口上部署Claroty传感器,被动观察所有OT网络流量而不影响运营。

```python
#!/usr/bin/env python3
"""Claroty xDome资产发现配置和报告工具。

自动化被动监控传感器的配置,并从
Claroty xDome API生成资产清单报告。
"""

import json
import sys
import csv
from datetime import datetime
from typing import Optional

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


class ClarotyAssetDiscovery:
    """通过Claroty xDome API进行ICS资产发现的接口。"""

    def __init__(self, base_url: str, api_token: str, verify_ssl: bool = True):
        self.base_url = base_url.rstrip("/")
        self.session = requests.Session()
        self.session.headers.update({
            "Authorization": f"Bearer {api_token}",
            "Content-Type": "application/json",
            "Accept": "application/json",
        })
        self.session.verify = verify_ssl

    def get_sites(self):
        """获取所有被监控的站点。"""
        resp = self.session.get(f"{self.base_url}/api/v1/sites")
        resp.raise_for_status()
        return resp.json().get("sites", [])

    def get_assets(self, site_id: Optional[str] = None, asset_type: Optional[str] = None):
        """获取已发现的资产(可选过滤)。

        asset_type: PLC, RTU, HMI, DCS, Engineering_Workstation,
                    Historian, Network_Device, IO_Module, Safety_Controller
        """
        params = {}
        if site_id:
            params["site_id"] = site_id
        if asset_type:
            params["type"] = asset_type

        resp = self.session.get(f"{self.base_url}/api/v1/assets", params=params)
        resp.raise_for_status()
        return resp.json().get("assets", [])

    def get_asset_detail(self, asset_id: str):
        """获取详细资产信息,包括固件、模块和CVE。"""
        resp = self.session.get(f"{self.base_url}/api/v1/assets/{asset_id}")
        resp.raise_for_status()
        return resp.json()

    def get_communication_map(self, site_id: str):
        """获取资产间的通信关系。"""
        resp = self.session.get(
            f"{self.base_url}/api/v1/sites/{site_id}/communications"
        )
        resp.raise_for_status()
        return resp.json().get("communications", [])

    def get_vulnerabilities(self, site_id: Optional[str] = None, severity: str = "critical"):
        """获取已发现资产的漏洞。"""
        params = {"min_severity": severity}
        if site_id:
            params["site_id"] = site_id

        resp = self.session.get(f"{self.base_url}/api/v1/vulnerabilities", params=params)
        resp.raise_for_status()
        return resp.json().get("vulnerabilities", [])

    def export_asset_inventory(self, output_file: str, site_id: Optional[str] = None):
        """将完整资产清单导出为CSV用于合规报告。"""
        assets = self.get_assets(site_id=site_id)
        if not assets:
            print("[!] 未找到资产")
            return

        fieldnames = [
            "asset_id", "name", "type", "vendor", "model", "firmware_version",
            "ip_address", "mac_address", "serial_number", "purdue_level",
            "zone", "protocol", "first_seen", "last_seen", "risk_score",
            "cve_count", "site_name",
        ]

        with open(output_file, "w", newline="") as f:
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            for asset in assets:
                writer.writerow({
                    "asset_id": asset.get("id", ""),
                    "name": asset.get("name", "未知"),
                    "type": asset.get("type", ""),
                    "vendor": asset.get("vendor", ""),
                    "model": asset.get("model", ""),
                    "firmware_version": asset.get("firmware_version", ""),
                    "ip_address": asset.get("ip_address", ""),
                    "mac_address": asset.get("mac_address", ""),
                    "serial_number": asset.get("serial_number", ""),
                    "purdue_level": asset.get("purdue_level", ""),
                    "zone": asset.get("zone", ""),
                    "protocol": ", ".join(asset.get("protocols", [])),
                    "first_seen": asset.get("first_seen", ""),
                    "last_seen": asset.get("last_seen", ""),
                    "risk_score": asset.get("risk_score", 0),
                    "cve_count": asset.get("cve_count", 0),
                    "site_name": asset.get("site_name", ""),
                })

        print(f"[+] 已导出 {len(assets)} 个资产到 {output_file}")

    def generate_purdue_level_report(self, site_id: str):
        """按Purdue模型级别生成资产分布报告。"""
        assets = self.get_assets(site_id=site_id)
        levels = {0: [], 1: [], 2: [], 3: [], 3.5: [], 4: [], 5: []}

        for asset in assets:
            level = asset.get("purdue_level", -1)
            if level in levels:
                levels[level].append(asset)

        print(f"\n{'='*65}")
        print("PURDUE模型资产分布报告")
        print(f"{'='*65}")
        print(f"站点: {site_id}")
        print(f"已发现资产总数: {len(assets)}")
        print(f"报告生成时间: {datetime.now().isoformat()}")
        print(f"{'-'*65}")

        level_names = {
            0: "0级 - 物理过程(传感器/执行器)",
            1: "1级 - 基本控制(PLC/RTU)",
            2: "2级 - 监控控制(HMI/SCADA)",
            3: "3级 - 站点运营(历史服务器/MES)",
            3.5: "3.5级 - IT/OT DMZ",
            4: "4级 - 企业IT",
            5: "5级 - 企业网络/互联网",
        }

        for level, name in level_names.items():
            device_list = levels.get(level, [])
            print(f"\n  {name}")
            print(f"    数量: {len(device_list)}")
            if device_list:
                vendors = set(a.get("vendor", "未知") for a in device_list)
                types = set(a.get("type", "未知") for a in device_list)
                print(f"    供应商: {', '.join(vendors)}")
                print(f"    类型: {', '.join(types)}")
                high_risk = [a for a in device_list if a.get("risk_score", 0) >= 7]
                if high_risk:
                    print(f"    高风险资产: {len(high_risk)}")
                    for a in high_risk[:5]:
                        print(f"      - {a['name']} (风险: {a.get('risk_score')})")


if __name__ == "__main__":
    discovery = ClarotyAssetDiscovery(
        base_url="https://your-claroty-instance.claroty.cloud",
        api_token="your-api-token-here",
        verify_ssl=True,
    )

    print("[*] 获取站点...")
    sites = discovery.get_sites()
    for site in sites:
        print(f"  站点: {site['name']} (ID: {site['id']})")

    if sites:
        site_id = sites[0]["id"]
        print(f"\n[*] 为 {sites[0]['name']} 生成Purdue级别报告...")
        discovery.generate_purdue_level_report(site_id)

        print(f"\n[*] 导出资产清单...")
        discovery.export_asset_inventory(
            f"asset_inventory_{datetime.now().strftime('%Y%m%d')}.csv",
            site_id=site_id,
        )

        print(f"\n[*] 检查严重漏洞...")
        vulns = discovery.get_vulnerabilities(site_id=site_id, severity="critical")
        print(f"  严重漏洞: {len(vulns)}")
        for v in vulns[:10]:
            print(f"    - {v.get('cve_id')}: {v.get('description', '')[:80]}")
```

### 步骤 2:使用Claroty Edge配置主动发现

Claroty Edge使用原生工业协议(而非IT扫描)对OT设备执行安全、有针对性的查询,从被动监控单独无法完全识别的设备中提取详细资产信息。

```yaml
# Claroty Edge主动发现配置
# 使用原生工业协议进行安全主动查询

edge_configuration:
  deployment_mode: "on-premises"
  collection_schedule:
    frequency: "weekly"
    maintenance_window: "周日 02:00-06:00"
    max_concurrent_queries: 5

  protocol_queries:
    siemens_s7:
      enabled: true
      target_subnets: ["10.10.1.0/24", "10.10.2.0/24"]
      ports: [102]
      query_type: "SZL_read"
      information_collected:
        - "模块标识"
        - "固件版本"
        - "硬件配置"
        - "保护级别"

    rockwell_cip:
      enabled: true
      target_subnets: ["10.10.3.0/24"]
      ports: [44818]
      query_type: "CIP_identity"
      information_collected:
        - "产品名称和版本"
        - "序列号"
        - "设备类型"
        - "供应商ID"

    modbus:
      enabled: true
      target_subnets: ["10.10.4.0/24"]
      ports: [502]
      query_type: "read_device_identification"
      function_code: 43
      information_collected:
        - "供应商名称"
        - "产品代码"
        - "固件版本"

    bacnet:
      enabled: true
      target_subnets: ["10.10.5.0/24"]
      ports: [47808]
      query_type: "who_is"
      information_collected:
        - "设备名称"
        - "供应商标识符"
        - "型号名称"
        - "应用软件版本"

  safety_controls:
    excluded_subnets: ["10.10.100.0/24"]  # SIS网络 - 永不主动扫描
    rate_limiting: true
    max_packets_per_second: 10
    timeout_seconds: 5
    retry_count: 1
    abort_on_device_error: true
```

### 步骤 3:验证和丰富资产数据

将已发现的资产与已知清单进行交叉比对,并用漏洞数据进行丰富。

```python
#!/usr/bin/env python3
"""资产验证和丰富工具。

将Claroty发现结果与现有CMDB进行交叉比对,
并用NVD漏洞数据进行丰富。
"""

import json
import csv
import sys
from datetime import datetime

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


class AssetValidator:
    """验证和丰富OT资产清单。"""

    def __init__(self, inventory_file: str):
        self.discovered_assets = []
        self.load_inventory(inventory_file)
        self.discrepancies = []

    def load_inventory(self, filepath: str):
        """加载Claroty发现的资产清单。"""
        with open(filepath, "r") as f:
            reader = csv.DictReader(f)
            self.discovered_assets = list(reader)
        print(f"[*] 已加载 {len(self.discovered_assets)} 个已发现资产")

    def compare_with_cmdb(self, cmdb_file: str):
        """将已发现资产与CMDB记录进行比较。"""
        with open(cmdb_file, "r") as f:
            cmdb_assets = {row["ip_address"]: row for row in csv.DictReader(f)}

        discovered_ips = {a["ip_address"] for a in self.discovered_assets if a["ip_address"]}
        cmdb_ips = set(cmdb_assets.keys())

        shadow_devices = discovered_ips - cmdb_ips
        missing_devices = cmdb_ips - discovered_ips

        print(f"\n{'='*60}")
        print("资产清单验证报告")
        print(f"{'='*60}")
        print(f"已发现资产: {len(discovered_ips)}")
        print(f"CMDB记录: {len(cmdb_ips)}")
        print(f"影子OT设备(不在CMDB中): {len(shadow_devices)}")
        print(f"缺失设备(在CMDB中但未发现): {len(missing_devices)}")

        if shadow_devices:
            print(f"\n  影子设备(未授权/未记录):")
            for ip in sorted(shadow_devices):
                asset = next((a for a in self.discovered_assets if a["ip_address"] == ip), {})
                print(f"    - {ip} | {asset.get('vendor', '未知')} {asset.get('model', '')} | 类型: {asset.get('type', '未知')}")
                self.discrepancies.append({
                    "type": "SHADOW_DEVICE",
                    "severity": "HIGH",
                    "ip": ip,
                    "detail": f"来自{asset.get('vendor', '未知供应商')}的未记录{asset.get('type', '设备')}",
                })

        if missing_devices:
            print(f"\n  缺失设备(预期存在但未发现):")
            for ip in sorted(missing_devices):
                cmdb = cmdb_assets[ip]
                print(f"    - {ip} | {cmdb.get('name', '未知')} | CMDB最后更新: {cmdb.get('last_updated', 'N/A')}")
                self.discrepancies.append({
                    "type": "MISSING_DEVICE",
                    "severity": "MEDIUM",
                    "ip": ip,
                    "detail": f"CMDB资产 {cmdb.get('name', ip)} 在网络上未发现",
                })

    def check_firmware_vulnerabilities(self, asset):
        """检查NVD中匹配资产固件的已知漏洞。"""
        vendor = asset.get("vendor", "").lower()
        model = asset.get("model", "").lower()
        firmware = asset.get("firmware_version", "")

        if not vendor or not model:
            return []

        search_term = f"{vendor} {model}"
        try:
            resp = requests.get(
                "https://services.nvd.nist.gov/rest/json/cves/2.0",
                params={"keywordSearch": search_term, "resultsPerPage": 10},
                timeout=15,
            )
            if resp.status_code == 200:
                data = resp.json()
                return data.get("vulnerabilities", [])
        except requests.RequestException:
            pass
        return []

    def generate_risk_summary(self):
        """生成按风险优先级排序的发现摘要。"""
        print(f"\n{'='*60}")
        print("风险摘要")
        print(f"{'='*60}")

        high_risk = [a for a in self.discovered_assets if float(a.get("risk_score", 0)) >= 7]
        end_of_life = [a for a in self.discovered_assets if a.get("firmware_version", "").startswith("v1.")]
        no_encryption = [a for a in self.discovered_assets if "modbus" in a.get("protocol", "").lower()]

        print(f"  高风险资产(评分 >= 7): {len(high_risk)}")
        print(f"  可能达到生命周期终止的固件: {len(end_of_life)}")
        print(f"  使用未加密协议的资产: {len(no_encryption)}")
        print(f"  清单差异数量: {len(self.discrepancies)}")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python validate_assets.py <claroty_export.csv> [cmdb_export.csv]")
        sys.exit(1)

    validator = AssetValidator(sys.argv[1])
    if len(sys.argv) >= 3:
        validator.compare_with_cmdb(sys.argv[2])
    validator.generate_risk_summary()
```

## 核心概念

| 术语 | 定义 |
|------|------|
| 被动监控(Passive Monitoring) | 通过SPAN/TAP观察镜像网络流量而不注入数据包,对所有OT设备安全 |
| 主动查询(Active Querying) | 发送原生协议请求以提取详细设备信息;需要仔细规划 |
| Claroty Edge | Claroty的安全主动发现采集器,使用原生工业协议而非IT扫描 |
| Purdue级别(Purdue Level) | 工业网络资产的层次化分类,从0级(物理过程)到5级(企业) |
| 影子OT设备(Shadow OT Device) | 连接到OT网络但未在资产管理系统中记录的资产 |
| xDome | Claroty的基于SaaS的网络物理系统保护平台,提供可见性、风险管理和威胁检测 |

## 常见场景

### 场景:棕地工厂资产发现

**背景**:一家拥有20年设备添加历史的制造工厂需要为IEC 62443风险评估建立完整的OT资产清单。没有准确的资产记录。

**方法**:
1. 在每个主要网段(控制、监控、DMZ)的SPAN端口上部署Claroty传感器
2. 允许被动监控2-4周以捕获所有常规通信模式
3. 在计划的维护窗口期间安排Claroty Edge主动查询
4. 导出已发现的清单,并按Purdue级别、供应商和关键性对资产进行分类
5. 与任何现有文档(P&ID图、网络图纸)进行交叉比对
6. 识别影子设备并与工厂运营部门启动审查流程
7. 将验证后的清单纳入IEC 62443区域和通道风险评估

**注意事项**:不要在被动监控捕获基线流量模式之前急于进行主动发现。切勿直接对PLC或RTU使用IT漏洞扫描器(Nessus主动扫描)——这可能导致旧版控制器崩溃。始终将安全仪表系统(SIS)排除在主动查询之外。

## 输出格式

```
ICS资产发现报告
============================
日期: YYYY-MM-DD
平台: Claroty xDome
站点: [站点名称]

发现摘要:
  已发现资产总数: [数量]
  新资产(不在CMDB中): [数量]
  高风险资产: [数量]

PURDUE级别分布:
  0级(过程): [数量] 个资产
  1级(控制): [数量] 个资产
  2级(监控): [数量] 个资产
  3级(运营): [数量] 个资产
  3.5级(DMZ): [数量] 个资产
  4-5级(企业): [数量] 个资产

主要供应商:
  1. [供应商] - [数量] 台设备
  2. [供应商] - [数量] 台设备

关键发现:
  - [影子设备描述]
  - [生命周期终止固件发现]
  - [未加密协议问题]
```

Related Skills

performing-yara-rule-development-for-detection

9
from killvxk/cybersecurity-skills-zh

通过识别可执行文件中的唯一字节模式、字符串和行为指标,开发精准的 YARA 恶意软件检测规则,同时将误报率降至最低。

performing-wireless-security-assessment-with-kismet

9
from killvxk/cybersecurity-skills-zh

使用 Kismet 通过被动射频监控进行无线网络安全评估,检测流氓接入点(Rogue AP)、隐藏 SSID、弱加密和未授权客户端。

performing-wireless-network-penetration-test

9
from killvxk/cybersecurity-skills-zh

执行无线网络渗透测试,通过捕获握手包、破解 WPA2/WPA3 密钥、检测流氓接入点以及使用 Aircrack-ng 和相关工具测试无线网络分段,评估 WiFi 安全性。

performing-windows-artifact-analysis-with-eric-zimmerman-tools

9
from killvxk/cybersecurity-skills-zh

使用 Eric Zimmerman 的开源 EZ Tools 套件(包括 KAPE、MFTECmd、PECmd、LECmd、JLECmd 和 Timeline Explorer)执行全面的 Windows 取证制品分析,解析注册表 hive、预取文件、事件日志和文件系统元数据。

performing-wifi-password-cracking-with-aircrack

9
from killvxk/cybersecurity-skills-zh

在授权无线安全评估中捕获 WPA/WPA2 握手包,并使用 aircrack-ng、hashcat 和字典攻击进行离线密码破解, 以评估密码短语强度和无线网络安全状况。

performing-web-cache-poisoning-attack

9
from killvxk/cybersecurity-skills-zh

在授权安全测试期间,通过未纳入缓存键的头部和参数毒化缓存响应,利用 Web 缓存机制向其他用户投递恶意内容。

performing-web-cache-deception-attack

9
from killvxk/cybersecurity-skills-zh

通过利用 CDN 缓存层与源服务器之间的路径规范化差异,执行 Web 缓存欺骗攻击,从而缓存并获取敏感的已认证内容。

performing-web-application-vulnerability-triage

9
from killvxk/cybersecurity-skills-zh

使用 OWASP 风险评级方法论对 DAST/SAST 扫描器的 Web 应用程序漏洞发现进行分类,区分真阳性和假阳性,并确定修复优先级。

performing-web-application-scanning-with-nikto

9
from killvxk/cybersecurity-skills-zh

Nikto 是一款开源 Web 服务器和 Web 应用程序扫描器,可针对超过 7,000 个潜在危险文件/程序进行测试,检查超过 1,250 个服务器的过期版本,并识别超过 270 个服务器的版本特定问题。

performing-web-application-penetration-test

9
from killvxk/cybersecurity-skills-zh

遵循 OWASP Web 安全测试指南(WSTG)方法论,对 Web 应用程序执行系统化安全测试,识别认证、授权、 输入验证、会话管理和业务逻辑中的漏洞。测试人员以 Burp Suite 作为主要拦截代理,结合手动测试技术 发现自动化扫描器遗漏的缺陷。适用于 Web 应用渗透测试、OWASP 测试、应用安全评估或 Web 漏洞测试等请求场景。

performing-web-application-firewall-bypass

9
from killvxk/cybersecurity-skills-zh

使用编码技术、HTTP 方法操控、参数污染和载荷混淆绕过 Web 应用防火墙保护,将 SQL 注入、XSS 及其他攻击载荷穿透 WAF 检测规则。

performing-vulnerability-scanning-with-nessus

9
from killvxk/cybersecurity-skills-zh

使用 Tenable Nessus 执行认证和未认证漏洞扫描,识别网络基础设施、服务器和应用程序中的已知漏洞、 错误配置、默认凭据和缺失补丁。扫描器将发现与 CVE 数据库和 CVSS 评分关联,生成优先级修复指导。 适用于漏洞扫描、Nessus 评估、补丁合规检查或自动化漏洞检测等请求场景。