
在一次针对某私有程序的安全性测试中,我们发现了一个与双因素认证(2FA)机制相关的逻辑漏洞。该漏洞允许攻击者在无需账号密码的情况下,向任意已启用2FA的受害者邮箱发送验证码,并最终接管其账户。据评估,受影响的用户数量超过2.5万名。
标准双因素认证(2FA)登录流程分析
为理解漏洞,首先需要回顾正常的2FA登录流程:
-
提交凭证:用户提交用户名和密码进行首次验证。
服务器返回的响应中包含了两个关键信息:
id:受害者的内部邮箱标识符,用于后续请求识别目标邮箱。
preauth_token:预认证令牌,用于后续发送和验证一次性密码(OTP)的请求。
-
请求发送OTP:客户端使用上一步获得的 preauth_token 向服务器发送请求,系统会向用户的邮箱发送一个6位数的验证码。

-
提交并验证OTP:用户输入收到的验证码,客户端将其与 preauth_token 以及上一步返回的 token 一同提交给服务器进行最终验证。

关键点:preauth_token 和 token 的格式均为 <victim_id>.<random_token>,其中 victim_id 是一个可预测或枚举的数字ID。
漏洞利用步骤详解
第一步:利用预认证令牌漏洞发送OTP
在“发送OTP”的请求中,攻击者可以绕过密码验证环节。原请求需要使用登录后返回的完整 preauth_token。我们发现,只需要在该参数的 <victim_id> 部分填入目标的 id,而将 <random_token> 部分置空,请求即可成功。

这意味着,攻击者若获取到目标的邮箱地址(通常可从公开资料获得)并通过枚举得到对应的 id,便可直接向该邮箱发送验证码,完全跳过了用户名密码验证步骤。
第二步:绕过OTP验证的令牌绑定
在最终的验证请求中,需要同时提供 preauth_token 和 token。我们尝试将这两个参数的值都设置为第一步“发送OTP”请求响应中返回的 token。

实验证明该操作成功。当验证码正确时,服务器返回 200 OK 以及受害者的 JWT令牌,意味着账户被成功接管。
为何这样可行? 核心问题在于服务端未正确校验 preauth_token 与 token 之间的绑定关系以及其来源的合法性。这使得攻击者可以使用同一个令牌值来完成验证流程,从而绕过了双因素认证的保护。
第三步:暴力破解OTP与绕过速率限制
由于OTP仅为6位数字,理论上可以进行暴力破解。但在实际测试中,直接进行大量尝试会触发速率限制,返回 429 Too Many Requests 错误。
为了绕过此防御,我们采用了 IP轮换 技术。通过编写Python脚本,在每次触发速率限制时自动切换代理IP地址,从而有效避开了WAF(Web应用防火墙)和请求频率限制。

完整的攻击链整合
综合上述发现,完整的账户接管攻击链如下:
- 信息收集:从目标的公开个人资料获取其邮箱地址。
- 枚举目标ID:通过暴力破解,在“发送OTP”请求的
preauth_token 参数中尝试不同的 id 值,直到请求成功(即找到与邮箱对应的正确 id)。
- 发送验证码:使用正确的
id 向目标邮箱发送OTP,并从服务器响应中获取 token。
- 暴力破解OTP:在“验证OTP”的请求中,将
preauth_token 和 token 参数均设置为上一步获取的 token 值,并配合 IP轮换 技术对6位数验证码进行暴力破解。
- 获取访问凭证:当正确的验证码被命中,攻击者即可获得代表目标身份的有效会话令牌,完成账户接管。
尽管该漏洞因“暴力破解环节超出测试范围”未被程序方采纳,但其揭示的双因素认证在令牌验证逻辑、绑定关系及防暴破机制上的缺陷,具有典型的研究和警示意义。
|