在分析一个Web应用程序的“更改电话号码”功能时,我注意到表单和标头中没有CSRF令牌,这表明该应用程序可能容易受到跨站请求伪造 (CSRF) 攻击。我的目标是利用此漏洞更改受害者的电话号码,最终实现账户接管。
什么是 CSRF 攻击?
跨站请求伪造 (CSRF) 是一种恶意攻击方式,攻击者能够诱骗已通过认证的用户,在其当前登录的Web应用程序上执行非本意的操作。
例如,若用户登录了银行会话并访问了一个恶意网站,攻击者就可以伪造请求,将资金从用户账户转移至攻击者账户,整个过程无需征得用户同意。
漏洞初探
更改电话号码的原始请求如下所示:
POST /change_phone HTTP/1.1
主机:example.com
Cookie:session_cookie=YOUR_SESSION_COOKIE
number=011.xxxxxx
值得注意的是,请求中没有任何CSRF令牌,这使其成为了一个潜在的攻击目标。
初次利用尝试
我编写了一个概念验证 (PoC) 来利用这个CSRF漏洞。然而,在测试时,PoC并未按预期工作。这引出了一个关键问题:漏洞利用为何会失败?
深入调查原因
我怀疑应用程序可能执行了服务器端验证,而不仅仅依赖于客户端验证。这或许能解释为什么缺少CSRF令牌的利用尝试会失败。我推测服务器可能通过以下方式之一来验证请求:
- 引荐来源标头验证:服务器检查
Referer 标头,以确保请求来自受信任的域。
- 来源标头验证:服务器验证
Origin 标头以确认请求来源。
- 隐藏参数验证:请求中可能存在一个用于验证的隐藏参数。
在排除了通过 Referer 或 Origin 标头进行验证的可能性后,我将注意力集中在了隐藏参数上。
识别隐藏参数
为了证实猜想,我使用了 Burp Suite 中的 Param Miner 扩展来强制发现隐藏参数,特别是那些可能用于CSRF保护的参数。作为一个强大的渗透测试工具,Burp Suite 是发现此类安全缺陷的利器。
关键发现
一段时间后,我发现了一个名为 C-token 的隐藏参数。此参数在初始请求中并不可见,但似乎是服务器用于验证的泄露令牌。为了获取其值,我搜索了Burp Suite的历史记录,成功找到了 C-token 泄露的实例。
更新攻击载荷
获取到 C-token 参数后,我创建了一个新的PoC,将此令牌包含在请求中。更新后的请求如下所示:
POST /change_phone HTTP/1.1
主机:example.com
Cookie:session_cookie=YOUR_SESSION_COOKIE
number=011.xxxxxx&C-token=My.token.xxxxxx
测试更新后的PoC成功利用了漏洞,使我能够更改自己的电话号码。
绕过令牌复用限制
然而,当目标为其他用户时,漏洞利用仍然没有成功。经过进一步调查,我发现服务器的验证机制存在缺陷。
服务器维护着一个固定令牌数组,它会检查请求中的令牌是否与数组中任一令牌匹配。但服务器允许同一个令牌在多个请求中重复使用,只是不能在连续的请求中重复使用。这留下了一个可被利用的漏洞窗口。
我在Burp Suite的历史记录中发现了多个泄露的 C-token(例如 token1, token2, token3)。为了绕过服务器的验证规则,我采用了交替使用令牌的策略:
- 第一个请求:使用
token1。
- 第二个请求:使用
token2。
- 第三个请求:恢复使用
token1。
这种方法成功地绕过了服务器的令牌验证机制,最终实现了对受害者账户的接管。
如何防止 CSRF 攻击
为了保护应用程序免受CSRF攻击,建议实施以下安全措施:
- 使用唯一且随机的令牌:为每个用户会话或每个敏感请求生成并验证唯一的CSRF令牌。
- 验证来源和引用标头:检查
Origin 和 Referer 标头,确保请求来自可信源。
- 使用 SameSite Cookies:为Cookie设置
SameSite 属性(如 Strict 或 Lax),限制跨站请求的Cookie发送。
- 实施双重提交Cookie:在请求参数和Cookie中都包含一个随机值,并在服务端验证两者是否匹配。
- 关键操作二次验证:对修改密码、转账等敏感操作,强制用户重新输入密码或使用多重身份验证 (MFA)。
结论
这个漏洞案例凸显了强大的服务器端验证机制的重要性,同时也揭示了依赖隐藏参数实现安全性的潜在风险。通过深入理解应用程序的请求验证逻辑,我成功利用了CSRF漏洞并最终实现了账户接管。这提醒开发者在设计安全功能时,必须考虑逻辑的严谨性,避免因实现缺陷导致防护机制形同虚设。