3 คะแนน โดย GN⁺ 2024-04-06 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

ช่องโหว่ HTTP/2 CONTINUATION Flood: รายละเอียดทางเทคนิค

  • CONTINUATION Flood เป็นหมวดหมู่ของช่องโหว่ที่พบในอิมพลีเมนเทชันของโปรโตคอล HTTP/2 หลายตัว และเป็นภัยคุกคามที่ร้ายแรงยิ่งกว่าการโจมตี Rapid Reset
  • ผลลัพธ์จากการโจมตีมีได้ตั้งแต่เซิร์ฟเวอร์ล่มไปจนถึงประสิทธิภาพลดลง และคำขอที่ใช้โจมตีจะไม่ปรากฏใน HTTP access log

บทนำ

  • ในเดือนตุลาคม 2023 ผู้เขียนได้ทราบเกี่ยวกับการโจมตี HTTP/2 Rapid Reset และตัดสินใจเริ่มศึกษาจากมุมมองของการวิเคราะห์ความปลอดภัยของ HTTP/2

แนะนำ HTTP/2 แบบย่อ

  • ความแตกต่างหลักระหว่าง HTTP/1.1 กับ HTTP/2 คือแบบหลังเป็นโปรโตคอลแบบไบนารี และไคลเอนต์กับเซิร์ฟเวอร์แลกเปลี่ยน เฟรม กันแทนบรรทัดข้อความ
  • จำเป็นต้องอธิบาย HEADERS frame และ CONTINUATION frame

HEADERS frame

  • HEADERS frame ใช้สำหรับส่ง HTTP header ของคำขอและการตอบกลับ และบีบอัดข้อมูล header ด้วยอัลกอริทึมการเข้ารหัส HPACK
  • ภายในเฟรมสามารถตั้งค่าแฟล็กอย่าง END_HEADERS และ END_STREAM ได้

CONTINUATION frame

  • CONTINUATION frame มีลักษณะคล้าย HEADERS frame มาก แต่มีเพียงแฟล็ก END_HEADERS เท่านั้น และเมื่อแฟล็กนี้ถูกตั้งค่า ก็หมายความว่าสตรีมของ header สิ้นสุดลงแล้ว

ช่องโหว่ CONTINUATION Flood

  • หากไคลเอนต์เริ่ม HTTP/2 stream ใหม่และส่ง HEADERS กับ CONTINUATION frame แต่ ไม่เคย ตั้งค่าแฟล็ก END_HEADERS เลย เซิร์ฟเวอร์จะต้องวิเคราะห์และเก็บสตรีม header ที่ไม่มีที่สิ้นสุดไว้ในหน่วยความจำ
  • ใน HTTP/1.1 มีการป้องกันจาก header แบบไม่สิ้นสุดด้วยการจำกัดขนาด header และกำหนด timeout สำหรับคำขอ/ส่วน header แต่ในเซิร์ฟเวอร์ HTTP/2 จำนวนมาก กลไกป้องกันเหล่านี้ไม่มีอยู่หรือถูกอิมพลีเมนต์ผิดพลาด

การใช้ CPU จนหมด: กรณีของ Golang

  • Golang เป็นตัวอย่างของการใช้ CPU จนหมดจาก CONTINUATION Flood โดยใช้คลาสนามธรรมชื่อ http2MetaHeadersFrame ในการจัดการ HEADERS frame และ CONTINUATION frame
  • ตัวถอดรหัส HPACK ถูกตั้งค่าให้หยุดปล่อย header เมื่อถึงขีดจำกัดขนาด header แต่หากไม่มีแฟล็ก END_HEADERS ฟังก์ชันจะไม่คืนค่าและยังคงถอดรหัส header ต่อไป

หน่วยความจำหมด

  • ภาวะหน่วยความจำหมดเป็นหนึ่งในกรณีที่ร้ายแรงที่สุด เนื่องจากมีอิมพลีเมนเทชันที่ไม่จำกัดขนาดของรายการ header ที่สร้างขึ้นด้วย CONTINUATION frame
  • ในอิมพลีเมนเทชันที่ไม่มี header timeout การเชื่อมต่อ HTTP/2 เพียงครั้งเดียวก็สามารถทำให้เซิร์ฟเวอร์ล่มได้

การทำให้เกิด assertion crash ได้: Node.js (กรณีพิเศษ)

  • Node.js จัดการกับสตรีม CONTINUATION frame ที่ไม่สิ้นสุดได้อย่างเหมาะสม แต่จะเกิดบั๊ก data race เมื่อการเชื่อมต่อถูกตัดระหว่างสตรีม header
  • Node.js ติดตามการจัดสรรหน่วยความจำภายใน destructor ของ Http2Session และเมื่อการเชื่อมต่อถูกตัด ค่า current_nghttp2_memory_ อาจถูกอัปเดตพร้อมกันจนทำให้เกิดการล่มได้

