CBC Mode
CBC (Cipher Block Chaining) XOR plaintext block เข้ากับ ciphertext block ก่อนหน้า ก่อนเข้ารหัส จึงแก้จุดอ่อน ECB (block เดียวกันไม่ให้ ciphertext เหมือนกัน) แต่เปิดช่องโจมตี 2 แบบที่พบบ่อยใน CTF: bit-flipping (แก้ byte ใน ciphertext เพื่อควบคุม plaintext) และ padding oracle (ถอดได้ทั้งข้อความถ้ามี oracle บอก padding ถูก/ผิด)
1. CBC ทำงานอย่างไร
ตอนเข้ารหัส แต่ละ plaintext block P_i จะถูก XOR กับ ciphertext block ก่อนหน้า C_(i−1) ก่อนเข้ารหัส block แรกใช้ IV แทน C_0: C_i = Enc(P_i ⊕ C_(i−1)) ตอนถอดจึงเป็น P_i = Dec(C_i) ⊕ C_(i−1) — จุดสำคัญคือ plaintext ที่ถอดได้ขึ้นกับ ciphertext block ก่อนหน้า โดยตรง นี่คือรากของทั้ง bit-flipping และ padding oracle
C_1 ถูก XOR เข้ากับผลถอดของ block 2 → กลายเป็น P_2 ดังนั้นถ้าเราแก้ byte ใน C_1 เราจะแก้ byte เดียวกันใน P_2 ได้แบบควบคุมได้ (แต่ block 1 เองจะพังกลายเป็นขยะ)2. Bit-Flipping Attack
เพราะ P_i = Dec(C_i) ⊕ C_(i−1) ถ้าเรารู้ (หรือเดา) plaintext เดิมที่ตำแหน่งหนึ่ง และอยากให้มันกลายเป็นค่าใหม่ ให้แก้ byte ใน ciphertext block ก่อนหน้าด้วยสูตร: C'_(i−1)[j] = C_(i−1)[j] ⊕ P_เดิม[j] ⊕ P_ต้องการ[j] ใช้บ่อยกับ cookie/token ที่เข้ารหัส CBC เช่นพลิก admin=0 → admin=1
# มี ciphertext (IV + blocks) อยากพลิก plaintext ตำแหน่ง idx
# จาก known 'user' -> target 'root' ใน block ถัดไป
from pwn import xor # หรือทำ XOR เอง
BS = 16
ct = bytearray(iv + ciphertext) # ทั้งก้อน
# ตำแหน่ง byte ใน plaintext block N -> แก้ที่ ct block N-1
known = b'user'
target = b'root'
off = block_index_prev * BS + col # ตำแหน่งใน ct ของ block ก่อนหน้า
for k in range(len(known)):
ct[off + k] ^= known[k] ^ target[k]
# ส่ง ct ที่แก้แล้วกลับไปให้ server ถอด
3. Padding Oracle (ถอดได้ทั้งข้อความ)
ถ้า server เผยว่า padding ถูกหรือผิด (ต่างกันที่ error / status / เวลา) ผู้โจมตีถอด ciphertext ได้ทุก byte โดยไม่ต้องรู้ key โดยไล่เดา byte สุดท้ายให้ padding valid (\x01) แล้วขยับไปเรื่อยๆ ทีละ byte — รายละเอียดคณิตศาสตร์เต็ม + สคริปต์ automatic อยู่ในหัวข้อ Padding Oracle Attack
| สัญญาณ | เดาว่าเป็น |
|---|---|
| block เดียวกัน → ciphertext ซ้ำ | ECB (ไปหัวข้อ ecb) |
| error ต่างกันเมื่อแก้ byte ท้าย | padding oracle เป็นไปได้ |
| cookie ยาวเป็นทวีคูณของ 16 | AES-CBC block 16 byte |
| แก้ 1 byte ใน ct → plaintext block ถัดไปเพี้ยน 1 byte | CBC bit-flipping ได้ |
4. ข้อควรระวัง & Quick Reference
- block ก่อนหน้าที่ถูกแก้จะกลายเป็นขยะเสมอ — วางแผนว่า block ไหนยอมพังได้
- byte แรกของข้อความคุมผ่าน IV; byte อื่นคุมผ่าน ciphertext block ก่อนหน้า
- padding oracle ไม่ต้องรู้ key — แค่ oracle บอกถูก/ผิดก็พอ (แม้ผ่าน timing)
- ถ้า ciphertext block ซ้ำเมื่อ plaintext ซ้ำ = ไม่ใช่ CBC ที่ IV สุ่ม (สงสัย ECB)
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติยืนยันแล้วว่าโจทย์ใช้ CBC (IV 16 byte แรกแยกออกมา หรือ ciphertext ไม่มี block ซ้ำเลย) มีแค่เครื่อง Kali เปล่าๆ ทำตามนี้ทีละขั้น
- 1แยก IV ออกจาก ciphertext ก่อน: ถ้า cookie/token เป็น base64/hex ยาว ลองตัด 16 byte แรกออกมาด้วย python (`iv, ct = data[:16], data[16:]`) ดูว่าเป็น IV แยกต่างหากไหม
- 2ทดสอบว่าแก้ ciphertext แล้วส่งกลับให้ server ถอดได้ไหม: แก้ 1 byte แบบสุ่มแล้วส่งไปดู ถ้าไม่ crash/ไม่ถูกปฏิเสธทันที = มีโอกาสโจมตีได้
- 3ทดลอง padding oracle: แก้ byte สุดท้ายของ ciphertext ไล่ค่า 0x00-0xFF ทีละค่าแล้วส่งไป สังเกต response (error message ต่างกัน, HTTP status ต่างกัน, ความยาว response, หรือเวลาตอบสนอง)
- 4เจอ response ที่ต่างกันชัดเจนเมื่อ padding ผิด/ถูก → ยืนยันว่ามี padding oracle จริง เขียน python script อัตโนมัติ หรือติดตั้ง padbuster: `apt install padbuster` (ถ้าไม่มีให้ `git clone` repo มา) แล้วรัน `padbuster URL sample_ciphertext 16 -cookies name=value`
- 5ไม่มี oracle ชัดเจน (response เหมือนกันหมดไม่ว่า padding ถูกหรือผิด) → เปลี่ยนไปลอง bit-flipping แทน
- 6bit-flipping ต้องรู้/เดา plaintext เดิมที่ตำแหน่งหนึ่งก่อน (เช่นรู้ว่ามี `role=user` อยู่ในข้อมูล) คำนวณ byte ที่ต้องแก้ใน ciphertext block ก่อนหน้าด้วยสูตร `C'[j] = C[j] ⊕ known[j] ⊕ target[j]` (โค้ดเต็มอยู่ในหัวข้อด้านบน)
- 7ส่ง ciphertext ที่แก้แล้วกลับไปให้ server ถอด ตรวจว่า plaintext ที่ได้ตรงกับที่ต้องการไหม (block ก่อนหน้าจะพังเป็นขยะ แต่ยอมรับได้ถ้าไม่ใช่ข้อมูลสำคัญ)
- 8อยากแก้ byte แรกสุดของข้อความทั้งหมด → แก้ที่ IV โดยตรงแทน (ถ้าโจทย์ให้เราควบคุม IV ได้ block แรกจะไม่พัง)
- 9ลอง bit-flipping/padding oracle แล้วยังไม่ได้ผล → เช็คว่า ciphertext มี block ซ้ำกันไหม (สงสัยว่าจริงๆ เป็น ECB ไม่ใช่ CBC) หรือ server เช็ค integrity/MAC ที่ป้องกันไว้อยู่
- 10ถอด/ปลอมข้อความสำเร็จ → เช็ค flag/privilege ที่ได้ตรงกับที่โจทย์ต้องการ
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| แยก IV ออกจาก ciphertext | python3, xxd | - | - |
| ทดสอบส่ง ciphertext ที่แก้แล้วกลับ server | curl, python3 (requests) | pip install requests | Burp Suite Repeater (ถ้ามี) |
| ถอด padding oracle อัตโนมัติ | python3 (script เอง), padbuster | apt install padbuster | - |
| bit-flip คำนวณ byte ที่ต้องแก้ | python3 | - | CyberChef (XOR) |
| ดู hex ของ ciphertext/plaintext | xxd | - | CyberChef (To Hex / From Hex) |
หัวข้อที่เชื่อมโยง
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้