คลัง
web

JWT Attacks

JWT (JSON Web Token) เป็น token ที่เซิร์ฟเวอร์ใช้ยืนยันตัวตน ช่องโหว่เกิดจากการ verify signature ที่ผิดพลาด เช่น alg=none, algorithm confusion (RS256→HS256), weak secret บทนี้ครอบคลุมโครงสร้าง JWT และการโจมตีหลัก

IntermediateAdvanced#jwt#jwt-none#algorithm-confusion#kid#token#web#ctf

1. โครงสร้าง JWT

JWT มี 3 ส่วนคั่นด้วยจุด: header.payload.signature แต่ละส่วนเป็น base64url header บอก algorithm (alg) payload เก็บ claims (เช่น user, role) signature ใช้ยืนยันว่าไม่ถูกแก้ — ความปลอดภัยทั้งหมดอยู่ที่การ verify signature อย่างถูกต้อง

โครงสร้าง JWT
header (alg) payload (claims) signature . .

2. alg=none

ถ้าเซิร์ฟเวอร์ยอมรับ alg: none หมายความว่ามันไม่ verify signature เลย — ผู้โจมตีแก้ payload (เช่น role: admin) ตั้ง alg เป็น none และลบ signature ทิ้ง token ก็ยังผ่าน

สร้าง token alg=none
# header: {"alg":"none","typ":"JWT"}  payload: {"user":"admin"}
# base64url ทั้งสองส่วน ตามด้วยจุดและ signature ว่าง
echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr '+/' '-_' | tr -d '='
echo -n '{"user":"admin","role":"admin"}' | base64 | tr '+/' '-_' | tr -d '='
# ผลลัพธ์: <header>.<payload>.   (ลงท้ายด้วยจุด ไม่มี signature)

# หรือใช้ jwt_tool
jwt_tool TOKEN -X a

3. Algorithm confusion (RS256 → HS256)

RS256 ใช้ private key เซ็น/public key verify ส่วน HS256 ใช้ secret เดียวกันทั้งเซ็นและ verify ถ้าเซิร์ฟเวอร์เขียนโค้ดไม่รัดกุม ผู้โจมตีเปลี่ยน alg เป็น HS256 แล้วใช้ public key (ที่เปิดเผยอยู่แล้ว) เป็น secret ในการเซ็น — เซิร์ฟเวอร์จะ verify ด้วย public key เดียวกันแล้วผ่าน

Algorithm confusion ด้วย jwt_tool
# ต้องมี public key ของเซิร์ฟเวอร์ (มักหาได้จาก /jwks.json, cert, หรือ derive)
jwt_tool TOKEN -X k -pk public.pem
# -X k = key confusion attack
ถ้าไม่มี public key ตรงๆ บางครั้ง derive จาก 2 token ที่ต่างกันได้ (jwt_tool/tools เฉพาะ)

4. จุดอ่อนอื่น

  • Weak secret (HS256): brute-force secret ด้วย wordlist — jwt_tool TOKEN -C -d rockyou.txt หรือ hashcat mode 16500
  • kid injection: header kid ชี้ไฟล์ key — ลอง path traversal หรือ SQLi ใน kid เพื่อควบคุม key
  • jku/x5u: header ชี้ URL ของ key set — ชี้ไป key ของเราเอง (ถ้าไม่ validate domain)
  • ไม่เช็ค expiry: token หมดอายุยังใช้ได้
  • claim ไม่ถูก validate: แก้ role/user ใน payload หลัง bypass signature

5. Quick Reference

  • JWT = header.payload.signature (base64url)
  • alg=none → ลบ signature, แก้ payload ได้
  • RS256→HS256 confusion: เซ็นด้วย public key เป็น secret
  • weak secret: jwt_tool -C -d wordlist / hashcat -m 16500
  • kid/jku/x5u: ควบคุม key ที่ใช้ verify
  • เครื่องมือหลัก: jwt_tool, jwt.io (decode)
  • ป้องกัน: บังคับ alg, ไม่รับ none, validate kid/jku, secret แข็งแรง

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