การเปรียบเทียบกับช่องโหว่ HTTP/2 ก่อนหน้า

  • ในอดีตมีการรายงานช่องโหว่ HTTP/2 หลายรายการ และ CONTINUATION Flood ทำงานในลักษณะที่แตกต่างจากช่องโหว่ก่อนหน้า
  • CONTINUATION Flood จะส่ง header ตามอำเภอใจจำนวนมากจนถึงขีดจำกัดขนาดเฟรมที่เซิร์ฟเวอร์ตั้งไว้ แทนที่จะส่ง header ว่าง

หมายเหตุส่งท้าย

  • ทราฟฟิก HTTP/2 คิดเป็นประมาณ 60% ของทราฟฟิก HTTP ที่มนุษย์ใช้งานทั้งหมด และเมื่อพิจารณาถึงความสำคัญของโปรเจกต์ที่ได้รับผลกระทบ ก็หมายความว่าอินเทอร์เน็ตส่วนใหญ่ได้รับผลกระทบจากช่องโหว่ที่ถูกนำไปใช้โจมตีได้ง่าย
  • หากช่องโหว่นี้ถูกนำไปใช้โจมตีจริงในภาคสนาม การดีบักจะเป็นเรื่องยากมากสำหรับผู้ดูแลเซิร์ฟเวอร์ที่ไม่มีความรู้ HTTP/2 อย่างเพียงพอ

ความเห็นของ GN⁺

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

1 ความคิดเห็น

 
GN⁺ 2024-04-06
ความคิดเห็นบน Hacker News
  • Bandit เพิ่งแก้ปัญหานี้ไปเมื่อไม่นานมานี้

    • มีประสบการณ์ส่วนตัวว่า Bandit แก้ปัญหาเดียวกันนี้ไปเมื่อหนึ่งเดือนก่อน
    • ให้ลิงก์ไปยังตำแหน่งโค้ดที่เกี่ยวข้องโดยเฉพาะ
    • จากมุมมองของผู้ลงมือเขียนอิมพลีเมนต์ ปัญหานี้ชัดเจนมาก และคิดว่าอิมพลีเมนต์อื่น ๆ ก็น่าจะมีมาตรการป้องกันไว้แล้ว
    • แต่เมื่อตรวจสอบอิมพลีเมนต์หลายสิบตัว กลับพบว่าแม้แต่เซิร์ฟเวอร์ HTTP/2 รายใหญ่ ๆ ก็ไม่มีมาตรการป้องกันนี้ หรือทำไว้ไม่ถูกต้อง
  • คำวิจารณ์ต่อวัฒนธรรมการพัฒนา

    • ชี้ว่าวัฒนธรรมที่นักพัฒนาคุ้นชินกับการขยายแบบไดนามิกโดยอัตโนมัติมากเกินไป จนไม่ค่อยคิดว่าสิ่งหนึ่งสิ่งใดจะขยายใหญ่ได้แค่ไหน เป็นปัญหา
    • ปัญหานี้ไม่ได้จำกัดอยู่แค่ HTTP/2 แต่ความซับซ้อนของ HTTP/2 อาจทำให้ปัญหารุนแรงขึ้น
    • ในอดีตสมัย HTTP/1.x ที่ใช้ภาษาอย่าง C ต้องคอยระวังเรื่องการจัดการความยาวบัฟเฟอร์อยู่ตลอด และไม่เคยมีการขยาย allocation ของ request header แบบไม่สิ้นสุด
  • รายชื่อเซิร์ฟเวอร์/รีเวิร์สพร็อกซีที่ไม่ได้รับผลกระทบ

    • รายชื่อเว็บเซิร์ฟเวอร์และรีเวิร์สพร็อกซีที่ไม่ได้รับผลกระทบซึ่งถูกกล่าวถึงในบทความก่อนหน้า
    • Nginx, Jetty, HAProxy, NetScaler, Varnish ไม่ได้รับผลกระทบ
  • ข้อกังวลเกี่ยวกับความปลอดภัยของ HTTP/1.1

    • กล่าวถึงว่าเว็บไซต์ของพวกเขาได้รับความสนใจตลอดทั้งวัน
    • ตั้งคำถามว่าหากเว็บไซต์มีทราฟฟิกไม่มาก การใช้ HTTP/1.1 จะปลอดภัยกว่าหรือไม่
  • คำชื่นชมต่อผู้เขียน

    • ชื่นชมที่ผู้เขียนเข้าหาปัญหาด้วยมุมมองที่กว้าง รายงานสิ่งที่ค้นพบอย่างมีความรับผิดชอบ และแบ่งปันออกมาในรูปแบบที่อ่านง่าย
  • การกล่าวถึง Slowloris v2

    • พูดติดตลกว่า ถ้าทำให้ปัญหานี้เกิดขึ้นอย่างช้า ๆ ก็คงเรียกมันว่า 'slowloris v2' ได้
  • การกล่าวถึงคำพิมพ์ผิด

    • รู้สึกขำกับคำพิมพ์ผิดว่า 'serveral retries'
  • มุมมองเชิงวิจารณ์ต่อ HTTP/2

    • วิจารณ์แนวคิดที่พยายามยัด HTTP/2 ให้เป็นชั้นขนส่งสำหรับการ 'อัปเกรด' ไปสู่โปรโตคอลชั้นแอปพลิเคชัน