4. 攻击者视角

要建立有效的收款账户变更控制,必须先理解对手。BEC(Business Email Compromise,商务电子邮件诈骗)不是单点黑客行为,而是一条分工明确、以“人”为突破口、以“钱”为终点的犯罪产业链。本节从攻击者视角出发,拆解其动机、组织、选目标、情报收集与社工手法,帮助防御方把控制点布在攻击链的必经之路上。

一、核心原理:BEC是一门“低技术、高回报”的生意

BEC团伙的核心逻辑并不依赖漏洞利用,而是利用信任关系与业务流程惯性。他们通常不需要入侵服务器,只需获得一个可信邮箱的访问权或伪造一个高度相似的邮箱,就能在“正常业务对话”中插入一条变更收款账户的指令。其收益模型可概括为:

  • 低成本:钓鱼邮件、域名注册、云邮箱试用账号即可起步。
  • 高杠杆:一封邮件可能触发数十万至数百万的转账。
  • 低风险:跨境资金快速分流,取证与追回难度大。
  • 可复制:模板化话术与目标清单可反复使用。
核心公式:BEC成功 = 可信身份 × 业务语境 × 时间压力 × 验证缺失。防御的关键,就是破坏其中任意一项。

二、动机与组织分工:从“写手”到“取款人”的流水线

BEC团伙的动机以直接经济利益为主,部分团伙兼具商业间谍目的(窃取并购、报价、税务信息)。其组织通常呈现分层协作:

角色 主要职责 关键产出
情报收集者 搜集高管、财务、供应商信息与邮件格式 目标清单、组织架构、话术素材
钓鱼/入侵者 投放凭证钓鱼、劫持邮箱会话 可用的邮箱访问权或伪造域名
话术写手 编写符合业务语境的变更请求邮件 高仿真邮件模板与回复链
资金操作者 提供收款账户、拆分转账、洗钱 多层账户与快速提现路径
取款/车手 ATM取现、购买贵金属或加密货币 现金或不可逆资产

这种分工意味着:即使你阻断了一个环节,团伙也可能换人换号继续尝试。因此控制措施必须覆盖“身份、语境、资金”三条线。

三、目标选择与信息收集:谁容易被盯上

攻击者偏好有付款权限、有供应商关系、有公开信息的岗位。常见目标包括:财务总监、应付会计、采购经理、CEO助理、法务与并购负责人。选择逻辑如下:

  1. 资金流可见:能发起或审批付款。
  2. 信息暴露多:官网、领英、招标公告、年报中可获取姓名、职务、邮箱格式。
  3. 业务节奏紧:月末、季末、并购期、审计期,时间压力大。
  4. 跨时区/跨语言:沟通延迟使验证更难。

信息收集手段包括:爬取企业官网与新闻稿、分析邮件签名与自动回复、利用泄露凭证库、观察社交媒体动态、甚至致电前台套取组织信息。攻击者会刻意模仿内部邮件格式、引用真实项目编号,使变更请求“看起来完全合理”。

BEC攻击链与防御控制点 目标选择 财务/采购/高管 信息收集 官网/领英/泄露库 社工与钓鱼 伪造身份/劫持会话 账户变更请求 邮件/电话/IM 资金转移 多层账户/洗钱 取现/变现 ATM/加密资产 防御控制点 1. 邮箱安全:MFA、条件访问、异常登录告警 2. 流程控制:变更收款账户必须双人复核 3. 验证机制:回拨已知号码,禁用邮件内号码 4. 资金监控:新账户首笔小额验证、延迟到账

四、社工手段与典型场景:为什么聪明人也会上当

BEC社工的核心是制造合理性与紧迫感。常见手法包括:

  • CEO欺诈:冒充高管,要求财务“紧急支付”并购款或供应商欠款。
  • 供应商账户变更:冒充长期供应商,称“银行账户升级”,附上伪造的盖章文件。
  • 邮件线程劫持:入侵真实邮箱后,在原有对话中插入变更请求,回复链完整可信。
  • 相似域名:注册与真实域名仅差一两个字符的域名,如 rn 代替 m。
  • 电话+邮件组合:先邮件铺垫,再电话催促,降低受害者核实意愿。
典型误区:认为“我们公司小,不会被盯上”。实际上,中小企业的财务流程更简化、人员更少、验证更弱,反而是BEC的高发区。

一个常见场景是:攻击者先监控财务与供应商的邮件往来,选择在月末付款高峰期,冒充供应商发送“因银行合并,请将后续款项付至新账户”的邮件,并附上伪造的银行证明。财务人员若仅通过邮件回复确认,就会落入圈套。

五、复盘与防御启示

从攻击者视角复盘,可以得出三条防御原则:

  1. 身份不可仅凭邮件确认:任何收款账户变更,必须通过独立渠道(已知电话、视频、面对面)回拨核实。
  2. 流程不可被时间压力绕过:设置“变更冷却期”与双人审批,紧急请求反而要触发更严格验证。
  3. 监控要覆盖异常信号:新登录地、邮件规则创建、大量转发、相似域名注册,都是早期预警。
# 示例:检测邮箱异常规则的伪代码
if user.created_inbox_rule:
    if rule.action in ["forward", "delete", "move_to"]:
        alert("可疑邮件规则", user, rule)
if login.geo not in user.known_geo:
    alert("异常登录地点", user, login.geo)