DataSight Analytics2

Writeup NCSA AI CTF 2026
b
benzdeus
Apr 3, 2026·2 min read

Series note

หมายเหตุ: โพสต์นี้จัดทำขึ้นระหว่างการทดลอง workflow ที่มี AI เข้ามาช่วยในการเรียบเรียงและสรุปเนื้อหา เนื้อหาบางส่วนยังอยู่ระหว่างการเกลาเพิ่มเติม ทั้งในด้านความครบถ้วน ตัวอย่างประกอบ และการอธิบายบริบทของโจทย์

หมวด Secure Architecture & Design

ภาพรวมโจทย์

ข้อนี้เป็นโจทย์ช่องโหว่เชิงตรรกะใน MCP ที่ต่อช่องโหว่เป็นลำดับได้สวยมาก มันเริ่มจาก service จัดการ plugin ที่หน้าตาเหมือนไม่มีอะไรเลย ถ้าเปิด / จะเจอแค่ health check:

JSON
{"status":"ok","server":"datasight-plugin-manager-ctf"}

แต่เบื้องหลังมันเปิด MCP endpoint ออกมาเต็มรูปแบบ และให้เครื่องมือที่ทรงพลังมากเกินไป ทั้ง register plugin, execute plugin, อ่าน config, ดู audit log และเข้าระบบ diagnostics ได้ด้วย

โจทย์จึงไม่ได้แตกจาก bug ตัวเดียว แต่แตกจาก ข้อมูลรั่วหลายชั้นที่ต่อกันได้พอดี

เริ่มจากช่องทางสื่อสารของ MCP

เช่นเดียวกับโจทย์ก่อนหน้า ระบบใช้ /sse เป็น event stream และส่ง endpoint ประมาณ:

text
event: endpoint
data: /messages/?session_id=c808e811fb7d4c518d8e6f51f2e96e1c

จากนั้นเราสามารถทำ MCP handshake ตามปกติ:

  1. initialize

  2. notifications/initialized

  3. tools/list

เมื่อดูรายการเครื่องมือ แล้วจะเจอชุดเครื่องมือหลัก:

  • plugin_list_tools

  • plugin_register_tool

  • plugin_execute_tool

  • plugin_get_info

  • plugin_get_config

  • plugin_audit_log

  • plugin_system_diagnostics

แค่เห็นชื่อพวกนี้ก็พอเดาได้แล้วว่า ถ้ามีการแยกสิทธิ์ไม่ดี หรือมีข้อมูลภายในรั่วแม้แต่นิดเดียว เส้นทางโจมตีน่าจะเกิดได้ง่าย

จุดรั่วแรก: config รั่ว

สิ่งที่ผิดพลาดชัดที่สุดคือ plugin_get_config คืนค่าภายในออกมามากเกินความจำเป็น ในคำตอบจะเห็นข้อมูลลักษณะนี้:

JSON
{
  "plugin_system": {
    "_internal_tool_prefix": "_ptools_",
    "name_validation": "NFKC+lower+strip"
  },
  "security": {
    "maintenance_key_hash": "...",
    "_maintenance_key": "6d61696e7431"
  },
  "debug": {
    "encryption_algo": "xor_rotating"
  }
}

ค่าที่สำคัญที่สุดคือ _maintenance_key ซึ่งอยู่ในรูป hex และถอดได้เป็น:

text
maint1

นี่คือ maintenance key ของระบบ ซึ่งไม่ควรโผล่มาในคำตอบของ config ตั้งแต่แรก

จุดรั่วที่สอง: การลดระดับ maintenance mode

เมื่อเอา key นี้ไปใช้กับ plugin_system_diagnostics เพื่อเปิด maintenance mode ระบบตอบว่า sandbox ถูก downgrade จาก v2 ลงเหลือ v1

ข้อความลักษณะนี้คือสิ่งที่ writeup เดิมพบ:

