Business Logic Vulnerabilities
Business Logic Vulnerabilities คือช่องโหว่จากตรรกะที่ออกแบบผิด ไม่ใช่บั๊กทางเทคนิค — เกิดเมื่อระบบเชื่อ 'สมมติฐานที่ผิด' เช่น เชื่อราคาที่ client ส่งมา, เชื่อว่าผู้ใช้ทำตามขั้นตอน, ไม่คิดถึงค่าติดลบ/ศูนย์/ใหญ่มาก บทนี้ไล่รูปแบบที่พบบ่อย (price/quantity manipulation, ข้ามขั้นตอน, ใช้ซ้ำ, race), วิธีคิดในการทดสอบ, พร้อม request จริงและ decision flow ช่องนี้ scanner หาไม่เจอ — ต้องเข้าใจ domain ของแอป
1. หลักการ — สมมติฐานที่ผิด
ช่องโหว่ประเภทนี้ไม่มี payload ตายตัว เกิดจากการที่ระบบ เชื่อ assumption ที่ผิด เช่น เชื่อว่าราคาที่ client ส่งมาถูกต้อง, เชื่อว่าผู้ใช้เดินตามขั้นตอน 1→2→3, หรือไม่ได้คิดถึงค่าติดลบ/ค่าศูนย์/ค่าใหญ่มาก กุญแจคือ เข้าใจ workflow ที่ตั้งใจ แล้วถามว่า 'ถ้าทำนอกเหนือจากที่ตั้งใจจะเกิดอะไร'
2. รูปแบบที่พบบ่อย
| รูปแบบ | ตัวอย่าง | ผลกระทบ |
|---|---|---|
| เชื่อค่าจาก client | price=0, discount=100 ใน request | ซื้อของฟรี/ลดเกินจริง |
| ค่าติดลบ | quantity=-1 → ยอดเงินเพิ่มแทนลด | เติมเงินตัวเอง |
| ข้ามขั้นตอน | เข้าหน้า confirm โดยไม่ผ่านหน้าจ่ายเงิน | ได้ของโดยไม่จ่าย |
| แก้ค่าที่ไม่ควรแก้ | เปลี่ยน user_id/account/status ใน request | IDOR/privesc |
| ใช้ซ้ำ | ใช้คูปอง/gift card เดิมหลายครั้ง (race) | ส่วนลดทวีคูณ |
| Integer overflow/round | จำนวนมากจน overflow / ปัดเศษเข้าข้างตัว | ยอดเพี้ยน |
| ลำดับสลับ (TOCTOU) | แก้ตะกร้าหลังคำนวณราคาแล้ว | จ่ายราคาเก่าของถูก |
| สมมติค่า enum จำกัด | ส่ง currency/role/tier ที่ไม่มีในลิสต์ | ได้สิทธิ์/เรตพิเศษ |
3. ตัวอย่าง request จริง
# checkout ส่งราคามาจาก client เอง (แทนคำนวณที่ server)
POST /api/checkout HTTP/1.1
Content-Type: application/json
{"item":"laptop","price":1,"quantity":1}
# เปลี่ยน price 49900 → 1 หรือ 0 → จ่ายน้อย/ฟรี
# ถ้า server เชื่อ = business logic flaw# ซื้อจำนวนติดลบ → บาง backend คิดเป็นเครดิตคืน
POST /api/cart/add {"item":"gift","quantity":-5,"price":1000}
# หรือ transfer ติดลบ = ดึงเงินจากปลายทางมาหาเรา
POST /api/transfer {"to":"victim","amount":-1000}# ปกติ: /cart → /shipping → /payment → /confirm
# ข้ามตรงไปหน้า confirm โดยไม่ผ่าน payment
POST /api/order/confirm HTTP/1.1
{"order_id":"12345"}
# ถ้าไม่มี state check ว่าจ่ายเงินแล้ว → ได้ของฟรี# ยิง apply-coupon พร้อมกันหลาย request ก่อน server mark ว่าใช้แล้ว
POST /api/coupon/apply {"code":"SAVE50"} x 20 พร้อมกัน
# ถ้า check-then-use ไม่ atomic → คูปองถูกใช้หลายครั้ง
# ดูหัวข้อ Race Condition สำหรับเทคนิค single-packet attack4. วิธีคิดในการทดสอบ
- 1วาดแผนผัง workflow ที่ตั้งใจให้ครบ (ทุกขั้นตอนปกติ + state ที่ควรเป็น)
- 2ที่แต่ละขั้น ถาม: 'ถ้าข้าม / ทำซ้ำ / ทำสลับลำดับ / ทำพร้อมกัน จะเกิดอะไร'
- 3ดูทุกค่าที่ client ส่ง — ลองค่าขอบ: 0, ติดลบ, ใหญ่มาก (overflow), ทศนิยม, string, array, null
- 4ลองแก้ค่าที่ 'ไม่ควรแก้ได้': ราคา, ส่วนลด, สิทธิ์, สถานะ order, เจ้าของ, currency, tier
- 5หา assumption ที่ซ่อนอยู่ — อะไรที่ระบบ 'คิดว่าผู้ใช้จะไม่ทำ' แล้วลองทำสิ่งนั้น
- 6ตรวจว่า validation อยู่ที่ client อย่างเดียวไหม (JS กันแต่ server ไม่กัน)
5. ตัวอย่าง CTF & Real-world
CTF (PortSwigger): ร้านค้าให้ส่วนลด 'ซื้อครบ $X ลด' โดยเช็คยอดตอนกด apply — แต่แก้ตะกร้าได้หลัง apply จึงใส่ของแพงให้ครบเกณฑ์ apply ส่วนลด แล้วลบของแพงออกก่อน checkout → ได้ส่วนลดโดยไม่ต้องซื้อจริง (TOCTOU ในราคา)
Real-world: แอปเติมเงินยอมรับ amount จาก client ในขั้นยืนยัน แม้ขั้นชำระจริงจะ fix ยอด — ผู้โจมตีจ่าย $1 แต่แก้ amount=1000 ในขั้น confirm ระบบเครดิตอ่านจาก confirm → เติมเงิน $1000 จ่ายจริง $1 เป็น pattern 'สอง endpoint เชื่อคนละค่า' ที่พบบ่อยใน payment
| โจทย์ | assumption ที่ผิด | ลองทำ |
|---|---|---|
| ร้านค้า/ตะกร้า | ราคา/ยอดจาก client ถูกต้อง | price=0, qty ติดลบ, แก้หลัง apply |
| คูปอง/รางวัล | ใช้ได้ครั้งเดียว | reuse + race |
| สมัคร/upgrade | tier/role มาจาก flow ปกติ | ส่ง tier=premium ตรงๆ |
| โอนเงิน | amount ≥ 0 เสมอ | amount ติดลบ, overflow |
| multi-step wizard | ต้องผ่านทุก step | เรียก step ปลายข้ามการจ่าย |
6. ข้อผิดพลาด & การป้องกัน
- หาแบบ scanner: ยิง payload มั่วโดยไม่เข้าใจ flow — logic flaw ต้องอ่าน domain
- ลืมค่าขอบ: ทดสอบแค่ค่าปกติ ไม่ลอง ติดลบ/0/ใหญ่มาก
- ดูทีละ request: logic flaw หลายอย่างเกิดจากลำดับ/สองendpoint ที่เชื่อคนละค่า
- เชื่อ validation ฝั่ง client: ปิด JS แล้วยิงตรง server อาจไม่กัน
7. Quick Reference
- logic flaw ไม่ใช่บั๊กเทคนิค — ไม่มี payload ตายตัว ต้องเข้าใจ domain
- เชื่อค่า client: แก้ price/discount/qty/role/status
- ค่าขอบ: ติดลบ, 0, ใหญ่มาก (overflow), ทศนิยม, string/array/null
- ข้าม/ทำซ้ำ/สลับลำดับ workflow; TOCTOU: แก้หลังคำนวณ
- chain กับ race (คูปอง/เงิน) และ IDOR (แก้ owner)
- หา 'สอง endpoint เชื่อคนละค่า' ในระบบ payment
- ป้องกัน: re-validate ที่ server ทุกค่า, state machine, atomic, abuse-case test
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติเจอเว็บ e-commerce/booking ที่มี workflow หลายขั้น (ตะกร้า→checkout→ยืนยัน) มีแค่ Kali เปล่าๆ ทำตามนี้ทีละขั้นเพื่อหา logic flaw
- 1เปิด Burp Suite ตั้ง proxy แล้วเดินแอปแบบ user ปกติทั้ง flow ให้ Burp เก็บทุก request ไว้ครบ
- 2จากประวัติใน Burp เขียนแผนผัง workflow ที่ตั้งใจไว้ (บันทึกใน notes): แต่ละ step คู่กับ endpoint ที่เกี่ยวข้อง
- 3หา request ที่มีตัวเลขสำคัญ (price/qty/amount/discount) ส่งเข้า Repeater
- 4ใน Repeater ลองค่าขอบ: 0, ติดลบ, ทศนิยม, ตัวเลขใหญ่มาก (overflow) แล้วดูว่า server ยอมรับไหม
- 5ลองข้ามขั้นตอน: เรียก endpoint ของ step ท้ายๆ ตรงๆ (เช่น /order/confirm) โดยไม่ผ่าน step ก่อนหน้า
- 6ลองแก้ field ที่ไม่ควรแก้ได้ (owner_id, status, tier, currency) ใน body แล้วดูว่า server เชื่อไหม
- 7ถ้ามี coupon/gift card ที่ควรใช้ครั้งเดียว ลองส่ง apply-coupon ซ้ำๆ พร้อมกันด้วย Burp Turbo Intruder
- 8เช็คว่า validate อยู่ที่ client อย่างเดียวไหม โดยปิด JS แล้วยิง request ตรงจาก Repeater
- 9เจอราคาผิด/ได้ของฟรี → เก็บ request/response ไว้เป็นหลักฐานพร้อมอธิบาย assumption ที่พัง
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| ดักจับ/แก้ค่าตัวเลข | Burp Suite Community | - | - |
| ยิง request พร้อมกัน (race) | - | BApp Store: Turbo Intruder | - |
| ทดสอบค่าขอบอัตโนมัติ | Burp Intruder | - | - |
| เขียน script ทดสอบ logic เอง | python3 | pip install requests | - |
| จัดรูป/อ่าน response JSON | - | - | CyberChef (JSON Beautify) |
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้