DataSight Analytics
Series note
หมวด Secure Architecture & Design
ภาพรวมโจทย์
DataSight Analytics เป็นโจทย์ที่ตอนแรกดูเหมือนระบบ health check ธรรมดา แต่จริง ๆ แล้วซ่อน MCP server สำหรับการจัดการไฟล์ ไว้ด้านหลัง โจทย์บอกเพียงว่าระบบมีเครื่องมือเกี่ยวกับไฟล์อยู่ 4 ตัว และเป้าหมายคือหาข้อมูลลับที่รั่วจากการตั้งค่า access control ผิดพลาดให้เจอ
หน้าแรกตอบกลับมาแค่นี้ แค่นี้:
{"status":"ok","server":"datasight-file-manager-ctf"}
ถ้าไม่ลองต่อก็อาจนึกว่ามันไม่มีอะไร แต่ความจริง route ที่สำคัญอยู่ที่ ช่องทางสื่อสารของ MCP
หา ช่องทางสื่อสารของระบบก่อน
เมื่อไล่ path มาตรฐานของ agent หรือ MCP server จะพบว่า /sse ตอบกลับเป็น text/event-stream และส่ง event ที่มี endpoint ลักษณะ:
event: endpoint
data: /messages/?session_id=...
ตรงนี้ยืนยันแล้วว่าระบบใช้ MCP over SSE แบบตรงไปตรงมา:
เปิด
GET /sseรับ
session_idส่ง JSON-RPC ไปที่
/messages/?session_id=...รับผลลัพธ์กลับจาก stream เดิม
นี่เป็น pattern ที่เจอได้บ่อยในระบบ agent ภายใน และเมื่อรู้ ช่องทางสื่อสารแล้ว ขั้นต่อไปก็คือ ไล่ดูเครื่องมือ
ไล่ดูเครื่องมือที่เปิดให้ใช้
หลังส่ง initialize และ tools/list จะพบเครื่องมือที่โจทย์บอกไว้จริง:
fs_list_directoriesfs_list_filesfs_read_filefs_get_file_info
ลองเรียกใช้งานแบบปกติก่อน จะเห็นโฟลเดอร์ประมาณ:
reports/models/
และไฟล์อย่าง:
annual_2025_highlights.txtq4_2025_summary.txtfraud_detector_v3_config.json
ทั้งหมดนี้เป็นตัวหลอก มากกว่า ไม่เจอ flag อยู่ในเส้นทางปกติ
จุดแตกอยู่ที่ path traversal
สิ่งที่น่าสงสัยตั้งแต่แรกคือ description ของ tool บอกว่าควรเข้าถึงได้เฉพาะ data directory เท่านั้น แต่ยังไม่มีหลักฐานว่าระบบตรวจ canonical path จริงหรือไม่
เมื่อเริ่มส่งค่า path ที่มี .. เข้าไป เช่น:
fs_list_files("../")fs_list_files("../../")fs_read_file("../../etc/passwd")
กลับพบว่าระบบยอมทำงานจริง ผลลัพธ์แสดงทั้งไฟล์ชั้นบน source code และแม้แต่ /etc/passwd
จุดนี้คือหลักฐานชัดเจนว่า service มี path traversal เพราะมันเอา user input ไปประกอบ path โดยไม่ตรวจว่าหลัง resolve แล้ว path ยังอยู่ภายใต้ root ที่อนุญาตหรือไม่
จาก traversal ไปสู่ การอ่าน source code
เมื่อ traversal ใช้ได้ ขั้นต่อไปไม่ควรรีบไล่หาค่า flag แบบสุ่ม แต่ควรอ่าน source หรือ startup scripts เพื่อเข้าใจว่าระบบเก็บ ค่าลับ ไว้ตรงไหน
ไฟล์ที่อ่านแล้วมีประโยชน์มาก ได้แก่:
../src/main.py../src/challenges/file_access.py../../start.sh../../proc/self/environ
โดยเฉพาะ start.sh เผยให้เห็นว่า container startup script นำ environment variable ไปแทนค่าใน source ตอนเริ่มระบบ:
sed -i "s/\[\[RANDOM_SECRET\]\]/$RANDOM_SECRET/g" /app/src/challenges/file_access.py
นี่เป็น clue สำคัญทันทีว่า ค่าลับ น่าจะอยู่ใน environment มากกว่าจะเป็นไฟล์ static ธรรมดา
เจอ flag จาก environment ของ process
เมื่ออ่าน ../src/challenges/file_access.py จะเจอบรรทัดแปลก ๆ ลักษณะ:
FLAG = os.environ.get("ai{egtKNaZEgj}")
ถึงโค้ดจะเขียนดูผิดธรรมชาติ แต่มันบอกอย่างน้อยว่า challenge นี้ inject ค่าบางอย่างผ่าน environment แน่นอน จากนั้นพออ่าน:
../../proc/self/environ
ก็พบค่า:
RANDOM_SECRET=ai{egtKNaZEgj}
นั่นคือ flag ของโจทย์
ทำไมโจทย์นี้ถึงสำคัญ
โจทย์นี้ไม่ใช่แค่ path traversal ธรรมดา แต่มันแสดง chain ที่อันตรายในระบบ เครื่องมือจัดการไฟล์ สำหรับ agent:
ผู้โจมตีใช้ tool ที่ควรจำกัด path ได้
หลุดออกจาก data directory ด้วย
..อ่าน source code และ startup script
เดาได้ว่า ค่าลับ อยู่ใน environment
อ่าน
/proc/self/environเพื่อดึงค่าจริงออกมา
นี่คือภาพของ "การใช้เครื่องมือผิดขอบเขต" ที่เกิดจาก lack of boundary enforcement ล้วน ๆ
บทเรียนจากโจทย์นี้
ถ้าจะ expose เครื่องมือเกี่ยวกับไฟล์ ให้ agent หรือผู้ใช้เรียกใช้ผ่าน API ต้องทำอย่างน้อย:
canonicalize path ก่อนทุกครั้ง
ตรวจว่า resolved path ยังอยู่ใต้ allowed root
block traversal patterns อย่าง
..แยก source code และ runtime ค่าลับs ออกจากพื้นที่ที่ tool เข้าถึงได้
ถ้าไม่ทำ แม้จะเปิดแค่เครื่องมือดูไฟล์ที่ "ดู ไม่มีพิษภัย" ก็ยังกลายเป็นช่องทางอ่าน source และ ค่าลับใน environment ได้เต็มรูปแบบ
Flag
ai{egtKNaZEgj}