เจาะลึกช่องโหว่อัปโหลดไฟล์: เมื่อตัวกรองสุดฉลาดก็ยังพลาดท่าให้ Null Byte

เจาะลึกช่องโหว่อัปโหลดไฟล์: เมื่อตัวกรองสุดฉลาดก็ยังพลาดท่าให้ Null Byte

ในการใช้งานเว็บแอปพลิเคชัน ไม่ว่าจะเว็บไซต์ทั่วไปหรือระบบซับซ้อน มักจะมีการเปิดโอกาสให้ผู้ใช้งานอัปโหลดไฟล์ต่าง ๆ ได้ ไม่ว่าจะเป็นรูปโปรไฟล์ เอกสาร หรือไฟล์อื่น ๆ ที่จำเป็น

แต่รู้หรือไม่ว่าฟังก์ชันที่ดูเหมือนธรรมดาและจำเป็นนี้ กลับเป็นประตูบานใหญ่ที่ผู้ไม่หวังดีสามารถใช้เจาะระบบได้อย่างง่ายดาย

นี่คือเหตุผลว่าทำไมการจัดการการอัปโหลดไฟล์อย่างไม่รัดกุม จึงเป็นหนึ่งในช่องโหว่ที่อันตรายที่สุดที่เรียกว่า Unrestricted File Upload หรือ ช่องโหว่อัปโหลดไฟล์แบบไม่จำกัด

ทำไมการอัปโหลดไฟล์ถึงเป็นช่องโหว่?

ลองนึกภาพว่าเว็บเซิร์ฟเวอร์ของคุณอนุญาตให้ใครก็ได้อัปโหลดไฟล์อะไรก็ได้ ไม่มีการตรวจสอบใด ๆ

ผู้โจมตีสามารถอัปโหลดไฟล์ที่เรียกว่า Webshell ซึ่งเป็นสคริปต์ที่เขียนขึ้นมาเพื่อควบคุมเซิร์ฟเวอร์ได้

เมื่อไฟล์ Webshell ถูกอัปโหลดสำเร็จ ผู้โจมตีก็เหมือนมีรีโมตคอนโทรลอยู่ในมือ

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

นี่คือฝันร้ายของความปลอดภัยทางไซเบอร์ที่แท้จริง

เมื่อตัวกรองฉลาดขึ้น: ความท้าทายใหม่

แน่นอนว่านักพัฒนาทราบถึงอันตรายนี้ดี จึงพยายามสร้าง ตัวกรอง (Filter) ขึ้นมาเพื่อป้องกันการโจมตี

ตัวกรองเหล่านี้มักจะตรวจสอบประเภทของไฟล์, ตรวจสอบ นามสกุลไฟล์, หรือแม้กระทั่งเนื้อหาของไฟล์ เพื่อให้แน่ใจว่ามีเพียงไฟล์ที่ปลอดภัยเท่านั้นที่สามารถอัปโหลดได้

ตัวกรองที่ฉลาดขึ้นจะใช้วิธีที่ซับซ้อนกว่าเดิม เช่น การอนุญาตเฉพาะนามสกุลที่อยู่ใน บัญชีขาว (Whitelist) อย่างเช่น .jpg, .png, .gif เท่านั้น

บางตัวกรองจะพยายามลบ อักขระพิเศษ หรือค่าที่อาจทำให้เกิดปัญหาออกไปจากชื่อไฟล์ เช่น ลบจุด (.) หรือแม้แต่ Null Byte (%00) เพื่อป้องกันการเล่นแสกหที่อาจเกิดขึ้น

แต่แม้จะมีการป้องกันที่ดีขึ้นเพียงใด ก็ยังคงมีช่องโหว่ซ่อนอยู่เสมอ

เจาะระบบด้วย Null Byte (%00) — เทคนิคคลาสสิกที่ยังใช้ได้ผล

Null Byte หรือ %00 เมื่อเข้ารหัสแบบ URL เป็นค่าที่แสดงถึง อักขระศูนย์ หรือ Null Character

ในทางโปรแกรมมิ่ง Null Character มักถูกใช้เป็นตัวบอก จุดสิ้นสุดของข้อความ (String Terminator)

เทคนิคการเจาะระบบด้วย Null Byte เป็นวิธีที่คลาสสิกแต่ยังทรงพลังในการหลอกตัวกรองที่ไม่ได้จัดการค่านี้อย่างสมบูรณ์แบบ

สมมติว่ามีระบบที่อนุญาตให้อัปโหลดไฟล์ .gif เท่านั้น และตัวกรองก็พยายามลบทั้งจุด (.) และ Null Byte (%00) ออกจากชื่อไฟล์เพื่อความปลอดภัย

ผู้โจมตีอาจอัปโหลดไฟล์ที่มีชื่อว่า shell.php%00.gif

เมื่อไฟล์นี้ถูกส่งไปยังเซิร์ฟเวอร์ ตัวกรองจะทำการตรวจสอบ:

  1. ตรวจสอบนามสกุล: ตัวกรองเห็นว่าชื่อไฟล์ลงท้ายด้วย .gif ซึ่งดูเหมือนจะถูกต้องตามเงื่อนไขที่อนุญาต
  2. พยายามลบอักขระพิเศษ: ตัวกรองอาจจะพยายามลบ Null Byte (%00) ออกจากชื่อไฟล์ตามที่ตั้งโปรแกรมไว้

แต่ปัญหาอยู่ตรงนี้: แม้ตัวกรองจะพยายามลบ Null Byte ออกไป แต่ในบางกรณี ตัวระบบปฏิบัติการหรือโปรแกรมที่รับผิดชอบการเขียนไฟล์อาจจะตีความ Null Byte ที่ยังหลงเหลืออยู่ (หรือถูกประมวลผลในช่วงเวลาที่แตกต่างกัน) ว่าเป็น จุดสิ้นสุดของชื่อไฟล์ เสียก่อน

ผลลัพธ์คือ ไฟล์ shell.php%00.gif จะถูกบันทึกในเซิร์ฟเวอร์ในชื่อเพียงแค่ shell.php แทนที่จะเป็น shell.php00gif หรือชื่ออื่น ๆ ที่ถูกทำความสะอาดแล้ว

เมื่อไฟล์ shell.php ถูกบันทึกเรียบร้อย ผู้โจมตีก็สามารถเข้าถึงสคริปต์ PHP ที่เป็น Webshell นั้น และสั่งงานเซิร์ฟเวอร์ได้ทันที

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

การป้องกันที่ดีที่สุดคือการใช้แนวทาง ความปลอดภัยเชิงลึก (Defense in Depth) โดยไม่พึ่งพากลไกป้องกันเพียงชั้นเดียว ควรมีการตรวจสอบไฟล์ตั้งแต่ระดับเบื้องต้นไปจนถึงระดับที่ละเอียดอ่อน เพื่อปิดประตูทุกบานที่ผู้โจมตีอาจใช้เข้ามาได้