竞争条件漏洞分析 | 第一部分
在深入研究了文件上传漏洞的第一部分和第二部分之后,我以为自己对Web应用程序安全有了很好的掌握。但后来我偶然发现了一个不同的"野兽":竞争条件。这些不是关于欺骗文件类型或扩展名;而是关于利用应用程序随时间处理请求的基本结构。
想象一个网站,您可以在那里获得一次性折扣。您应用代码,它起作用了。简单,对吧?但是,如果您可以多次应用该折扣,将20%的折扣变成200%的折扣呢?这就是竞争条件的魔力(或威胁),特别是"限制超限"。
在这篇文章中,我将引导您了解我如何利用经典的"限制超限"竞争条件,借鉴PortSwigger的Web安全学院实验室的见解。这不仅仅是理论上的;这些缺陷可能导致企业严重的经济损失和攻击者的意外收益。
什么是竞争条件?
竞争条件的核心发生在系统的行为依赖于不可控事件的序列或时间安排时。在Web应用程序中,这通常意味着几乎同时向服务器发送多个请求,希望它们以特定的、易受攻击的顺序到达服务器。
“限制超限"场景
让我们以折扣代码为例。应用一次性折扣的典型应用程序流程可能如下所示:
- 检查:用户是否已经使用了此代码?
- 应用:如果没有,将折扣应用到订单。
- 更新:在数据库中标记代码为已使用。
这看起来很健壮。如果您尝试重用代码,初始检查应该会阻止您。但是,如果两个请求在第一个请求的"更新"完成之前几乎同时到达服务器,导致两个请求都进行了"检查"呢?
这创建了一个微小的"竞争窗口”——一个临时的子状态,此时应用程序是脆弱的。如果您能在此窗口内发送多个请求,就可以绕过"一次性"限制。
我在现实场景中见过这种变体:
- 多次兑换礼品卡
- 提取超过账户可用金额的钱
- 重复使用单个CAPTCHA解决方案
- 绕过反暴力破解的速率限制
这些都是"检查时间到使用时间"(TOCTOU)缺陷的子类型,即条件被检查,但在使用之前发生了变化。
使用Burp Repeater进行检测和利用
找到这些微小的竞争窗口可能像大海捞针。但使用正确的工具,它会变得更容易管理。Burp Suite的Repeater,特别是其新功能,对此是一个改变游戏规则的工具。
实验室:折扣超限
我在PortSwigger的Web安全学院解决了一个实验室,目标是通过利用折扣代码竞争条件以意外价格购买"轻量级L33t皮夹克"。凭据是wiener:peter。
步骤1:理解流程
首先,我登录并购买了最便宜的商品,确保使用提供的折扣代码,以便我可以研究购买流程。在Burp中,从代理历史中,我确定了所有允许我与购物车交互的端点。例如,POST /cart请求将商品添加到购物车,POST /cart/coupon请求应用折扣代码。
我还将GET /cart请求发送到Burp Repeater,并确认如果没有会话cookie,我只能访问空购物车。由此,我可以推断:
- 购物车的状态存储在服务器端的会话中。
- 对购物车的任何操作都基于您的会话ID或相关的用户ID。
这表明存在潜在的冲突可能。
我注意到,如果我尝试多次应用折扣代码,我会收到"优惠券已应用"的响应。这确认了它是单次使用代码。
步骤2:基准行为测试(顺序请求)
为了理解服务器的响应时间,我清除了购物车中任何已应用的折扣代码。然后,我将POST /cart/coupon请求发送到Repeater。在Repeater中,我将新标签页添加到组中。然后,我右键单击分组的标签页并选择"复制标签页",创建了19个重复标签页。新标签页自动添加到组中。
我使用单独连接按顺序发送这组请求,以减少干扰的机会。正如预期,第一个响应确认折扣成功应用,但其余响应一致地以相同的"优惠券已应用"消息拒绝代码。这建立了基线。
步骤3:探测线索(并行请求)
现在是真正的测试。我再次从购物车中移除折扣代码。在Repeater中,我再次发送这组请求,但这次是并行发送,有效地同时多次应用折扣代码。这就是Burp Repeater强大的新功能发挥作用的地方,特别是其HTTP/2单包攻击,可以在单个TCP数据包中同时发送20-30个请求,中和网络抖动。
我研究了响应,并观察到多个请求收到了指示代码成功应用的响应!就是这样——竞争条件被触发了。
在浏览器中,我刷新了购物车,并确认20%的减免被应用了多次,导致订单价格显著降低。限制被超限了!
我是如何发现的:通过使用Burp Repeater并行发送多个请求,我能够在竞争窗口内击中服务器,导致在数据库更新之前多次应用折扣。
Turbo Intruder:竞争条件专家
虽然Burp Repeater对于快速测试并行请求非常出色,但一些竞争条件需要更高的精度、更多尝试或更复杂的序列。这就是Turbo Intruder的用武之地。它是Burp Suite的一个扩展,允许高度定制的高性能攻击序列,通常需要一些Python脚本。
它特别强大,因为它也支持单包攻击技术,就像Repeater一样,但让您可以精细控制请求的发送方式和时间。如果您正在处理极其紧张的竞争窗口或需要编排复杂的攻击,Turbo Intruder是您的首选。
实验室:通过竞争条件绕过速率限制
我深入研究了另一个PortSwigger实验室,这次是一个"从业者"级别的挑战:“通过竞争条件绕过速率限制”。目标很明确:暴力破解用户carlos在受速率限制保护的登录机制上的密码,然后登录并删除他的账户。我自己的测试账户的凭据是wiener:peter。
挑战:登录机制在超过三次错误密码尝试后会暂时封锁账户。这意味着标准的暴力攻击将无效。
步骤1:预测潜在的冲突(理解速率限制)
我的第一步是理解速率限制如何工作。我故意为我的wiener账户提交了错误的密码。
在三次错误尝试后,应用程序暂时封锁了我的账户。
我尝试使用另一个任意用户名登录,并观察到正常的"无效用户名或密码"消息。这确认了速率限制是按用户名强制执行的,而不是按会话。
这是一个关键的线索。服务器必须为每个用户名存储一个失败尝试计数器。这意味着存在一个竞争窗口:
- 在我提交登录尝试时。
- 和网站为该用户名增加失败尝试计数器时。
如果我能在这个微小窗口内为carlos发送多个登录尝试,我可能会绕过三次尝试的限制。
步骤2:基准行为测试(顺序请求)
为了获得基线,我在Burp代理历史中找到了一个POST /login请求(用于不成功的登录)并将其发送到Repeater。然后我复制了这个标签页19次,创建了一组20个相同的请求。我将这些设置为按顺序发送。
正如预期,在另外两次失败的登录尝试(总共三次)之后,我的账户被暂时锁定。这确认了在正常的顺序条件下,速率限制确实活跃且按预期工作。
步骤3:探测线索(并行请求)
现在是竞争的时候了。我使用Repeater并行发送相同的20个请求组。我的目标是压倒服务器,并在其能够更新失败登录计数器之前用许多尝试击中它。
我研究了响应。尽管账户最终被锁定,但我注意到在锁定消息出现之前,超过三个请求收到了正常的"无效用户名和密码"响应。这就是证据!如果我足够快,我可以在触发账户锁定之前提交超过三个登录尝试。
步骤4:证明概念(使用Turbo Intruder进行暴力破解)
竞争窗口被确认后,是时候自动化暴力破解了。我将其中一个POST /login请求发送到Turbo Intruder。
- 在Turbo Intruder中,密码参数自动被标记为有效载荷位置(
%s)。 - 我将请求中的
username参数更改为carlos。 - 从下拉菜单中,我选择了
examples/race-single-packet-attack.py模板。这个模板正是为这种HTTP/2单包竞争攻击设计的。 - 我将提供的候选密码列表(123123, abc123, football, 等)复制到剪贴板。
- 我编辑了Turbo Intruder中的Python脚本,以使用
wordlists.clipboard中的每个密码排队登录请求。
我启动了攻击。Turbo Intruder并行发送所有密码猜测,利用竞争条件。我仔细研究了响应。如果没有出现成功的登录,我会等待账户锁定重置并重复攻击,可能优化密码列表。
最终,其中一个响应返回了302 Found状态,表示成功登录!我从有效载荷列记下了相应的密码。
步骤5:访问管理面板并解决实验室
在账户锁定重置后(如果被触发),我使用识别出的密码以carlos身份登录。然后我访问了管理面板并删除了用户carlos以解决实验室。
如果您有任何问题或需要进一步澄清,请随时联系。此外,您可以通过以下方式保持联系以获取更多高级网络安全见解和更新:
🔹 GitHub: @0xEhab 🔹 Instagram: @pjo_ 🔹 LinkedIn: https://www.linkedin.com/in/ehxb/
请继续关注更全面的文章和教程,以加深您的网络安全专业知识。 🚀