คอมพิวเตอร์ หน้าต่าง อินเทอร์เน็ต

เว็บลิงค์ที่ซื่อสัตย์ php. เลเยอร์เค้กและ com_weblinks Joomla ไฟล์อื่นๆ ที่ใช้ในส่วนประกอบ

ในเดือนนี้ นักขุดบั๊กไม่ต้องการที่จะตามใจเราด้วยการหาช่องโหว่ใหม่ๆ ในแอปพลิเคชันยอดนิยม แน่นอนว่า มีการเผยแพร่คำแนะนำมากมายในผลิตภัณฑ์ของบริษัทที่มีชื่อเสียง แต่มีเพียงไม่กี่รายการที่มีรหัส PoC ที่ย่อยได้ ในการตรวจสอบของเรา ฉันพยายามรวบรวมช่องโหว่ที่สำคัญและสมบูรณ์ที่สุดที่อธิบายไว้เมื่อเร็วๆ นี้ ดังนั้นนั่งเอนหลังและสนุกกับการอ่าน

ช่องโหว่ PHP ในการจัดการคำขอ HTTP Head โดยย่อ

เมื่อวันที่ 3 มีนาคม Adam Ivanyuk ค้นพบคุณสมบัติที่น่าสนใจในตัวแปลภาษา PHP ซึ่งประมวลผลคำขอ HEAD ไม่ถูกต้องนัก ผู้วิจัยตั้งชื่อช่องโหว่นี้ว่า "HTTP HEAD method trick in php scripts"

ผู้เขียนโค้ดหลายคนพัฒนาสคริปต์ PHP ด้วยความหวังว่าคำสั่งทั้งหมดที่เขียนในนั้นจะดำเนินการได้สำเร็จโดยไม่ถูกขัดจังหวะกลางคัน (โดยเฉพาะในสคริปต์สั้นๆ) นี่คือสิ่งที่เกิดขึ้นหากผู้ใช้ปลายทางร้องขอสคริปต์โดยใช้เมธอด GET, POST, PUT

แต่คุณควรทราบว่ามีวิธี HTTP อื่นๆ เช่น HEAD เมื่อประมวลผลวิธีนี้ใน PHP จะทำให้เกิดช่องโหว่ด้านความปลอดภัยได้

เราดูที่หนึ่งในแหล่งที่มาของล่าม: ./main/SAPI.c, บรรทัดที่ 315:

