收集 Qualys Virtual Scanner 日志
支持的环境:
Google secops
SIEM
此解析器会将原始 JSON 格式的 Qualys Virtual Scanner 日志转换为符合 Google Security Operations UDM 的结构化格式。它会提取相关字段(例如资产信息、扫描详细信息和检测到的漏洞),并将这些字段映射到相应的 UDM 字段,以实现一致的表示和分析。
准备工作
请确保满足以下前提条件:
- Google Security Operations 实例。
- 能够访问的特权 Google Cloud。
- 能够访问 Qualys 的特权。
启用必需的 API:
- 登录 Google Cloud 控制台。
- 前往“API 和服务” > “库”。
- 搜索并启用以下 API:
- Cloud Functions API
- Cloud Scheduler API
- Cloud Pub/Sub(Cloud Scheduler 调用函数时需要)
创建 Google Cloud 存储分区
- 登录 Google Cloud 控制台。
前往 Cloud Storage 存储分区 页面。
点击创建 。
配置存储桶:
- 名称:输入符合存储桶名称要求的唯一名称(例如,qualys-vscanner-bucket)。
- 选择数据存储位置:选择一个位置。
- 选择数据的存储类别:为存储桶选择默认存储类别,或者选择Autoclass进行自动存储类别管理。
- 选择如何控制对象的访问权限:选择不强制执行禁止公开访问,然后为存储桶对象选择访问权限控制模型。
- 存储类别:根据您的需求进行选择(例如,标准)。
点击创建 。
创建 Google Cloud 服务账号
- 前往 IAM 和管理 > 服务账号。
- 创建新的服务帐号。
- 指定一个描述性名称(例如,qualys-user )。
- 向服务帐号授予在上一步中创建的 Cloud Storage 存储桶的 Storage Object Admin 角色。
- 向服务帐号授予 Cloud Functions Invoker 角色。
- 为服务帐号创建 SSH 密钥 。
- 下载服务帐号的 JSON 密钥文件。请妥善保管此文件。
可选:在 Qualys 中创建专用 API 用户
- 登录 Qualys 控制台。
- 前往用户 。
- 依次点击新建 > 用户。
- 输入用户所需的常规信息 。
- 选择用户角色 标签页。
- 确保该角色已选中 API 访问权限 复选框。
- 点击保存 。
确定您的特定 Qualys API 网址
选项 1
按照平台标识中的说明确定您的网址。
选项 2
- 登录 Qualys 控制台。
- 依次前往帮助 > 关于。
- 滚动查看安全运维中心 (SOC) 下的此信息。
- 复制 Qualys API 网址。
配置 Cloud Function
- 在 Google Cloud 控制台中前往 Cloud Functions 。
- 点击创建函数 。
配置函数:
- 名称:输入函数的名称(例如,fetch-qualys-vscanner)。
- 区域:选择靠近存储分区的区域。
- 触发器:根据需要选择 HTTP 触发器,或选择 Cloud Pub/Sub 以进行定期执行。
- 身份验证:通过身份验证确保安全。
- 使用内嵌编辑器编写代码 :
```python from google.cloud import storage import requests import base64 import json # Google Cloud Storage Configuration BUCKET_NAME = "<bucket-name>" FILE_NAME = "qualys_virtual_scanners.json" # Qualys API Credentials QUALYS_USERNAME = "qualys-username" QUALYS_PASSWORD = "<qualys-password>" QUALYS_BASE_URL = "https://<qualys_base_url>" # for example, https://qualysapi.qualys.com def fetch_virtual_scanners(): """Fetch Virtual Scanner details from Qualys.""" auth = base64.b64encode(f"{QUALYS_USERNAME}:{QUALYS_PASSWORD}".encode()).decode() headers = { "Authorization": f"Basic {auth}", "Content-Type": "application/xml" } url = f"{QUALYS_BASE_URL}/api/2.0/fo/scanner/" payload = { "action": "list", "scanner_type": "virtual" } response = requests.post(url, headers=headers, data=payload) response.raise_for_status() return response.text # Qualys API returns XML data def upload_to_gcs(data): """Upload data to Google Cloud Storage.""" client = storage.Client() bucket = client.get_bucket(BUCKET_NAME) blob = bucket.blob(FILE_NAME) blob.upload_from_string(data, content_type="application/xml") def main(request): """Cloud Function entry point.""" try: scanners = fetch_virtual_scanners() upload_to_gcs(scanners) return "Qualys Virtual Scanners data uploaded to Cloud Storage successfully!" except Exception as e: return f"An error occurred: {e}", 500 ```完成配置后,点击部署 。
配置 Cloud Scheduler
- 在 Google Cloud 控制台中前往 Cloud Scheduler 。
- 点击创建作业 。
配置作业:
- 名称:输入作业的名称(例如,trigger-fetch-qualys-vscanner)。
- 频率:使用 cron 语法指定时间表(例如,0 0 * * * 表示每天午夜)。
- 时区:设置您偏好的时区。
- 触发器类型:选择 HTTP。
- 触发器网址:输入 Cloud Functions 函数的网址(部署后可在函数详细信息中找到)。
- 方法:选择 POST。
创建作业。
设置 Feed
如需配置 Feed,请按以下步骤操作:
- 前往 SIEM 设置 > Feed。
- 点击 Add New Feed (添加新 Feed)。
- 在下一页上,点击 Configure a single feed (配置单个 Feed)。
- 在 Feed 名称 字段中,输入 Feed 的名称;例如,Qualys Virtual Scanner Logs 。
- 选择 Google Cloud Storage V2 作为来源类型 。
- 选择 Qualys Virtual Scanner 作为日志类型 。
- 点击下一步 。
为以下输入参数指定值:
- 存储桶 URI: Google Cloud 存储桶来源 URI。
- 来源删除选项:根据您的偏好选择删除选项。
点击下一步 。
在最终确定 屏幕中检查新的 Feed 配置,然后点击提交 。
UDM 映射表
| 日志字段 | UDM 映射 | 逻辑 |
|---|---|---|
| ASSET_ID | entity.entity.asset.asset_id | 直接从 ASSET_ID 字段映射。 |
| CLOUD_PROVIDER_TAGS.CLOUD_TAG.NAME | entity.relations.entity.resource.attribute.labels.key | 直接从 CLOUD_PROVIDER_TAGS.CLOUD_TAG.NAME 字段映射。 |
| CLOUD_PROVIDER_TAGS.CLOUD_TAG.VALUE | entity.relations.entity.resource.attribute.labels.value | 直接从 CLOUD_PROVIDER_TAGS.CLOUD_TAG.VALUE 字段映射。 |
| CLOUD_RESOURCE_ID | entity.relations.entity.resource.id | 直接从 CLOUD_RESOURCE_ID 字段映射。 |
| DETECTION_LIST.DETECTION.FIRST_FOUND_DATETIME | entity.metadata.threat.first_discovered_time | 直接从 DETECTION_LIST.DETECTION.FIRST_FOUND_DATETIME 字段映射,并转换为时间戳。 |
| DETECTION_LIST.DETECTION.FIRST_REOPENED_DATETIME | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.FIRST_REOPENED_DATETIME 字段映射。该键硬编码为“FIRST_REOPENED_DATETIME”。 |
| DETECTION_LIST.DETECTION.IS_DISABLED | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.IS_DISABLED 字段映射。该键硬编码为“IS_DISABLED”。 |
| DETECTION_LIST.DETECTION.LAST_FIXED_DATETIME | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.LAST_FIXED_DATETIME 字段映射。该键硬编码为“LAST_FIXED_DATETIME”。 |
| DETECTION_LIST.DETECTION.LAST_FOUND_DATETIME | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.LAST_FOUND_DATETIME 字段映射。该键硬编码为“LAST_FOUND_DATETIME”。 |
| DETECTION_LIST.DETECTION.LAST_PROCESSED_DATETIME | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.LAST_PROCESSED_DATETIME 字段映射。该键硬编码为“LAST_PROCESSED_DATETIME”。 |
| DETECTION_LIST.DETECTION.LAST_REOPENED_DATETIME | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.LAST_REOPENED_DATETIME 字段映射。该键硬编码为“LAST_REOPENED_DATETIME”。 |
| DETECTION_LIST.DETECTION.LAST_TEST_DATETIME | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.LAST_TEST_DATETIME 字段映射。该键硬编码为“LAST_TEST_DATETIME”。 |
| DETECTION_LIST.DETECTION.LAST_UPDATE_DATETIME | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.LAST_UPDATE_DATETIME 字段映射。该键硬编码为“LAST_UPDATE_DATETIME”。 |
| DETECTION_LIST.DETECTION.PORT | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.PORT 字段映射。该键硬编码为“PORT”。 |
| DETECTION_LIST.DETECTION.PROTOCOL | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.PROTOCOL 字段映射。该键硬编码为“PROTOCOL”。 |
| DETECTION_LIST.DETECTION.QID | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.QID 字段映射。该键硬编码为“QID”。 |
| DETECTION_LIST.DETECTION.RESULTS | entity.metadata.threat.summary | 直接从 DETECTION_LIST.DETECTION.RESULTS 字段映射。 |
| DETECTION_LIST.DETECTION.SEVERITY | entity.metadata.threat.severity_details | 直接从 DETECTION_LIST.DETECTION.SEVERITY 字段映射。 |
| DETECTION_LIST.DETECTION.SSL | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.SSL 字段映射。该键硬编码为“SSL”。 |
| DETECTION_LIST.DETECTION.STATUS | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.STATUS 字段映射。该键硬编码为“STATUS”。 |
| DETECTION_LIST.DETECTION.TIMES_FOUND | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.TIMES_FOUND 字段映射。该键硬编码为“TIMES_FOUND”。 |
| DETECTION_LIST.DETECTION.TIMES_REOPENED | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.TIMES_REOPENED 字段映射。该键硬编码为“TIMES_REOPENED”。 |
| DETECTION_LIST.DETECTION.TYPE | entity.metadata.threat.severity | 从 DETECTION_LIST.DETECTION.TYPE 字段映射。如果值为“info”(不区分大小写),则映射到“INFORMATIONAL”。否则,它会作为检测字段添加,键为“TYPE”。 |
| DETECTION_LIST.DETECTION.UNIQUE_VULN_ID | entity.metadata.threat.detection_fields.value | 直接从 DETECTION_LIST.DETECTION.UNIQUE_VULN_ID 字段映射。该键硬编码为“UNIQUE_VULN_ID”。 |
| DNS | entity.entity.asset.hostname | 如果 DNS_DATA.HOSTNAME 为空,则从 DNS 字段映射。 |
| DNS_DATA.HOSTNAME | entity.entity.asset.hostname | 直接从 DNS_DATA.HOSTNAME 字段映射。 |
| EC2_INSTANCE_ID | entity.relations.entity.resource.product_object_id | 直接从 EC2_INSTANCE_ID 字段映射。 |
| ID | entity.entity.asset.product_object_id | 直接从 ID 字段映射。 |
| ID | entity.metadata.product_entity_id | 直接从 ID 字段映射。 |
| IP | entity.entity.ip | 直接从 IP 字段映射。 |
| LAST_SCAN_DATETIME | entity.metadata.interval.start_time | 直接从 LAST_SCAN_DATETIME 字段映射,并转换为时间戳。 |
| METADATA.AZURE.ATTRIBUTE.NAME | entity.relations.entity.resource.attribute.labels.key | 直接从 METADATA.AZURE.ATTRIBUTE.NAME 字段映射。 |
| METADATA.AZURE.ATTRIBUTE.VALUE | entity.relations.entity.resource.attribute.labels.value | 直接从 METADATA.AZURE.ATTRIBUTE.VALUE 字段映射。 |
| OS | entity.entity.asset.platform_software.platform | 从 OS 字段映射。如果值包含“windows”(不区分大小写),则映射到“WINDOWS”。如果值包含“Linux”(不区分大小写),则映射到“LINUX”。 |
| TAGS.TAG.NAME | entity.relations.entity.resource.attribute.labels.key | 直接从 TAGS.TAG.NAME 字段映射。 |
| TAGS.TAG.TAG_ID | entity.relations.entity.resource.attribute.labels.value | 从 TAGS.TAG.TAG_ID 字段映射。该值带有“TAG_ID: ”前缀。 |
| entity.metadata.collected_timestamp | 日志条目的时间戳。 | |
| entity.metadata.entity_type | 根据是否存在 IP 字段确定。如果存在 IP,则设置为“IP_ADDRESS”。否则,设置为“ASSET”。 |
|
| entity.metadata.interval.end_time | 硬编码为非常大的时间戳值(253402300799 秒)。 | |
| entity.metadata.product_name | 硬编码为“QUALYS_VIRTUAL_SCANNER”。 | |
| entity.metadata.vendor_name | 硬编码为“QUALYS_VIRTUAL_SCANNER”。 | |
| entity.relations.entity.resource.resource_type | 如果 CLOUD_SERVICE 为“VM”,则设置为“VIRTUAL_MACHINE”。 |
|
| entity.relations.entity_type | 硬编码为“RESOURCE”。 | |
| entity.relations.relationship | 硬编码为“MEMBER”。 |