สมมติเจอ token ที่ขึ้นต้นด้วย eyJ ในคุกกี้หรือ Authorization header มีแค่ Kali เปล่าๆ ทำตามนี้ทีละขั้นเพื่อดูว่าปลอมได้ไหม

  1. 1ก็อป token ไปวางที่ jwt.io ดู header/payload (decode ได้เลยไม่ต้องมี secret)
  2. 2เช็คว่า header alg เป็นอะไร: none, HS256, RS256
  3. 3ติดตั้ง jwt_tool (git clone https://github.com/ticarpi/jwt_tool) แล้วลอง jwt_tool TOKEN -X a เพื่อสร้าง token alg=none ส่งกลับไปแทน token เดิม
  4. 4ถ้า alg=HS256 ลอง crack weak secret ด้วย jwt_tool TOKEN -C -d /usr/share/wordlists/rockyou.txt หรือ hashcat -m 16500 -a 0 token.txt rockyou.txt
  5. 5ถ้า alg=RS256 หา public key จาก /jwks.json หรือ /.well-known/jwks.json แล้วลอง jwt_tool TOKEN -X k -pk public.pem (algorithm confusion)
  6. 6เช็ค header ว่ามี kid ไหม ลอง path traversal/SQLi ใน kid ด้วย jwt_tool TOKEN -X i
  7. 7เช็คว่ามี jku/x5u header ชี้ URL ที่เราคุมเองได้ไหม
  8. 8เมื่อได้ signature ที่ปลอมได้แล้ว แก้ payload (เช่น role:admin) แล้วส่ง token กลับไปยัง endpoint จริงเพื่อยืนยันผล
  9. 9เช็ค claim หมดอายุ (exp) ด้วยว่า token เก่ายังใช้ได้ไหม
ตัดสินใจ: ไล่ปลอม JWT ทีละเทคนิค
วาง token ที่ jwt.io ดู header.alg
alg=none (ลองส่งดูว่า server ยอมรับไหม)→ ลอง forge alg=none
alg=HS256→ ลอง crack weak secret
alg=RS256→ ลอง algorithm confusion
สร้าง token alg=none (jwt_tool -X a) แก้ role เป็น admin แล้วส่ง
✅ server ยอมรับ→ ปลอม token สำเร็จ
❌ ถูกปฏิเสธ→ ไปลอง HS256/RS256 path
crack weak secret: jwt_tool -C -d rockyou.txt หรือ hashcat -m 16500
✅ crack ได้ secret→ เซ็น token ใหม่ด้วย secret ที่ได้
❌ secret แข็งแรง→ ลอง kid/jku/x5u
หา public key (/jwks.json) แล้วลอง jwt_tool -X k -pk public.pem (RS256→HS256)
✅ server verify ผ่าน→ ปลอม token ด้วย public key เป็น secret
❌ ไม่ผ่าน→ ลอง kid/jku/x5u
ลอง kid injection (path traversal/SQLi) หรือ jku/x5u ชี้ key ที่เราคุมเอง
✅ ควบคุม key ที่ใช้ verify ได้→ เซ็น token เองได้เต็มรูปแบบ
❌ ไม่ได้เลย→ JWT อาจไม่ใช่จุดอ่อน ไปดู session-testing/access-control แทน
forge token ผ่าน → replay ที่ endpoint จริง ยืนยัน privesc/bypass
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
decode/inspect JWT--jwt.io
โจมตี/แก้/เซ็น JWT อัตโนมัติ-git clone https://github.com/ticarpi/jwt_tool-
crack weak HMAC secrethashcat (-m 16500), john-crackstation.net
wordlist สำหรับ crack secret/usr/share/wordlists/rockyou.txt--
ดักจับ/แก้ token ใน requestBurp Suite Community--
แปลง/encode base64url ด้วยมือ--CyberChef
🚑 ถ้าตันสนิท ลองท่าถัดไป: Access Control — ถ้า role มาจาก JWT claim ที่ปลอมได้แล้ว ต้องไปยืนยัน privesc จริงที่ endpoint · Session Testing — ถ้า JWT ถูกใช้เป็น session token ให้ตรวจ lifecycle/cookie flags ต่อ · IDOR — ถ้า user_id ฝังอยู่ใน JWT payload และ endpoint ไม่ตรวจซ้ำ · OAuth Attacks — ถ้า JWT เป็น access token ที่ได้จาก OAuth flow

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

โน้ตของฉัน

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