text
Status: ENABLED
Sandbox downgraded: v2 -> v1
Advanced security checks disabled

ตรงนี้เป็นจุดเปลี่ยนสำคัญมาก เพราะหมายความว่า มาตรการป้องกันที่เดิมตรวจ normalization, zero-width characters และการ shadow ชื่อ tool ถูกลดระดับลงอย่างตั้งใจโดยระบบเอง

ใช้ zero-width character ทำ tool เงา

เมื่อ sandbox อ่อนลง เราสามารถ register tool ชื่อที่ดูเหมือน built-in เดิม แต่แอบต่างกันด้วย zero-width character เช่น:

text
get_system_info\u200b

แล้ว register ผ่าน plugin_register_tool

จากนั้นเมื่อเรียก plugin_execute_tool กับชื่อดังกล่าว ระบบกลับไหลเข้า path ภายในที่ไม่ควรถูกเปิด และคืนข้อมูลลักษณะ:

text
Internal Configuration (encrypted):
  encrypted_flag: 021f75753f3e57421b270402280c475a703704451b370701340c575a70625a6d29674746772149
  encryption: xor_rotating
  note: Use the correct decryption key to reveal the flag.

นี่หมายความว่าเราหลุดเข้า debug/shadow path สำเร็จแล้ว

ดึง key จาก audit log

แม้จะมี encrypted_flag แล้ว แต่ยังต้องมี key สำหรับถอดรหัส จุดนี้ระบบพลาดอีกครั้งผ่าน plugin_audit_log เพราะ detailed log หลุดบริบทการทำงาน ออกมาด้วย เช่น:

text
encryption_context:
  algo: xor_rotating
  key_hex: 44533432
  key_len: 4

เมื่อได้ key_hex แล้ว เรามีทั้ง ciphertext และ key ครบถ้วน

วิธีจบโจทย์

มีสองทาง:

  1. ถอด XOR เองจาก encrypted_flag กับ key_hex

  2. ใช้ debug_key ส่งกลับเข้า plugin_execute_tool เพื่อให้ระบบเปิด flag แบบตรง ๆ

ใน writeup เดิม วิธีหลังให้ผลลัพธ์เป็น:

text
flag: FLAG{mcp_t00l_sh4d0w_d33p_ch41n_m4st3r}

และนั่นคือ flag สุดท้าย

ทำไมโจทย์นี้ถึงดีมาก

เพราะมันเป็นตัวอย่างที่ชัดมากของลำดับช่องโหว่เชิงตรรกะ:

  1. config รั่ว หลุด maintenance key

  2. maintenance mode ลดระดับ sandbox

  3. weakened normalization เปิดทางให้ shadow ชื่อ tool

  4. shadow path หลุด encrypted flag

  5. audit log หลุด decryption key

  6. debug path หรือการถอดรหัสเองคืน flag จริง

ไม่มี memory corruption, ไม่มี RCE, ไม่มี payload หวือหวา แต่ระบบก็พังหมดได้จากการเปิดข้อมูลภายในทีละน้อย

บทเรียนจากโจทย์นี้

ระบบ MCP หรือ plugin manager ควรแยกหน้าที่ของเครื่องมือชัดมาก:

  • config endpoints ต้องไม่เปิดค่าลับ

  • maintenance mode ต้องไม่ลดการป้องกันในแบบที่ผู้โจมตีใช้ต่อได้

  • audit logs ต้องไม่หลุด key material ระหว่าง runtime

  • การตรวจชื่อ ต้อง normalize และ compare อย่างสอดคล้องทุกจุด

ถ้าปล่อยให้มาตรการป้องกันแต่ละส่วนคิดถึงบริบทของตัวเองอย่างเดียว โดยไม่มองทั้งลำดับ ผู้โจมตีก็จะเป็นคนประกอบ puzzle แทนเรา

Flag

text
FLAG{mcp_t00l_sh4d0w_d33p_ch41n_m4st3r}

In This Series

View All Parts