ถ้า (SG(request_info).request_method &&
!strcmp(SG(request_info).request_method, "HEAD"))
{
SG(request_info).headers_only = 1;
...

เมื่อข้อมูลใดๆ มาถึง ฟังก์ชัน php_ub_body_write จะถูกดำเนินการ ต่อไป ดูที่ main/output.c บรรทัดที่ 699:

ถ้า (SG(request_info).headers_only) (
ถ้า(SG(headers_sent))
{
กลับ 0;
}
php_header(TSRMLS_C);
zend_bailout();
}

ที่นี่คุณจะเห็นว่าในเอาต์พุตหน้าจอแรกและเมื่อใช้เมธอด HEAD ฟังก์ชัน zend_bailout จะยกเลิกสคริปต์

เอาเปรียบ

ตอนนี้มาเข้าถึงสคริปต์นี้โดยใช้เมธอด HEAD:

อย่างที่คุณคาดไว้ สมุดเยี่ยมของเราจะหยุดที่บรรทัด "echo $data;" ดังนั้นไฟล์ book.txt จะถูกรีเซ็ตเป็นศูนย์
ตัวอย่างนี้ค่อนข้างทำลายล้าง ในตัวอย่างที่สอง เราสามารถข้ามการให้สิทธิ์ในแผงการดูแลระบบดั้งเดิมได้:

ในสคริปต์นี้ เมื่อคุณเข้าสู่ระบบโดยใช้วิธีการปกติ ตัวแปรการดูแลระบบจะถูกตั้งค่าในเซสชัน จากนั้น หากผู้ใช้ป้อนรหัสผ่านผิด ตัวแปรนี้จะถูกตั้งค่าเป็นศูนย์ และผู้ใช้จะไม่ได้เป็นผู้ดูแลระบบ

หากเราเข้าถึงแผงการดูแลระบบผ่าน HEAD การดำเนินการจะถูกขัดจังหวะด้วยโค้ดที่มี "echo" ดังนั้นตัวแปรการดูแลระบบจะไม่ถูกรีเซ็ตเป็นศูนย์ และเราสามารถเดินไปรอบๆ ส่วนที่ปิดของแอปพลิเคชันได้อย่างปลอดภัย ที่นี่ จำเป็นต้องคำนึงว่าในเว็บเซิร์ฟเวอร์ส่วนใหญ่ ค่าของเอาต์พุตบัฟเฟอร์ถูกกำหนดเป็น 4096 ไบต์ ดังนั้นในตัวอย่างการทำงาน เราอาจต้องใช้บรรทัด 'สตริงยาวประกอบด้วยอักขระประมาณ 4090 ตัว'

เอาเปรียบ
  • พี.เอช.พี

    ที่นี่ อาร์เรย์ $check มีข้อมูล POST ของเรา และตัวแปร $locked เป็นสตริงอนุกรมที่ถูกทำให้ยุ่งเหยิงโดยใช้ฟังก์ชัน str_rot13() ซึ่งอยู่ภายใต้การควบคุมของเราทั้งหมด

    ณ จุดนี้ มันคุ้มค่าที่จะพูดนอกเรื่องสำหรับผู้ที่ยังไม่ได้อ่านบทความที่เกี่ยวข้องใน ][ และพูดคุยสั้น ๆ เกี่ยวกับข้อผิดพลาดที่แสดงออกในวิธีการวิเศษของ PHP ดังนั้นใน PHP เวอร์ชัน 5 แนวคิดพื้นฐานของการเขียนโปรแกรม OOP จึงปรากฏขึ้น: ตัวสร้างและตัวทำลาย ตัวสร้างถูกนำไปใช้ด้วยเมธอด "__construct" และตัวทำลายถูกนำไปใช้ด้วยเมธอด "__destruct" เมื่อสิ้นสุดการทำงานและเมื่อเรียกใช้ผ่านฟังก์ชัน unserialize() แต่ละอ็อบเจกต์จะรันเมธอด __ destruct ของตัวเอง ถ้ามันถูกเขียนไว้ในโค้ด

    ตอนนี้กลับไปที่เฟรมเวิร์กของเราและดูที่ตัวทำลายของคลาส App จากไฟล์ ./libs/configure.php:

    ฟังก์ชัน __destruct()
    {
    ถ้า ($this->__cache)
    {
    $core = App::core("เค้ก");
    unset($this->__paths);
    แคช::write("dir_map", array_filter($this->__paths),
    "เค้ก_คอร์");
    แคช::write("fi le_map", array_filter($this->__map),
    "เค้ก_คอร์");
    แคช::write("object_map", $this->__objects,
    "เค้ก_คอร์");
    }
    }

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

    รหัสจริงสำหรับการโหลดคลาสดูซับซ้อนกว่าเล็กน้อย แต่ทั้งหมดจะลงเอยที่โค้ดต่อไปนี้จากเมธอด __load ภายในคลาส App:

    บิงโก! โดยการแทนที่ตัวแปร $file เราสามารถรวมโค้ด PHP ของเราเองได้! ยิ่งไปกว่านั้น นี่จะเป็นจุดบกพร่องการรวมไฟล์ระยะไกลอย่างแท้จริง ดังนั้น เราจึงไม่ต้องการเทคนิคเพิ่มเติมใดๆ ในการอัปโหลดไฟล์ในเครื่องไปยังเซิร์ฟเวอร์ อย่างไรก็ตาม ผู้เขียนช่องโหว่ที่พบแนะนำให้ LFI ใช้ประโยชน์จากช่องโหว่นี้ เนื่องจาก CakePHP ใช้ไฟล์แคชในเครื่อง ซึ่งอยู่ในรูปแบบซีเรียลไลซ์ในไดเร็กทอรีที่แคร็กเกอร์รู้จัก

    เอาเปรียบ

    ในฐานะ PoC ขนาดเล็กสำหรับสร้างสตริงซีเรียลไลซ์ที่เป็นพิษ เฟลิกซ์แนะนำโค้ดต่อไปนี้:

    แน่นอน คุณต้องรวมคลาสที่จำเป็นจาก CakePHP ก่อน นอกจากนี้ยังมีการใช้ประโยชน์จาก Python ที่มีคุณลักษณะครบถ้วน ซึ่งคุณสามารถดูได้ที่ malloc.im/burnedcake.py

    พล็อตนี้ควรใช้งานได้ในทุกแอปพลิเคชันที่สร้างด้วย CakePHP ที่ใช้แบบฟอร์ม POST พร้อมโทเค็นความปลอดภัยและไม่ได้เปลี่ยนตำแหน่งไฟล์แคชเริ่มต้น ตามค่าเริ่มต้นช่องโหว่จะแสดงการกำหนดค่าฐานข้อมูล ประโยชน์อื่น ๆ สามารถเพิ่มได้อย่างง่ายดายโดยการเปลี่ยนเพย์โหลด PHP ในตัว

    เป้าหมาย
    • CakePHP getState("filter_order_dir");
      $filter_order = JFilterInput::clean($filter_order, "cmd");
      $filter_order_dir =
      JFilterInput::clean($filter_order_dir, "คำ");
      // เราต้องได้รับรายชื่อทั้งหมด
      // เว็บลิงค์ในหมวดหมู่ที่กำหนด
      $query = "เลือก *"
      " จาก #__เว็บลิงก์" .
      " ที่ไหน catid = ". (int) $this->_id.
      " และเผยแพร่ = 1" .
      "และเก็บถาวร = 0"
      " สั่งโดย ". $filter_order "".
      $filter_order_dir .", สั่งซื้อ";
      ส่งคืน $query;
      }

      ที่นี่ คุณจะเห็นว่าตัวแปร $filter_order และ $filter_order_dir ไม่ได้รับการตรวจสอบความสอดคล้องอย่างเข้มงวดกับคำสั่ง SQL แต่จะตรวจสอบโดยใช้วิธีการล้างมาตรฐานจากคลาส JFilterInput เท่านั้น: