From b457a55e0674b8d46b287dd3c2bb94fef334bd3c Mon Sep 17 00:00:00 2001 From: duguwanglong Date: Fri, 10 Apr 2026 19:39:06 +0800 Subject: [PATCH] feat(qingteng): align API with v3.4.1.58 manual and add fastjob, asset-discovery, microseg modules Add three new API modules (33 endpoints) based on the QingTeng v3.4.1.58 external API manual: - qingteng_fastjob: task template queries, job CRUD, execution and results - qingteng_asset_discovery: discovered host list and scan job management - qingteng_microseg: segmentation policies, host microseg controls, and black-strategy management Fix existing interface discrepancies: - delete_host: add missing password and allOffline body fields - bounceshell_list: make os_type optional (defaults to linux, supports win) - poc_job_rule_list: make os_type optional (win uses /win/rule_list path) Each new module includes a standalone YAML definition, thin handler, and validator function. Update api-reference.md accordingly. Made-with: Cursor --- .../qingteng-use/references/api-reference.md | 146 ++++++++ .../tools/api/qingteng/qingteng.handler.py | 315 ++++++++++++++++- .../qingteng_asset_discovery.handler.py | 19 ++ .../qingteng/qingteng_asset_discovery.yaml | 119 +++++++ .../tools/api/qingteng/qingteng_assets.yaml | 8 +- .../tools/api/qingteng/qingteng_detect.yaml | 10 + .../api/qingteng/qingteng_fastjob.handler.py | 19 ++ .../tools/api/qingteng/qingteng_fastjob.yaml | 168 ++++++++++ .../api/qingteng/qingteng_microseg.handler.py | 19 ++ .../tools/api/qingteng/qingteng_microseg.yaml | 316 ++++++++++++++++++ .../tools/api/qingteng/qingteng_risk.yaml | 2 +- pyproject.toml | 2 +- 12 files changed, 1136 insertions(+), 7 deletions(-) create mode 100644 .flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.handler.py create mode 100644 .flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.yaml create mode 100644 .flocks/plugins/tools/api/qingteng/qingteng_fastjob.handler.py create mode 100644 .flocks/plugins/tools/api/qingteng/qingteng_fastjob.yaml create mode 100644 .flocks/plugins/tools/api/qingteng/qingteng_microseg.handler.py create mode 100644 .flocks/plugins/tools/api/qingteng/qingteng_microseg.yaml diff --git a/.flocks/plugins/skills/qingteng-use/references/api-reference.md b/.flocks/plugins/skills/qingteng-use/references/api-reference.md index 880d51b..5af11ea 100644 --- a/.flocks/plugins/skills/qingteng-use/references/api-reference.md +++ b/.flocks/plugins/skills/qingteng-use/references/api-reference.md @@ -13,6 +13,9 @@ | 查基线任务、基线结果、授权 | `qingteng_baseline` | `job_list` / `job_status` / `spec_check_result` / `auth_list` | 通常至少要 `os_type` | | 查系统审计日志 | `qingteng_system_audit` | tool 直接调用 | 可空参,常补 `eventName`、`userName` | | 做快速风险体检 | `qingteng_vul_check` | tool 直接调用 | 常见 `risk_type`、`os_type` | +| 查/创建/执行快速安全检测任务 | `qingteng_fastjob` | `task_list` / `job_create` / `job_execute` / `task_result` | `taskId`、`name` 等 | +| 查发现的主机、管理资产扫描任务 | `qingteng_asset_discovery` | `discovered_host_list` / `job_create` / `job_execute` | `name`、`specId` 等 | +| 主机网络隔离、微隔离策略管理 | `qingteng_microseg` | `seg_create` / `seg_delete` / `host_list` / `black_list` | `agentIds`、`ids` 等 | ## 通用规则 @@ -382,6 +385,149 @@ - WebShell / 后门 / 漏洞 / 弱密码扫描 - 基线任务创建 / 更新 / 执行 - 授权信息变更 +- 快速任务作业创建 / 执行 +- 资产发现扫描任务创建 / 执行(会触发网络扫描) +- 微隔离策略创建 / 编辑 / 删除(会阻断或恢复主机网络) +- 主机阻断状态变更(`host_protect_status`) + +## 7. 快速任务:`qingteng_fastjob` + +适用于对单台或多台主机快速执行预定义的安全检测和应急响应任务。 + +### 典型流程 + +1. `task_list` — 查询可用的检测项模板(`osType=1` Linux,`2` Windows) +2. `job_create` — 创建作业,绑定 `taskId` 和目标主机范围 `realm` +3. `job_execute` — 立即执行,获取 `taskRecordId` +4. `task_result` — 查看执行结果;`task_error` — 查看失败主机 + +### 最小示例 + +查询检测项列表: + +```json +{ + "action": "task_list", + "osType": 1, + "name": "Weblogic", + "page": 0, + "size": 20 +} +``` + +创建作业(全部主机): + +```json +{ + "action": "job_create", + "name": "weblogic-check-2024", + "osType": 1, + "taskType": 1, + "taskId": "0478ee5024763edc6d3c", + "realm": {"type": 0}, + "realmName": "全部主机" +} +``` + +立即执行: + +```json +{ + "action": "job_execute", + "id": "5d1b568b67657c1b743cf33b" +} +``` + +## 8. 资产发现:`qingteng_asset_discovery` + +适用于发现未安装 Agent 的主机,了解全局资产覆盖情况。 + +### 典型流程 + +1. `discovered_host_list` — 查看当前已发现的主机 +2. `job_create` — 创建扫描任务,配置发起主机和目标 IP 段 +3. `job_execute` — 立即触发扫描 +4. 扫描完成后再次调用 `discovered_host_list` 查看新发现主机 + +### 最小示例 + +查看发现主机: + +```json +{ + "action": "discovered_host_list" +} +``` + +创建扫描任务: + +```json +{ + "action": "job_create", + "name": "内网段扫描", + "kind": 2, + "values": [], + "ipList": ["192.168.0.0/24"], + "osDetection": true +} +``` + +执行扫描任务: + +```json +{ + "action": "job_execute", + "specId": "5fdacbf3edc90d7a292ae9a5" +} +``` + +## 9. 微隔离:`qingteng_microseg` + +⚠️ **高风险操作模块**,隔离类操作会直接阻断主机网络连接,操作前必须确认 `agentId` 正确。 + +### 三类子功能 + +| 分组 | 代表 action | +|---|---| +| 隔离策略(一键隔离) | `seg_create`、`seg_edit`、`seg_delete`、`seg_list`、`seg_detail` | +| 主机管理 | `host_list`、`host_ms_enable`、`host_protect_status`、`host_limit_out` | +| 黑名单策略 | `black_list`、`black_create`、`black_update`、`black_delete`、`black_detail` | + +### 典型应急响应流程 + +1. `host_list` — 查找目标主机 `agentId` +2. `seg_create` — 对目标主机实施网络隔离 +3. 取证完成后 `seg_delete` — 解除隔离 + +```json +{ + "action": "seg_create", + "agentIds": ["5fa27259dae9af8a"], + "remark": "疑似失陷主机紧急隔离", + "direction": "out", + "ipList": [], + "portList": [] +} +``` + +解除隔离: + +```json +{ + "action": "seg_delete", + "agentIds": ["5fa27259dae9af8a"] +} +``` + +查看微隔离主机列表: + +```json +{ + "action": "host_list", + "page": 0, + "size": 20 +} +``` ## 何时回退浏览器 diff --git a/.flocks/plugins/tools/api/qingteng/qingteng.handler.py b/.flocks/plugins/tools/api/qingteng/qingteng.handler.py index 08d32f2..4a5bf1d 100644 --- a/.flocks/plugins/tools/api/qingteng/qingteng.handler.py +++ b/.flocks/plugins/tools/api/qingteng/qingteng.handler.py @@ -533,7 +533,7 @@ def path(self, params: dict[str, Any]) -> str: "delete_host": ActionSpec( "POST", lambda p: f"/external/api/assets/hostoperation/deletehost/{p['os_type']}", - body_builder=lambda p: _body_with_fields(p, "hostIds", "agentIds", "reason"), + body_builder=lambda p: _body_with_fields(p, "hostIds", "agentIds", "reason", "password", "allOffline"), ), "batch_create_group": ActionSpec( "POST", @@ -671,7 +671,13 @@ def path(self, params: dict[str, Any]) -> str: query_builder=_common_query, ), "poc_job_rule_list": ActionSpec( - "GET", lambda p: f"/external/api/vul/poc/job/{p['os_type']}/rule_list", query_builder=_common_query + "GET", + lambda p: ( + f"/external/api/vul/poc/job/{p['os_type']}/rule_list" + if p.get("os_type") == "win" + else "/external/api/vul/poc/job/rule_list" + ), + query_builder=_common_query, ), "poc_job_add": ActionSpec( "POST", @@ -744,7 +750,7 @@ def path(self, params: dict[str, Any]) -> str: "abnormallogin_list": ActionSpec( "GET", lambda p: f"/external/api/detect/abnormallogin/{p['os_type']}", query_builder=_abnormallogin_list_query ), - "bounceshell_list": ActionSpec("GET", "/external/api/detect/bounceshell/linux", query_builder=_common_query), + "bounceshell_list": ActionSpec("GET", lambda p: f"/external/api/detect/bounceshell/{p.get('os_type', 'linux')}", query_builder=_common_query), "localrights_list": ActionSpec("GET", "/external/api/detect/localrights/linux", query_builder=_common_query), "abnormallogin_rule_set": ActionSpec( "POST", @@ -916,11 +922,232 @@ def path(self, params: dict[str, Any]) -> str: } +FASTJOB_ACTIONS: dict[str, ActionSpec] = { + "task_list": ActionSpec( + "GET", + "/external/api/fastjob/task/list", + query_builder=lambda p: _paged_query(p, "osType", "ids", "name", "categories", "updatedTimeRange"), + ), + "task_detail": ActionSpec( + "GET", + lambda p: f"/external/api/fastjob/task/{_quote_param(p, 'taskId')}", + query_builder=_common_query, + ), + "job_create": ActionSpec( + "POST", + "/external/api/fastjob/job", + body_builder=lambda p: _body_with_fields( + p, "name", "osType", "description", "realm", "realmName", "taskType", "taskId", "taskParams", "cron", "cronEnable" + ), + ), + "job_update": ActionSpec( + "PUT", + lambda p: f"/external/api/fastjob/job/{_quote_param(p, 'jobId')}", + body_builder=lambda p: _body_with_fields( + p, "name", "osType", "description", "realm", "realmName", "taskType", "taskId", "taskParams", "cron", "cronEnable" + ), + ), + "job_delete": ActionSpec( + "DELETE", + lambda p: f"/external/api/fastjob/job/{_quote_param(p, 'jobId')}", + body_builder=_common_body, + ), + "job_list": ActionSpec( + "GET", + "/external/api/fastjob/job", + query_builder=lambda p: _paged_query(p, "osType"), + ), + "job_execute": ActionSpec( + "POST", + lambda p: f"/external/api/fastjob/job/execute/{_quote_param(p, 'id')}", + body_builder=_common_body, + ), + "job_execute_list": ActionSpec( + "GET", + "/external/api/fastjob/job/execute", + query_builder=lambda p: _paged_query(p, "osType"), + ), + "task_result": ActionSpec( + "GET", + lambda p: f"/external/api/fastjob/job/task/result/{_quote_param(p, 'taskRecordId')}", + query_builder=_common_query, + ), + "task_error": ActionSpec( + "GET", + lambda p: f"/external/api/fastjob/job/task/error/{_quote_param(p, 'taskRecordId')}", + query_builder=_common_query, + ), +} + + +ASSETDISCOVERY_ACTIONS: dict[str, ActionSpec] = { + "discovered_host_list": ActionSpec( + "GET", + "/external/api/discoveredhost/list", + query_builder=_common_query, + ), + "job_create": ActionSpec( + "POST", + "/external/api/assetdiscovery/job/create", + body_builder=lambda p: _body_with_fields( + p, "name", "kind", "values", "cronExpression", "osDetection", "ipList", "advanceConfigs" + ), + ), + "job_delete": ActionSpec( + "POST", + "/external/api/assetdiscovery/job/delete", + body_builder=lambda p: _body_with_fields(p, "specId"), + ), + "job_find": ActionSpec( + "POST", + "/external/api/assetdiscovery/job/find", + body_builder=lambda p: _body_with_fields(p, "specId"), + ), + "job_update": ActionSpec( + "POST", + "/external/api/assetdiscovery/job/update", + body_builder=lambda p: _body_with_fields( + p, "specId", "name", "kind", "values", "osDetection", "ipList", "advanceConfigs" + ), + ), + "job_list": ActionSpec( + "POST", + "/external/api/assetdiscovery/job/list", + body_builder=lambda p: _body_with_fields(p, "name", "scanType"), + ), + "job_execute": ActionSpec( + "POST", + "/external/api/assetdiscovery/job/execute", + body_builder=lambda p: _body_with_fields(p, "specId"), + ), +} + + +MICROSEG_ACTIONS: dict[str, ActionSpec] = { + "seg_list": ActionSpec( + "GET", + "/external/api/ms-srv/api/segmentation/list", + query_builder=lambda p: _paged_query(p, "groups"), + ), + "seg_detail": ActionSpec( + "GET", + "/external/api/ms-srv/api/segmentation/detail", + query_builder=lambda p: _query_with_fields(p, "agentId"), + ), + "seg_create": ActionSpec( + "POST", + "/external/api/ms-srv/api/segmentation/create", + body_builder=lambda p: _body_with_fields(p, "agentIds", "remark", "direction", "ipList", "portList"), + ), + "seg_edit": ActionSpec( + "POST", + "/external/api/ms-srv/api/segmentation/edit", + body_builder=lambda p: _body_with_fields(p, "agentIds", "remark", "direction", "ipList", "portList"), + ), + "seg_delete": ActionSpec( + "DELETE", + "/external/api/ms-srv/api/segmentation/del", + body_builder=lambda p: _body_with_fields(p, "agentIds"), + ), + "seg_real_delete": ActionSpec( + "DELETE", + "/external/api/ms-srv/api/segmentation/realDel", + body_builder=lambda p: _body_with_fields(p, "agentIds"), + ), + "seg_retry": ActionSpec( + "POST", + "/external/api/ms-srv/api/segmentation/retry", + body_builder=lambda p: _body_with_fields(p, "agentIds"), + ), + "host_list": ActionSpec( + "GET", + "/external/api/ms-srv/api/hosts/list", + query_builder=lambda p: _paged_query(p, "groups"), + ), + "host_ms_enable": ActionSpec( + "POST", + "/external/api/ms-srv/api/hosts/ms-enable", + body_builder=lambda p: _body_with_fields(p, "agentIds", "enabled"), + ), + "host_access_control_mode": ActionSpec( + "POST", + "/external/api/ms-srv/api/hosts/access-control-mode", + body_builder=lambda p: _body_with_fields(p, "agentIds", "accessControlModeSetting"), + ), + "host_run_status": ActionSpec( + "POST", + "/external/api/ms-srv/api/hosts/run-status", + body_builder=lambda p: _body_with_fields(p, "agentIds", "runStatusSetting"), + ), + "host_protect_status": ActionSpec( + "POST", + "/external/api/ms-srv/api/hosts/protect-status", + body_builder=lambda p: _body_with_fields(p, "agentIds", "runStatusSetting"), + ), + "host_limit_out": ActionSpec( + "POST", + "/external/api/ms-srv/api/hosts/limit-out", + body_builder=lambda p: _body_with_fields(p, "agentIds", "limitOutSetting"), + ), + "host_black_strategy_enable": ActionSpec( + "POST", + "/external/api/ms-srv/api/hosts/black-strategy-enable", + body_builder=lambda p: _body_with_fields(p, "agentIds", "blackStrategyEnableSetting"), + ), + "black_list": ActionSpec( + "GET", + "/external/api/ms-srv/api/black-strategy/list", + query_builder=lambda p: _paged_query(p, "groups"), + ), + "black_create": ActionSpec( + "POST", + "/external/api/ms-srv/api/black-strategy/create", + body_builder=lambda p: _body_with_fields( + p, "strategyName", "remark", "ports", "protos", "displayPort", "switchStatus", + "dstTagIds", "dstGroupIds", "dstRealmType", "dstIpList", + "srcTagIds", "srcGroupIds", "srcRealmType", "srcAgentIds", "srcIpList", + ), + ), + "black_update": ActionSpec( + "POST", + "/external/api/ms-srv/api/black-strategy/update", + body_builder=lambda p: _body_with_fields( + p, "id", "strategyName", "remark", "ports", "protos", "displayPort", "switchStatus", + "dstTagIds", "dstGroupIds", "dstRealmType", "dstIpList", + "srcTagIds", "srcGroupIds", "srcRealmType", "srcAgentIds", "srcIpList", + ), + ), + "black_update_switch": ActionSpec( + "POST", + "/external/api/ms-srv/api/black-strategy/update-switch", + body_builder=lambda p: _body_with_fields(p, "ids", "switchStatus"), + ), + "black_delete": ActionSpec( + "DELETE", + "/external/api/ms-srv/api/black-strategy/delete", + body_builder=lambda p: _body_with_fields(p, "ids"), + ), + "black_host_list": ActionSpec( + "GET", + "/external/api/ms-srv/api/black-strategy/strategy-host-list", + query_builder=lambda p: _paged_query(p, "ip", "msSwitchStatus", "strategyId", "strategyHostType"), + ), + "black_detail": ActionSpec( + "GET", + "/external/api/ms-srv/api/black-strategy/detail", + query_builder=lambda p: _query_with_fields(p, "id"), + ), +} + + GROUP_ACTIONS = { "assets": ASSET_ACTIONS, "risk": RISK_ACTIONS, "detect": DETECT_ACTIONS, "baseline": BASELINE_ACTIONS, + "fastjob": FASTJOB_ACTIONS, + "assetdiscovery": ASSETDISCOVERY_ACTIONS, + "microseg": MICROSEG_ACTIONS, } @@ -982,7 +1209,6 @@ def _validate_risk(action: str, params: dict[str, Any]) -> Optional[str]: "poc_scan_status", "poc_list", "poc_detail", - "poc_job_rule_list", "poc_job_add", "poc_job_fix", "poc_job_delete", @@ -995,6 +1221,8 @@ def _validate_risk(action: str, params: dict[str, Any]) -> Optional[str]: "poc_job_result_detail", }: missing.extend(_require_fields(params, "os_type")) + if action == "poc_job_rule_list": + pass # os_type 可选:win 时调用 /win/rule_list,否则调用通用 /rule_list(Linux) if action == "poc_detail": missing.extend(_require_fields(params, "recordId")) if action == "poc_job_delete": @@ -1096,11 +1324,78 @@ def _validate_baseline(action: str, params: dict[str, Any]) -> Optional[str]: return None +def _validate_fastjob(action: str, params: dict[str, Any]) -> Optional[str]: + missing: list[str] = [] + if action == "task_detail": + missing.extend(_require_fields(params, "taskId")) + if action in {"job_update", "job_delete"}: + missing.extend(_require_fields(params, "jobId")) + if action == "job_execute": + missing.extend(_require_fields(params, "id")) + if action in {"task_result", "task_error"}: + missing.extend(_require_fields(params, "taskRecordId")) + if action == "job_create": + if not _has_value(params.get("name")) and not _has_value(_dict_param(params, "body")): + missing.append("name/body") + if missing: + return f"Missing required parameters for fastjob.{action}: {', '.join(dict.fromkeys(missing))}" + return None + + +def _validate_assetdiscovery(action: str, params: dict[str, Any]) -> Optional[str]: + missing: list[str] = [] + if action in {"job_delete", "job_find", "job_execute"}: + if not _has_value(params.get("specId")) and not _has_value(_dict_param(params, "body")): + missing.append("specId/body") + if action == "job_update": + if not _has_value(params.get("specId")) and not _has_value(_dict_param(params, "body")): + missing.append("specId/body") + if action == "job_create": + if not _has_value(params.get("name")) and not _has_value(_dict_param(params, "body")): + missing.append("name/body") + if missing: + return f"Missing required parameters for assetdiscovery.{action}: {', '.join(dict.fromkeys(missing))}" + return None + + +def _validate_microseg(action: str, params: dict[str, Any]) -> Optional[str]: + missing: list[str] = [] + seg_write_actions = { + "seg_create", "seg_edit", "seg_delete", "seg_real_delete", "seg_retry", + "host_ms_enable", "host_access_control_mode", "host_run_status", + "host_protect_status", "host_limit_out", "host_black_strategy_enable", + } + if action in seg_write_actions: + if not _has_value(params.get("agentIds")) and not _has_value(_dict_param(params, "body")): + missing.append("agentIds/body") + if action == "seg_detail": + if not _has_value(params.get("agentId")) and not _has_value(_dict_param(params, "query")): + missing.append("agentId/query") + if action == "black_detail": + if not _has_value(params.get("id")) and not _has_value(_dict_param(params, "query")): + missing.append("id/query") + if action in {"black_update_switch", "black_delete"}: + if not _has_value(params.get("ids")) and not _has_value(_dict_param(params, "body")): + missing.append("ids/body") + if action in {"black_create", "black_update"}: + if not _has_value(params.get("strategyName")) and not _has_value(_dict_param(params, "body")): + missing.append("strategyName/body") + if action == "black_update": + if not _has_value(params.get("id")) and not _has_value(_dict_param(params, "body")): + missing.append("id/body") + if missing: + return f"Missing required parameters for microseg.{action}: {', '.join(dict.fromkeys(missing))}" + return None + + VALIDATORS = { "assets": _validate_assets, "risk": _validate_risk, "detect": _validate_detect, "baseline": _validate_baseline, + "fastjob": _validate_fastjob, + "assetdiscovery": _validate_assetdiscovery, + "microseg": _validate_microseg, } @@ -1174,3 +1469,15 @@ async def detect(ctx: ToolContext, action: str, **params: Any) -> ToolResult: async def baseline(ctx: ToolContext, action: str, **params: Any) -> ToolResult: return await _dispatch_group(ctx, "baseline", action, **params) + + +async def fastjob(ctx: ToolContext, action: str, **params: Any) -> ToolResult: + return await _dispatch_group(ctx, "fastjob", action, **params) + + +async def assetdiscovery(ctx: ToolContext, action: str, **params: Any) -> ToolResult: + return await _dispatch_group(ctx, "assetdiscovery", action, **params) + + +async def microseg(ctx: ToolContext, action: str, **params: Any) -> ToolResult: + return await _dispatch_group(ctx, "microseg", action, **params) diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.handler.py b/.flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.handler.py new file mode 100644 index 0000000..171fccf --- /dev/null +++ b/.flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.handler.py @@ -0,0 +1,19 @@ +import importlib.util +from pathlib import Path + +from flocks.tool.registry import ToolContext, ToolResult + + +def _load_core_module(): + script_path = Path(__file__).with_name("qingteng.handler.py") + spec = importlib.util.spec_from_file_location("_flocks_qingteng_core", str(script_path)) + if spec is None or spec.loader is None: + raise ImportError(f"Cannot create import spec for {script_path}") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +async def assetdiscovery(ctx: ToolContext, action: str, **kwargs) -> ToolResult: + core = _load_core_module() + return await core.assetdiscovery(ctx, action=action, **kwargs) diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.yaml b/.flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.yaml new file mode 100644 index 0000000..05bd521 --- /dev/null +++ b/.flocks/plugins/tools/api/qingteng/qingteng_asset_discovery.yaml @@ -0,0 +1,119 @@ +name: qingteng_asset_discovery +description: > + 青藤资产发现工具。支持查询已发现主机列表,以及创建/查询/更新/删除/执行资产扫描任务。 + 适用于对未安装 Agent 的主机进行网络扫描发现,了解全局资产状况。 +description_cn: > + 青藤资产发现工具。通过 `action` 参数访问主机发现结果和扫描任务管理接口。 +category: custom +enabled: true +requires_confirmation: true +provider: qingteng +inputSchema: + type: object + properties: + action: + type: string + description: | + 资产发现动作名,可选值: + - discovered_host_list + 用途: 获取已发现的主机列表(无需参数) + 是否任务型: 否 + - job_create + 用途: 创建资产扫描任务 + 必填: `name`(或 `body`) + 常用: `name`、`kind`、`values`、`cronExpression`、`osDetection`、`ipList`、`advanceConfigs` + 风险提示: 会触发网络扫描 + 是否任务型: 是 + - job_delete + 用途: 删除扫描任务 + 必填: `specId`(或 `body`) + 风险提示: 不可恢复 + 是否任务型: 否 + - job_find + 用途: 查询扫描任务配置详情 + 必填: `specId`(或 `body`) + 是否任务型: 否 + - job_update + 用途: 修改扫描任务配置(建议先 `job_find` 获取当前配置再修改) + 必填: `specId`(或 `body`) + 风险提示: 写操作 + 是否任务型: 否 + - job_list + 用途: 查询扫描任务列表 + 常用: `name`、`scanType` + 是否任务型: 否 + - job_execute + 用途: 立即执行扫描任务 + 必填: `specId`(或 `body`) + 风险提示: 会触发网络扫描 + 是否任务型: 是 + enum: + - discovered_host_list + - job_create + - job_delete + - job_find + - job_update + - job_list + - job_execute + specId: + type: string + description: 扫描任务配置 ID,适用于 `job_delete`、`job_find`、`job_update`、`job_execute` + name: + type: string + description: 任务名称,`job_create` 必填,`job_list` 支持模糊查询 + kind: + type: integer + description: > + 扫描发起主机类型。0=自定义主机;1=自定义业务组;2=全部主机。 + 注意:只能选择 Linux 主机作为扫描发起主机 + values: + type: array + items: + type: string + description: 当 `kind=0` 时传 agentId 列表,`kind=1` 时传 groupId 列表 + cronExpression: + type: string + description: Cron 表达式,用于定时执行,如 `0 15 * * *` + osDetection: + type: boolean + description: 是否启用操作系统探测 + ipList: + type: array + items: + type: string + description: 扫描 IP 范围列表 + advanceConfigs: + type: array + items: + type: object + description: 高级扫描配置列表,每项包含 `scanType`、`tcpPort`、`udpPort` 等 + scanType: + type: array + items: + type: integer + description: 扫描方式过滤,用于 `job_list` + query: + type: object + description: 额外 GET 查询参数对象 + body: + type: object + description: POST 请求体对象,与对应字段参数合并 + required: + - action + +handler: + type: script + script_file: qingteng_asset_discovery.handler.py + function: assetdiscovery + +notes: | + 调用流程: + 1. 自动使用已配置的凭据登录青藤,获取 jwt/signKey/comId + 2. 对请求参数进行 SHA1 签名 + 3. 调用对应 /external/api/discoveredhost/ 或 /external/api/assetdiscovery/ 接口 + + 典型用法: + - 用 `discovered_host_list` 查看当前已发现但未安装 Agent 的主机 + - 用 `job_create` 创建新的扫描任务,配置扫描发起主机和目标 IP 范围 + - 用 `job_execute` 立即触发扫描 + - 扫描完成后再次调用 `discovered_host_list` 查看新发现主机 diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_assets.yaml b/.flocks/plugins/tools/api/qingteng/qingteng_assets.yaml index badf6b6..cec0950 100644 --- a/.flocks/plugins/tools/api/qingteng/qingteng_assets.yaml +++ b/.flocks/plugins/tools/api/qingteng/qingteng_assets.yaml @@ -50,7 +50,7 @@ inputSchema: - delete_host 用途: 批量卸载 Agent 必填: `os_type` - 常用: `hostIds`、`agentIds`、`reason` + 常用: `hostIds`、`agentIds`、`reason`、`password`(MD5 加密的授权密码)、`allOffline`(true=卸载离线超7天主机) 风险提示: 高风险写操作,会影响主机受管状态 是否任务型: 是 - batch_create_group @@ -215,6 +215,12 @@ inputSchema: taskName: type: string description: 任务名称 + password: + type: string + description: MD5 加密的授权密码,用于 `delete_host` 时的身份验证 + allOffline: + type: boolean + description: 设为 true 时批量卸载离线超过 7 天的主机(`delete_host` 专用) hostInfoList: type: array items: diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_detect.yaml b/.flocks/plugins/tools/api/qingteng/qingteng_detect.yaml index f8e8b00..5b61a4f 100644 --- a/.flocks/plugins/tools/api/qingteng/qingteng_detect.yaml +++ b/.flocks/plugins/tools/api/qingteng/qingteng_detect.yaml @@ -45,6 +45,16 @@ inputSchema: 常用: `page`、`size`、`severity`、`status`、`hostId`、`groups`、`file_path`、`hostIds` 风险提示: 下载动作通常依赖已有下载任务 ID;列表类专属字段误传会被拦截 是否任务型: `scan` 为是 + - bounceshell_list + 用途: 查询反弹 Shell 检测结果 + 必填: 无(`os_type` 可选,不传默认 `linux`;传 `win` 查询 Windows) + 常用: `page`、`size`、`sorts`、`groups` + 是否任务型: 否 + - localrights_list + 用途: 查询本地提权检测结果(仅 Linux) + 必填: 无 + 常用: `page`、`size`、`sorts`、`groups` + 是否任务型: 否 - backdoor_list / backdoor_scan / backdoor_scan_status 用途: Linux/Windows 后门检测查询与扫描 必填: `os_type` diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_fastjob.handler.py b/.flocks/plugins/tools/api/qingteng/qingteng_fastjob.handler.py new file mode 100644 index 0000000..e862b6f --- /dev/null +++ b/.flocks/plugins/tools/api/qingteng/qingteng_fastjob.handler.py @@ -0,0 +1,19 @@ +import importlib.util +from pathlib import Path + +from flocks.tool.registry import ToolContext, ToolResult + + +def _load_core_module(): + script_path = Path(__file__).with_name("qingteng.handler.py") + spec = importlib.util.spec_from_file_location("_flocks_qingteng_core", str(script_path)) + if spec is None or spec.loader is None: + raise ImportError(f"Cannot create import spec for {script_path}") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +async def fastjob(ctx: ToolContext, action: str, **kwargs) -> ToolResult: + core = _load_core_module() + return await core.fastjob(ctx, action=action, **kwargs) diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_fastjob.yaml b/.flocks/plugins/tools/api/qingteng/qingteng_fastjob.yaml new file mode 100644 index 0000000..71e7e7a --- /dev/null +++ b/.flocks/plugins/tools/api/qingteng/qingteng_fastjob.yaml @@ -0,0 +1,168 @@ +name: qingteng_fastjob +description: > + 青藤快速任务(FastJob)工具。支持查看检测项列表、创建/编辑/删除/执行快速作业及查询执行结果。 + 适用于对单台或多台主机快速执行安全检测和应急响应任务。 +description_cn: > + 青藤快速任务(FastJob)工具。通过 `action` 参数访问快速任务的全部接口, + 包括任务模板查询、作业创建/执行/管理及结果查看。 +category: custom +enabled: true +requires_confirmation: true +provider: qingteng +inputSchema: + type: object + properties: + action: + type: string + description: | + 快速任务动作名,可选值: + - task_list + 用途: 查询快速任务检测项模板列表 + 常用: `osType`、`name`、`categories`、`page`、`size` + 是否任务型: 否 + - task_detail + 用途: 查询某一检测项模板的详细信息 + 必填: `taskId` + 是否任务型: 否 + - job_create + 用途: 创建一个快速作业 + 必填: `name`(或 `body`) + 常用: `name`、`osType`、`description`、`realm`、`taskType`、`taskId`、`taskParams`、`cron`、`cronEnable` + 风险提示: 写操作 + 是否任务型: 否 + - job_update + 用途: 编辑已有快速作业 + 必填: `jobId` + 常用: 同 `job_create` + 风险提示: 写操作 + 是否任务型: 否 + - job_delete + 用途: 删除快速作业 + 必填: `jobId` + 风险提示: 不可恢复 + 是否任务型: 否 + - job_list + 用途: 查询快速作业列表 + 常用: `osType`、`page`、`size`、`sorts` + 是否任务型: 否 + - job_execute + 用途: 立即执行某个快速作业 + 必填: `id`(作业 ID) + 风险提示: 会在目标主机触发扫描 + 是否任务型: 是 + - job_execute_list + 用途: 查询作业执行历史记录列表 + 常用: `osType`、`page`、`size`、`sorts` + 是否任务型: 否 + - task_result + 用途: 查看某次执行记录的结果 + 必填: `taskRecordId` + 是否任务型: 否 + - task_error + 用途: 查看某次执行记录中失败的主机列表 + 必填: `taskRecordId` + 是否任务型: 否 + enum: + - task_list + - task_detail + - job_create + - job_update + - job_delete + - job_list + - job_execute + - job_execute_list + - task_result + - task_error + taskId: + type: string + description: 快速任务检测项 ID,适用于 `task_detail` 和 `job_create` + jobId: + type: string + description: 快速作业 ID,适用于 `job_update`、`job_delete` + id: + type: string + description: 作业 ID,适用于 `job_execute` + taskRecordId: + type: string + description: 执行记录 ID,适用于 `task_result` 和 `task_error` + name: + type: string + description: 作业名称,`job_create`/`job_update` 必填 + osType: + type: integer + description: 操作系统类型,1=Linux,2=Windows + enum: + - 1 + - 2 + description: + type: string + description: 作业描述 + realm: + type: object + description: 作业目标主机范围。示例:`{"type":0}` 表示全部主机;`{"type":1,"agents":["agentId1"]}` 表示指定主机 + realmName: + type: string + description: 主机范围名称(显示用) + taskType: + type: integer + description: 任务类型 + taskParams: + type: array + items: + type: object + description: 任务参数列表 + cron: + type: string + description: Cron 表达式,用于定时执行 + cronEnable: + type: boolean + description: 是否启用定时执行 + categories: + type: array + items: + type: string + description: 检测项分类过滤,如 `["安全检测", "应急响应"]` + ids: + type: array + items: + type: string + description: 检测项 ID 列表过滤 + updatedTimeRange: + type: object + description: '更新时间范围过滤,格式 {"min": "yyyy-MM-dd HH:mm:ss", "max": "yyyy-MM-dd HH:mm:ss"}' + page: + type: integer + description: 页码,从 0 开始 + default: 0 + size: + type: integer + description: 每页数量 + default: 20 + sorts: + type: string + description: 排序字段 + query: + type: object + description: 额外 GET 查询参数对象 + body: + type: object + description: POST/PUT/DELETE 请求体对象,与对应字段参数合并 + required: + - action + +handler: + type: script + script_file: qingteng_fastjob.handler.py + function: fastjob + +notes: | + 调用流程: + 1. 自动使用已配置的凭据登录青藤,获取 jwt/signKey/comId + 2. 对请求参数进行 SHA1 签名 + 3. 调用对应 /external/api/fastjob/... 接口 + + 典型用法: + - 先用 `task_list` 找到需要运行的检测项 `taskId` + - 用 `job_create` 创建作业,指定 `taskId` 和主机范围 `realm` + - 用 `job_execute` 立即触发执行,获取 `taskRecordId` + - 用 `task_result` 查看结果,`task_error` 查看失败主机 diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_microseg.handler.py b/.flocks/plugins/tools/api/qingteng/qingteng_microseg.handler.py new file mode 100644 index 0000000..a7bcce0 --- /dev/null +++ b/.flocks/plugins/tools/api/qingteng/qingteng_microseg.handler.py @@ -0,0 +1,19 @@ +import importlib.util +from pathlib import Path + +from flocks.tool.registry import ToolContext, ToolResult + + +def _load_core_module(): + script_path = Path(__file__).with_name("qingteng.handler.py") + spec = importlib.util.spec_from_file_location("_flocks_qingteng_core", str(script_path)) + if spec is None or spec.loader is None: + raise ImportError(f"Cannot create import spec for {script_path}") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +async def microseg(ctx: ToolContext, action: str, **kwargs) -> ToolResult: + core = _load_core_module() + return await core.microseg(ctx, action=action, **kwargs) diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_microseg.yaml b/.flocks/plugins/tools/api/qingteng/qingteng_microseg.yaml new file mode 100644 index 0000000..a4bc2c5 --- /dev/null +++ b/.flocks/plugins/tools/api/qingteng/qingteng_microseg.yaml @@ -0,0 +1,316 @@ +name: qingteng_microseg +description: > + 青藤微隔离工具。支持一键隔离策略管理、主机微隔离状态控制及黑名单策略管理。 + 适用于对受感染主机实施网络隔离、配置访问控制策略及管理黑名单流量规则。 +description_cn: > + 青藤微隔离工具。通过 `action` 参数访问微隔离的全部接口, + 包括隔离策略增删改查、主机状态管理和黑名单策略管理。 +category: custom +enabled: true +requires_confirmation: true +provider: qingteng +inputSchema: + type: object + properties: + action: + type: string + description: | + 微隔离动作名,可选值: + + 【隔离策略】 + - seg_list + 用途: 查询一键隔离策略列表 + 常用: `page`、`size`、`groups`、`sorts` + 是否任务型: 否 + - seg_detail + 用途: 查询某主机的隔离策略详情 + 必填: `agentId` + 是否任务型: 否 + - seg_create + 用途: 为主机创建隔离策略 + 必填: `agentIds`(或 `body`) + 常用: `agentIds`、`remark`、`direction`、`ipList`、`portList` + 风险提示: 高风险,会阻断主机网络连接 + 是否任务型: 是 + - seg_edit + 用途: 修改隔离策略 + 必填: `agentIds`(或 `body`) + 常用: 同 `seg_create` + 风险提示: 高风险写操作 + 是否任务型: 否 + - seg_delete + 用途: 解除隔离(软删除) + 必填: `agentIds`(或 `body`) + 风险提示: 解除隔离后主机网络恢复 + 是否任务型: 是 + - seg_real_delete + 用途: 彻底删除隔离策略记录 + 必填: `agentIds`(或 `body`) + 风险提示: 不可恢复 + 是否任务型: 否 + - seg_retry + 用途: 重试隔离策略下发 + 必填: `agentIds`(或 `body`) + 是否任务型: 是 + + 【主机管理】 + - host_list + 用途: 查询微隔离主机列表 + 常用: `page`、`size`、`groups` + 是否任务型: 否 + - host_ms_enable + 用途: 修改主机微隔离开关 + 必填: `agentIds`(或 `body`) + 常用: `agentIds`、`enabled`(0=关闭,1=开启) + 风险提示: 写操作 + 是否任务型: 否 + - host_access_control_mode + 用途: 修改主机访问控制模式 + 必填: `agentIds`(或 `body`) + 常用: `agentIds`、`accessControlModeSetting` + 风险提示: 写操作 + 是否任务型: 否 + - host_run_status + 用途: 修改主机监控状态 + 必填: `agentIds`(或 `body`) + 常用: `agentIds`、`runStatusSetting`(如 "monitor") + 风险提示: 写操作 + 是否任务型: 否 + - host_protect_status + 用途: 修改主机阻断状态 + 必填: `agentIds`(或 `body`) + 常用: `agentIds`、`runStatusSetting`(如 "protect") + 风险提示: 高风险,会影响主机网络阻断行为 + 是否任务型: 否 + - host_limit_out + 用途: 修改主机出站限制开关 + 必填: `agentIds`(或 `body`) + 常用: `agentIds`、`limitOutSetting`(0=关闭) + 风险提示: 写操作 + 是否任务型: 否 + - host_black_strategy_enable + 用途: 修改主机黑名单策略开关 + 必填: `agentIds`(或 `body`) + 常用: `agentIds`、`blackStrategyEnableSetting`(true/false) + 风险提示: 写操作 + 是否任务型: 否 + + 【黑名单策略】 + - black_list + 用途: 查询黑名单策略列表 + 常用: `page`、`size`、`groups`、`sorts` + 是否任务型: 否 + - black_create + 用途: 创建黑名单策略 + 必填: `strategyName`(或 `body`) + 常用: `strategyName`、`ports`、`protos`、`switchStatus`、`dstGroupIds`、`srcGroupIds` + 风险提示: 写操作,会影响网络流量 + 是否任务型: 否 + - black_update + 用途: 修改黑名单策略 + 必填: `id`、`strategyName`(或 `body`) + 风险提示: 写操作 + 是否任务型: 否 + - black_update_switch + 用途: 批量修改黑名单策略开关 + 必填: `ids`(或 `body`) + 常用: `ids`、`switchStatus`(0=关闭,1=开启) + 风险提示: 写操作 + 是否任务型: 否 + - black_delete + 用途: 删除黑名单策略 + 必填: `ids`(或 `body`) + 风险提示: 不可恢复 + 是否任务型: 否 + - black_host_list + 用途: 查看某条黑名单策略的主机范围 + 常用: `strategyId`、`page`、`size`、`ip`、`msSwitchStatus`、`strategyHostType` + 是否任务型: 否 + - black_detail + 用途: 查看黑名单策略详情 + 必填: `id` + 是否任务型: 否 + enum: + - seg_list + - seg_detail + - seg_create + - seg_edit + - seg_delete + - seg_real_delete + - seg_retry + - host_list + - host_ms_enable + - host_access_control_mode + - host_run_status + - host_protect_status + - host_limit_out + - host_black_strategy_enable + - black_list + - black_create + - black_update + - black_update_switch + - black_delete + - black_host_list + - black_detail + agentId: + type: string + description: 单个主机 Agent ID,适用于 `seg_detail` + agentIds: + type: array + items: + type: string + description: 主机 Agent ID 列表,适用于隔离策略写操作和主机管理写操作 + id: + type: string + description: 黑名单策略 ID,适用于 `black_update`、`black_detail` + ids: + type: array + items: + type: string + description: 黑名单策略 ID 列表,适用于 `black_update_switch`、`black_delete` + remark: + type: string + description: 备注信息 + direction: + type: string + description: 隔离方向,如 `"out"`(出站) + ipList: + type: array + items: + type: string + description: 白名单 IP 列表(隔离时允许访问的 IP) + portList: + type: array + items: + type: string + description: 白名单端口列表(隔离时允许访问的端口) + enabled: + type: integer + description: 微隔离开关,0=关闭,1=开启 + accessControlModeSetting: + type: integer + description: 访问控制模式设置 + runStatusSetting: + type: string + description: 监控/阻断状态设置,如 `"monitor"` 或 `"protect"` + limitOutSetting: + type: integer + description: 出站限制设置,0=关闭 + blackStrategyEnableSetting: + type: boolean + description: 黑名单策略开关设置 + strategyName: + type: string + description: 黑名单策略名称 + ports: + type: array + items: + type: string + description: 端口列表,如 `["7788", "80"]` + protos: + type: array + items: + type: string + description: 协议列表,如 `["TCP", "UDP"]` + displayPort: + type: string + description: 展示用端口描述字符串 + switchStatus: + type: integer + description: 策略开关状态,0=关闭,1=开启 + dstTagIds: + type: array + items: + type: string + description: 目标主机标签 ID 列表 + dstGroupIds: + type: array + items: + type: integer + description: 目标主机业务组 ID 列表 + dstRealmType: + type: integer + description: 目标主机范围类型 + dstIpList: + type: array + items: + type: object + description: 目标 IP 范围列表 + srcTagIds: + type: array + items: + type: string + description: 源主机标签 ID 列表 + srcGroupIds: + type: array + items: + type: integer + description: 源主机业务组 ID 列表 + srcRealmType: + type: integer + description: 源主机范围类型 + srcAgentIds: + type: array + items: + type: string + description: 源主机 Agent ID 列表 + srcIpList: + type: array + items: + type: object + description: 源 IP 范围列表 + strategyId: + type: string + description: 黑名单策略 ID,用于 `black_host_list` 过滤 + strategyHostType: + type: integer + description: 策略主机类型过滤,0=全部 + msSwitchStatus: + type: integer + description: 微隔离开关状态过滤 + ip: + type: string + description: IP 模糊查询 + groups: + type: string + description: 业务组 ID 过滤,逗号分隔 + page: + type: integer + description: 页码,从 0 开始 + default: 0 + size: + type: integer + description: 每页数量 + default: 20 + sorts: + type: string + description: 排序字段 + query: + type: object + description: 额外 GET 查询参数对象 + body: + type: object + description: POST/DELETE 请求体对象,与对应字段参数合并 + required: + - action + +handler: + type: script + script_file: qingteng_microseg.handler.py + function: microseg + +notes: | + 调用流程: + 1. 自动使用已配置的凭据登录青藤,获取 jwt/signKey/comId + 2. 对请求参数进行 SHA1 签名 + 3. 调用对应 /external/api/ms-srv/api/... 接口 + + ⚠️ 高风险操作说明: + - `seg_create`/`seg_edit`: 会直接阻断主机网络连接,操作前请确认目标主机 agentId 正确 + - `host_protect_status`: 开启阻断模式后主机将无法建立新的出站连接 + - `black_create`/`black_update`: 黑名单策略一旦下发将立即生效 + + 典型应急响应流程: + 1. `host_list` 找到目标主机 agentId + 2. `seg_create` 对目标主机实施网络隔离 + 3. 取证完成后 `seg_delete` 解除隔离 diff --git a/.flocks/plugins/tools/api/qingteng/qingteng_risk.yaml b/.flocks/plugins/tools/api/qingteng/qingteng_risk.yaml index 8c8601c..19e5705 100644 --- a/.flocks/plugins/tools/api/qingteng/qingteng_risk.yaml +++ b/.flocks/plugins/tools/api/qingteng/qingteng_risk.yaml @@ -59,7 +59,7 @@ inputSchema: 是否任务型: 仅 `poc_scan` 为是 - poc_job_rule_list / poc_job_add / poc_job_fix / poc_job_delete / poc_job_execute / poc_job_status / poc_job_error_host / poc_job_list / poc_job_tasks / poc_job_stats / poc_job_result_detail 用途: 漏洞检测作业管理与结果查询 - 必填: `os_type`;删除通常需要 `jobId` + 必填: `poc_job_rule_list` 的 `os_type` 为可选(不传或传 `linux` 时调用通用规则列表,传 `win` 时调用 Windows 规则列表);其余动作通常需要 `os_type`;删除通常需要 `jobId` 常用: `jobName`、`ruleIds`、`groups`、`hostIds`、`schedule` 风险提示: 写操作较多,建议先确认任务目标范围 是否任务型: 是 diff --git a/pyproject.toml b/pyproject.toml index 6ca38c2..90aa608 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "flocks" -version = "v2026.4.9" +version = "v2026.4.10" description = "AI-Native SecOps platform with multi-agent collaboration" authors = [ {name = "Flocks Team", email = "team@example.com"}