Google Threat Intelligence Group(GTIG)正在逐步启用统一的威胁行为者命名体系。变化不只是给组织“改名”,而是把过去由 Mandiant 与 Google Threat Analysis Group(TAG)分别维护的追踪系统合并,并尝试让名称直接携带防御人员需要的上下文。
新体系采用两个单词组成的 cryptonym(代号):第一个单词标识具体行为者,第二个单词表达来源、动机或活动类型。相比 APT1 这类依赖记忆和外部查询的编号,语义化后缀能帮助分析人员更快完成分类、检索和响应。
两个单词分别解决什么问题
代号的第一个单词要求唯一、容易记忆。若某个组织此前已在公开报告中使用过稳定名称,GTIG 会优先考虑延续该词;没有合适旧名称时,则随机生成候选词,再由分析人员审核,以减少命名中的主观偏见。
第二个单词承担分类功能。已公布的示例映射包括:
| 来源或类型 | 第二个单词 |
|---|---|
| 中华人民共和国 | CASTLE |
| 伊朗 | ION |
| 朝鲜 | NEPTUNE |
| 俄罗斯 | RELIC |
| 网络犯罪组织 | COMET |
这意味着分析人员看到一个以 COMET 结尾的名称时,可以立即把它放入网络犯罪活动的调查语境;看到 RELIC,则知道该分类与俄罗斯相关。名称不能替代证据,但可以减少团队在告警分诊时反复查表的成本。
分类依据也不一定只代表国家归属。GTIG 会根据防御与响应策略中最重要的维度,在动机、归因或活动类型之间作出选择。因此,后缀更适合被理解为“当前最有操作价值的分类”,而不是永久不变的身份结论。
统一命名不等于统一实体
威胁情报行业长期存在多套命名体系。同一个攻击活动可能被不同厂商赋予多个别名;反过来,一个厂商追踪的群组也未必与另一家定义的群组完全重合。
根本原因是可见性不同。邮件服务商、终端安全厂商、云平台与事件响应团队掌握的遥测数据并不相同,对基础设施、恶意软件和受害者集合的聚类边界自然会有差异。因此,别名映射应表达“有关联”或“当前认为对应”,不能自动推导出两个对象严格相等。
GTIG 会保留旧名称、MITRE ATT&CK 映射及其他厂商别名,并允许在 Google Threat Intelligence 平台中继续搜索这些标识。这对迁移很重要:历史检测规则、事件工单和情报报告不需要在同一天全部改写。
对于尚处于调查早期、无法可靠分类的威胁集群,GTIG 仍将使用 UNC(uncategorized)标识。它传递的是分析置信度边界,而不是一个等待美化的正式名称。
可以这样实践:建立可审计的别名解析器
下面是一个可直接运行的 Python 示例,用于把旧名称或其他厂商别名解析为团队内部采用的规范名称。示例中的行为者和对应关系均为演示数据,不代表 GTIG 已公布的真实映射。
将代码保存为 resolve_actor.py,使用 Python 3.9 或更高版本运行:
#!/usr/bin/env python3
import argparse
from dataclasses import dataclass
from typing import Dict, List, Optional
@dataclass(frozen=True)
class Actor:
canonical_name: str
category: str
aliases: List[str]
confidence: str
ACTORS = [
Actor(
canonical_name="SAMPLE COMET",
category="cybercriminal",
aliases=["Legacy-Fin-01", "Vendor-Cluster-X"],
confidence="medium",
),
Actor(
canonical_name="DEMO RELIC",
category="russia-linked",
aliases=["Legacy-Espionage-02"],
confidence="high",
),
Actor(
canonical_name="UNC-9000",
category="uncategorized",
aliases=["Emerging-Cluster-7"],
confidence="low",
),
]
def build_index(actors: List[Actor]) -> Dict[str, Actor]:
index: Dict[str, Actor] = {}
for actor in actors:
for name in [actor.canonical_name, *actor.aliases]:
key = name.casefold()
if key in index and index[key] != actor:
raise ValueError(f"Conflicting alias: {name}")
index[key] = actor
return index
def resolve(name: str) -> Optional[Actor]:
return build_index(ACTORS).get(name.casefold())
def main() -> None:
parser = argparse.ArgumentParser(description="Resolve threat actor aliases")
parser.add_argument("name", help="Canonical name or historical alias")
args = parser.parse_args()
actor = resolve(args.name)
if actor is None:
raise SystemExit(f"No mapping found for: {args.name}")
print(f"canonical_name={actor.canonical_name}")
print(f"category={actor.category}")
print(f"confidence={actor.confidence}")
print(f"aliases={','.join(actor.aliases)}")
if __name__ == "__main__":
main()
运行查询:
python3 resolve_actor.py 'Legacy-Fin-01'
python3 resolve_actor.py 'UNC-9000'
生产环境不应只保存一张无版本的别名表。至少还应记录映射来源、首次与最后确认时间、分析置信度,以及 related、overlaps、supersedes 等关系类型。只有证据足够时,才把关系标记为 equivalent。
迁移时应保护哪些接口
GTIG 会分批重命名数十个最活跃的组织,而不是一次性切换全部记录。企业内部也适合采用渐进迁移:
- 使用稳定的内部 ID 作为数据库主键,不要把展示名称当作实体身份。
- 在 SIEM、SOAR 和威胁情报平台中同时索引规范名称与历史别名。
- 检测规则优先引用技术指标、行为和 ATT&CK 技术,不要仅匹配组织名称。
- 在报告中显示规范名称,同时保留“原称”与厂商别名,避免历史工单失联。
- 对
UNC集群明确标注低置信度和调查状态,避免业务方把临时聚类误读成已确认归因。
语义化名称能缩短识别时间,却不会消除归因的不确定性。真正可靠的落地方式,是把名称视为可变的展示层,把稳定 ID、证据、关系类型和时间版本留在数据模型中。