แจ้งปัญหาช่องโหว่ LFI ของโปรเจ็คตัวอย่างโปรเจ็คหนึ่งของ Kotchasan (แก้ไขแล้ว)
ช่องโหว่ LFI คืออะไร
LFI ย่อมาจาก Local file Inclusion ความหมายของมันก็คือ ช่องโหว่การเข้าถึงไฟล์ภายในเครื่อง ช่องโหว่นี้จัดเป็นช่องโหว่ร้ายแรงประเภทหนึ่งทีเดียว เนื่องจาก อาจทำให้ Server ของเรา เสร็จโจรได้ง่ายๆ ยกตัวอย่างเช่น หากสามารถเข้าถึงไฟล์ที่ทำหน้าที่ในการเก็บรหัสผ่านได้ รหัสผ่านก็จะอยู่ในมือโจร สามารถเป็นเจ้าของเครื่องแทนเราได้เลยทีเดียว
ช่องโหว่นี้เกิดขึ้นที่โปรเจ็คตัวอย่างหนึ่งของ Kotchasan ครับ คือโปรเจ็ค Ajax (projects/ajax/) มาดูโค้ดที่เป็นปัญหากัน
$url = $request->post('url')->url();
if ($url != '') {
// โหลด URL ที่ส่งมา
$content = file_get_contents($url);
// คืนค่า HTML ไปยัง Ajax
echo $content;
}
ปัญหาอยู่ที่บรรทัดนี้ครับ
$content = file_get_contents($url);
คำสั่งนี้เป็นการโหลดไฟล์ ที่ส่งมากับ $url เช่นส่งค่า http://goragod.com ก็จะเป็นการโหลด URL ข้างต้นส่งกลับไปด้วย Ajax แต่ปัญหาก็คือ รูปแบบของคำสั่งมันสามารถโหลดไฟล์ภายในเครื่องได้ซะด้วย เช่น /var/www/index.html ทำให้สคริปต์สามารถโหลดไฟล์ใดๆก็ได้ในเครื่อง ซึ่งหากรู้ที่อยู่ของไฟล์ที่สำคัญเช่น ไฟล์เก็บ password ก็จะสามารถอ่านออกมาได้ง่ายๆ
จากปัญหาข้างต้น การแก้ไขคือ ทำการตรวจสอบก่อน ว่าไฟล์เป้าหมายต้องเป็น URL เท่านั้น หรือ หากต้องการโหลดไฟล์ในเครื่องจริงๆก็ต้องจำกัดพื้นที่ ที่จะยอมให้โปรแกรมสามารถเข้าถึงไฟล์ได้
$url = $request->post('url')->url();
if ($url != '' && preg_match('/^https?:\/\/.*/', $url)) {
// โหลด URL ที่ส่งมา
$content = file_get_contents($url);
// คืนค่า HTML ไปยัง Ajax
echo $content;
}
คำสั่งที่เพิ่มเข้ามา คือ preg_match('/^https?:\/\/.*/', $url) เป็นการกำหนดว่า $url ที่ส่งมาต้องขึ้นต้นด้วย http เท่านั้น เพียงเท่านี้ก็จะไม่สามารถโหลดไฟล์ใดๆในเครื่องได้แล้ว (นอกจากไฟล์ที่สามารถเรียกผ่าน URL ได้ตามปกติ)