2 คะแนน โดย GN⁺ 2024-04-13 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • XZ Utils/liblzma backdoor ถูกเปิดเผยเมื่อวันที่ 29 มีนาคม 2024 บนเมลลิงลิสต์ Openwall OSS-security และมีความเป็นไปได้สูงว่าเป้าหมายสุดท้ายของผู้โจมตีคือฝังความสามารถในการรันโค้ดจากระยะไกลลงใน sshd ซึ่งเป็นเซิร์ฟเวอร์ OpenSSH บนดิสโทรที่ใช้ systemd
  • ห่วงโซ่การติดเชื้อประกอบด้วยการ แทรกหลายชั้น โดยอาศัยไฟล์ทดสอบและโครงสร้างการบิลด์ของ XZ ผ่าน build-to-host.m4, bad-3-corrupt_lzma2.xz, good-large_compressed.lzma ก่อนที่ไฟล์ออบเจ็กต์อันตรายจะถูกลิงก์เข้ากับ liblzma ระหว่างการบิลด์
  • XZ 5.6.0 และ 5.6.1 ที่มี backdoor ถูกแจกจ่ายในบิลด์เบต้าและบิลด์ทดลองของผู้จำหน่ายรายใหญ่บางราย และ CVE-2024-3094 ถูกจัดให้มีระดับความรุนแรง 10 คะแนน
  • backdoor ระดับไบนารีถูกโหลดโดยอาศัย GLIBC IFUNC และเส้นทางการเรียก cpuid จากนั้นพยายาม hook ฟังก์ชันที่เกี่ยวข้องกับ OpenSSL/libcrypto เพื่อเฝ้าดูการเชื่อมต่อของเครื่องที่ติดเชื้อ
  • โค้ดอันตรายจะตรวจสอบว่ามีการรัน /usr/bin/sshd อยู่หรือไม่ และตรวจสอบตัวแปรแวดล้อม kill switch พร้อมใช้การประมวลผลสตริงแบบ trie, การ resolve สัญลักษณ์แบบไดนามิก และการแพตช์รันไทม์ rtdl-audit เพื่อทำให้การวิเคราะห์และการตรวจจับยากขึ้น

ภาพรวมเหตุการณ์และขอบเขตผลกระทบ

  • เมื่อวันที่ 29 มีนาคม 2024 มีการเปิดเผยการค้นพบ XZ backdoor ผ่านข้อความ ในเมลลิงลิสต์ Openwall OSS-security
  • XZ คือ ยูทิลิตีบีบอัดข้อมูล ที่ถูกรวมอยู่ใน Linux distribution หลักหลายตัว
  • ประเด็นสำคัญของความเสี่ยงคือ liblzma ที่มี backdoor สามารถเชื่อมโยงกับโปรเซส OpenSSH server sshd ได้ในบางดิสโทรที่ใช้ systemd
    • Ubuntu, Debian, RedHat/Fedora Linux มีการแพตช์ให้ OpenSSH ใช้ความสามารถของ systemd จึงพึ่งพาไลบรารีนี้
    • สรุปได้ว่า Arch Linux และ Gentoo ไม่ได้รับผลกระทบ
  • มีความเป็นไปได้สูงว่าเป้าหมายสุดท้ายของผู้โจมตีคือการใส่ความสามารถ sshd remote code execution ที่ผู้อื่นไม่สามารถใช้งานได้
  • ต่างจากการโจมตี supply chain แบบอื่นที่มักเน้นแพตช์อันตรายเพียงตัวเดียว แพ็กเกจปลอม หรือแพ็กเกจ typo-squatting เหตุการณ์นี้ใกล้เคียงกับ ปฏิบัติการหลายขั้นตอนที่เกือบประสบความสำเร็จในการเจาะ SSH server ทั่วโลก

วิธีที่ backdoor ถูกใส่เข้าไป

  • backdoor ใน liblzma ถูกแทรกในสองระดับ โดยใช้ทั้งกระบวนการบิลด์และไฟล์ทดสอบร่วมกัน
    • ซอร์สโค้ดของโครงสร้างการบิลด์ ที่ใช้สร้างแพ็กเกจสุดท้ายถูกแก้ไขด้วยการเพิ่ม build-to-host.m4
    • สคริปต์และองค์ประกอบไบนารีที่ซ่อนอยู่ในไฟล์ test case ถูกดึงออกมาระหว่างการบิลด์
  • กระบวนการติดเชื้อดำเนินไปโดยมีสามไฟล์เป็นแกนหลัก
    • build-to-host.m4: สคริปต์บิลด์ที่ดึงสคริปต์ขั้นถัดไปออกมา
    • bad-3-corrupt_lzma2.xz: ไฟล์ทดสอบที่ซ่อนเชลล์สคริปต์ไว้
    • good-large_compressed.lzma: ไฟล์ทดสอบที่ซ่อนไบนารีออบเจ็กต์อันตรายไว้
  • องค์ประกอบไบนารีอันตรายที่ถูกดึงออกมานั้นถูกลิงก์เข้ากับไลบรารีปกติระหว่างขั้นตอนคอมไพล์ และอาจถูกส่งต่อไปยัง repository ของ Linux ได้
  • ผู้จำหน่ายหลักบางรายได้แจกจ่ายองค์ประกอบอันตรายนี้ใน บิลด์เบต้าและบิลด์ทดลอง
  • การเจาะ XZ Utils นี้ได้รับการกำหนดเลข CVE-2024-3094 และมีระดับความรุนแรงสูงสุดที่ 10 คะแนน

ไทม์ไลน์หลัก

  • 19 มกราคม 2024: เมนเทนเนอร์ใหม่ jiaT75 ย้ายเว็บไซต์ XZ ไปยัง GitHub Pages
  • 15 กุมภาพันธ์ 2024: เพิ่ม build-to-host.m4 ลงใน .gitignore
  • 23 กุมภาพันธ์ 2024: เพิ่ม “ไฟล์ทดสอบ” สองไฟล์ที่มีขั้นตอนสคริปต์อันตรายอยู่ภายใน
  • 24 กุมภาพันธ์ 2024: ออก XZ 5.6.0
  • 26 กุมภาพันธ์ 2024: มีคอมมิตใน CMakeLists.txt ที่ขัดขวางความสามารถด้านความปลอดภัยของ Landlock
  • 4 มีนาคม 2024: backdoor ทำให้เกิดปัญหาที่เกี่ยวข้องกับ Valgrind
  • 9 มีนาคม 2024: อัปเดตไฟล์ทดสอบทั้งสอง แก้ไขฟังก์ชัน CRC และ “แก้ไข” ปัญหา Valgrind
  • 9 มีนาคม 2024: ออก XZ 5.6.1
  • 28 มีนาคม 2024: พบบั๊กและแจ้ง Debian กับ RedHat
  • 28 มีนาคม 2024: Debian rollback XZ 5.6.1 กลับไปเป็นเวอร์ชัน 5.4.5-0.2
  • 29 มีนาคม 2024: มีการโพสต์อีเมลเปิดเผยต่อสาธารณะในเมลลิงลิสต์ OSS-security
  • 29 มีนาคม 2024: RedHat ยืนยันว่า XZ ที่มี backdoor ถูกแจกจ่ายไปยัง Fedora Rawhide และ Fedora Linux 40 beta
  • 30 มีนาคม 2024: Debian หยุดการบิลด์และเริ่มขั้นตอนการ rebuild
  • 2 เมษายน 2024: นักพัฒนาหลักของ XZ ยอมรับเหตุการณ์ backdoor

3 ขั้นของห่วงโซ่การติดเชื้อ

  • ขั้นที่ 1: build-to-host.m4 ที่ถูกแก้ไข

    • รีลีสจาก GitHub repository ทางการของ XZ มีไฟล์ทดสอบอันตรายรวมอยู่ แต่ในตอนแรกยังไม่เป็นอันตรายเพราะไม่มีโอกาสถูกเรียกใช้
    • โค้ดอันตรายที่ใช้ bootstrap การติดเชื้อดูเหมือนจะรวมอยู่ในรีลีสที่ให้บริการจาก jiaT75 ซึ่งควบคุม xz[.]tukaani.org
    • ดิสโทรส่วนใหญ่ใช้ URL นี้ และรีลีสที่ดาวน์โหลดมามีไฟล์ build-to-host.m4 ที่มีโค้ดอันตรายอยู่
    • build-to-host.m4 จะถูกรันระหว่างกระบวนการบิลด์ โดยใช้ tr แก้ข้อมูลที่ “เสีย” ใน bad-3-corrupt_lzma2.xz แล้วแตกไฟล์ด้วย xz -d
    • ผลลัพธ์หลังแตกไฟล์มี เชลล์สคริปต์ ที่ภายหลังจะถูกรันด้วย /bin/bash
  • ขั้นที่ 2: เชลล์สคริปต์ที่ถูกแทรก

    • สคริปต์ที่ไฟล์ .m4 อันตรายแทรกเข้ามาจะตรวจสอบว่ากำลังรันบนเครื่อง Linux หรือไม่ และรันอยู่ในกระบวนการบิลด์ที่ตั้งใจไว้หรือไม่
    • ขั้นตอนถัดไปใช้ good-large_compressed.lzma
    • ไฟล์นี้ถูกบีบอัดด้วย XZ อย่างปกติ แต่ในข้อมูลหลังแตกมี junk data ปะปนอยู่
    • สคริปต์จะรันชุดคำสั่ง head ผ่าน eval เพื่อดึงข้อมูลออกมา
    • คำสั่ง head แต่ละตัวจะข้าม 1024 ไบต์ถัดไป หรือดึง 2048 ไบต์ถัดไป หรือ 724 ไบต์ถัดไป
    • มีการดึงข้อมูลรวม 33,492 ไบต์
    • tail จะเก็บ 31,265 ไบต์ สุดท้ายของไฟล์ไว้และละทิ้งส่วนที่เหลือ
    • จากนั้นใช้ tr ทำการแทนที่พื้นฐานเพื่อคลายการ obfuscate แล้วใช้คำสั่ง XZ ครั้งที่สองแตกไบต์ที่แปลงแล้วเป็น raw lzma stream ก่อนส่งผลลัพธ์เข้าเชลล์
  • ขั้นที่ 3: การดึงออบเจ็กต์ backdoor

    • เชลล์สคริปต์ในขั้นสุดท้ายจะตรวจสอบหลายเงื่อนไขเพื่อยืนยันว่ากำลังรันอยู่ในสภาพแวดล้อมที่คาดไว้
    • ตรวจสอบว่าโปรเจ็กต์ถูกตั้งค่าให้ใช้ IFUNC หรือไม่
    • ตรวจสอบว่ามีการคอมไพล์ด้วย GCC หรือไม่
    • จากนั้นตรวจสอบว่ามีไฟล์บางตัวที่สคริปต์ต้องใช้ในโปรเจ็กต์หรือไม่
    • ขั้นนี้จะดึง ไฟล์ออบเจ็กต์ ที่ซ่อนอยู่ใน offset อื่นของ good-large_compressed.lzma
    • ขั้นตอนการดึงจะรันหลายคำสั่งต่อเนื่องกัน โดยส่ง output ของแต่ละคำสั่งไปเป็น input ของคำสั่งถัดไป
    • ใช้เครื่องมือ XZ แตก good-large_compressed.lzma
    • ใช้ eval $i และการเรียก head หลายครั้ง
    • ถอดรหัสข้อมูลไบนารีด้วยอัลกอริทึมแบบกำหนดเองที่คล้าย RC4
    • แตกไฟล์ที่ถูกถอดรหัสแล้วอีกครั้งด้วย XZ
    • ตัดไบต์บางส่วนช่วงต้นออก ก่อนบันทึกผลลัพธ์เป็น liblzma_la-crc64-fast.o
    • สุดท้ายสคริปต์จะแก้ฟังก์ชัน is_arch_extension_supported ในไฟล์ crc_x86_clmul.h ของ liblzma
    • เปลี่ยนการเรียก __get_cpuid เป็น _get_cpuid โดยลบขีดล่างออกหนึ่งตัว
    • การเปลี่ยนแปลงนี้ทำให้ออบเจ็กต์ backdoor สามารถถูกลิงก์เข้าไลบรารีได้

วิธีโหลด backdoor ระดับไบนารี

  • โค้ด XZ เดิมมีฟังก์ชันพิเศษสำหรับคำนวณ CRC คือ lzma_crc32 และ lzma_crc64
  • ฟังก์ชันทั้งสองถูกเก็บใน ELF symbol table เป็นชนิด IFUNC ของ GLIBC
    • IFUNC ทำให้ dynamic linker สามารถเลือกฟังก์ชันที่จะใช้แบบไดนามิกขณะโหลด shared library
    • XZ ใช้ความสามารถนี้เพื่อตัดสินใจว่าจะใช้ฟังก์ชัน CRC ที่ปรับแต่งแล้วหรือไม่ หลังตรวจสอบความสามารถของโปรเซสเซอร์สมัยใหม่อย่าง CLMUL, SSSE3, SSE4.1
  • การตรวจสอบความสามารถของโปรเซสเซอร์ต้องใช้คำสั่ง cpuid และมีการเรียก wrapper __get_cpuid ที่ GLIBC จัดเตรียมไว้
  • เมื่อสคริปต์อันตรายเปลี่ยน __get_cpuid เป็น _get_cpuid การเรียกจากโค้ดจึงถูกเชื่อมไปยัง สัญลักษณ์ _get_cpuid ภายในไฟล์ออบเจ็กต์ backdoor
  • โค้ด backdoor ระยะแรกจะถูกเรียกสองครั้ง เพราะทั้ง lzma_crc32 และ lzma_crc64 ใช้ฟังก์ชัน _get_cpuid ที่ถูกแก้ไขตัวเดียวกัน
    • มันใช้เคาน์เตอร์อย่างง่ายเพื่อตรวจสอบว่าเคยรันแล้วหรือยัง
    • เมื่อ lzma_crc64 IFUNC เรียก _get_cpuid และค่าเคาน์เตอร์เท่ากับ 1 จะเริ่มขั้นตอน redirect ไปยัง entry point สุดท้าย

พฤติกรรมขณะรันและเป้าหมายการ hook

  • backdoor จะเริ่มต้นโครงสร้างข้อมูลที่เก็บข้อมูลสำคัญของโปรเซสที่กำลังรันอยู่
  • มันค้นหาที่อยู่ของ Global Offset Table(GOT) จาก offset ที่ hardcode ไว้ แล้วค้นหาพอยน์เตอร์ cpuid ภายในนั้น
  • จากนั้นแทนที่พอยน์เตอร์ด้วยฟังก์ชันอันตรายหลัก เพื่อให้เรียกฟังก์ชันอันตรายได้ ราวกับเป็นการเรียก cpuid
  • เป้าหมายหลักคือ hook ฟังก์ชันบางตัวเพื่อเฝ้าดูการเชื่อมต่อที่เข้ามายังเครื่องที่ติดเชื้อ
  • ฟังก์ชันเป้าหมายเกี่ยวข้องกับ libcrypto
    • RSA_public_decrypt: ใช้ถอดรหัส ciphertext ที่ถูกเซ็นด้วย private key
    • EVP_PKEY_set1_RSA: ใช้ตั้งค่า RSA key ของ context บางตัว
      • ไม่มีใน SSH server เวอร์ชันใหม่ แต่ใช้ในเครื่องมือสร้าง SSH key แบบแยกต่างหาก
    • RSA_get0_key: ใช้ดึง RSA key
  • กระบวนการ hook ต้องอาศัยการเข้าถึงโครงสร้างภายในหลายตัวและการจัดการโครงสร้างเฉพาะโปรเซส โดยโค้ดอันตรายยังทำการตรวจสอบเพื่อหลบเลี่ยงการวิเคราะห์ควบคู่กันไป

การตรวจสอบสภาพแวดล้อมการรันและเทคนิคหลบเลี่ยงการวิเคราะห์

  • การตรวจสอบ sshd และ kill switch

    • backdoor จะเริ่มจากการ parse dynamic linker ld-linux เพื่อ resolve ที่อยู่ของสัญลักษณ์แบบไดนามิก
    • จากนั้นตรวจสอบว่าสภาพแวดล้อมการรันปัจจุบันตรงตามเกณฑ์หรือไม่
    • ตรวจสอบว่าโปรเซสปัจจุบันคือ /usr/bin/sshd หรือไม่
    • ตรวจสอบว่ามี kill switch อยู่หรือไม่
    • ชื่อโปรเซสปัจจุบันถูกดึงมาจาก argv[0]
    • มีการ parse ตัวแปรแวดล้อมของโปรเซสทั้งหมด แล้วตรวจสอบว่าตรงกับค่าที่อยู่ใน internal string table หรือไม่
    • หากพบตัวแปรแวดล้อมที่ตรงกัน หรือโปรเซสไม่ใช่ sshd โค้ดอันตรายจะหยุดทำงาน
    • ตัวแปรเดียวในตารางภายในคือ yolAbejyiejuvnup=Evjtgvsh5okmkAvj ซึ่งทำหน้าที่เป็น kill switch ในบริบทนี้
  • การประมวลผลสตริงแบบ trie

    • หนึ่งในลักษณะเด่นของ backdoor คือใช้โครงสร้าง trie เดียวสำหรับงานเกี่ยวกับสตริง
    • แทนที่จะเทียบค่าคงที่อย่างชื่อฟังก์ชันโดยตรง หรือเปรียบเทียบผ่าน string hash มันจะตรวจว่าผลลัพธ์จากการค้นหาใน trie เท่ากับค่าคงที่ที่กำหนดหรือไม่
    • magic value ของ ELF header จะทำให้ trie คืนค่า 0x300
    • ชื่อฟังก์ชัน system จะจับคู่กับค่าที่คืนกลับ 0x9F8
    • trie ไม่ได้ใช้แค่การเปรียบเทียบ แต่ยังใช้ค้นหาสตริงภายใน host binary ด้วย
    • ตัวอย่างเช่น ฟังก์ชันที่ใช้พอยน์เตอร์สตริงอย่าง ssh-2.0 จะค้นหาสตริงจาก host binary เพื่อไม่ให้มีข้อมูลน่าสงสัยค้างอยู่ในตัว backdoor เอง
    • การใช้งานนี้ใช้บิตแมสก์ขนาด 16 ไบต์
    • แต่ละครึ่งสอดคล้องกับช่วงไบต์อินพุต 0x00-0x3F, 0x40-0x7F
    • trie leaf node มีขนาด 2 ไบต์ โดย 3 บิตใช้เป็น flag และส่วนที่เหลือสงวนไว้สำหรับค่า หรือชี้ไปยังตำแหน่งของโหนดถัดไป

การ resolve สัญลักษณ์และการ hook ผ่าน rtdl-audit

  • รูทีน resolve สัญลักษณ์

    • backdoor มี รูทีน resolve สัญลักษณ์ อย่างน้อย 3 ตัวสำหรับค้นหาโครงสร้าง ELF Symbol
    • ฟังก์ชัน resolve สัญลักษณ์ทั้งหมดรับคีย์สำหรับค้นหาใน trie เป็นอินพุต
    • หนึ่งในฟังก์ชัน resolve จะไล่ดูสัญลักษณ์ทั้งหมดเพื่อหาตัวที่มีคีย์ที่ต้องการ และเมื่อพบจะคืนค่าโครงสร้าง Elf64_Sym
    • จากนั้นโครงสร้างนี้จะถูกใช้เติมค่าในโครงสร้างภายในของ backdoor เพื่อเก็บฟังก์ชันพอยน์เตอร์ที่จำเป็น
    • กระบวนการนี้คล้ายกับ API hashing routine ที่พบได้บ่อยในภัยคุกคามฝั่ง Windows
    • จากนั้น backdoor จะค้นหาฟังก์ชัน OpenSSL libcrypto จำนวนมากเพื่อนำไปใช้ในรูทีนเข้ารหัส
    • มันติดตามจำนวนฟังก์ชันที่ค้นหาและ resolve สำเร็จ และใช้ค่านี้ตัดสินใจว่าจะทำงานต่ออย่างปกติหรือหยุดทำงาน
  • fake allocator ที่อาศัย lzma_alloc

    • ตัว resolve สัญลักษณ์อีกตัวหนึ่งอาศัยฟังก์ชัน lzma_alloc ของ liblzma เอง
    • lzma_alloc เป็นฟังก์ชันที่ช่วยจัดสรรหน่วยความจำอย่างมีประสิทธิภาพ โดยใช้ allocator ปกติอย่าง malloc หรือ custom allocator
    • ใน XZ backdoor ฟังก์ชันนี้ถูกทำให้ทำงานราวกับเป็นตัว resolve สัญลักษณ์อีกตัวผ่าน fake allocator
    • พารามิเตอร์ที่เดิมใช้เป็น “ขนาดการจัดสรร” กลับถูกใช้เป็นคีย์สัญลักษณ์ภายใน trie
    • กลเม็ดนี้มีจุดประสงค์เพื่อทำให้การวิเคราะห์ backdoor ยากขึ้น
    • backdoor ทำการ resolve สัญลักษณ์แบบไดนามิกระหว่างรัน โดยไม่ได้จำกัดว่าจะต้อง resolve ทั้งหมดครั้งเดียวหรือ resolve เฉพาะเมื่อจำเป็นเท่านั้น
    • เป้าหมายที่ถูก resolve มีตั้งแต่ฟังก์ชัน OpenSSL ปกติไปจนถึง system ที่ใช้รันคำสั่งบนเครื่อง
  • การแพตช์รันไทม์ rtdl-audit

    • backdoor ใช้ความสามารถ rtdl-audit ของ dynamic linker เพื่อทำ function hooking
    • ปกติแล้ว rtdl-audit เป็นความสามารถที่ช่วยให้นักพัฒนาสร้าง shared library แบบกำหนดเองเพื่อรับการแจ้งเหตุการณ์ของ linker เช่น การ resolve สัญลักษณ์
    • XZ backdoor ไม่ได้สร้าง shared library แยกต่างหาก แต่เลือก แพตช์อินเทอร์เฟซเริ่มต้นที่ลงทะเบียนอยู่ในหน่วยความจำในขณะรัน เพื่อยึดการทำงานของรูทีน resolve สัญลักษณ์
    • โครงสร้าง audit_iface อันตรายที่เก็บอยู่ในตัวแปร global dl_audit ในหน่วยความจำของ dynamic linker มีที่อยู่ callback ของ symbind64
    • เมื่อ dynamic linker เรียก callback นี้ ข้อมูลสัญลักษณ์ทั้งหมดจะถูกส่งไปอยู่ภายใต้การควบคุมของ backdoor และสำหรับฟังก์ชันเป้าหมายก็จะคืนที่อยู่อันตรายกลับมา ทำให้การ hook สำเร็จ
    • ที่อยู่ของ dl_audit และ dl_naudit ได้มาจากการ disassemble ฟังก์ชัน dl_main และ dl_audit_symbind_alt
    • backdoor มี disassembler ขนาดย่อมภายในสำหรับถอดรหัสคำสั่ง และถูกใช้อย่างกว้างขวางเมื่อต้องค้นหาค่าบางอย่าง เช่น ที่อยู่ *audit

ชุดแจกจ่ายที่ยืนยันว่ามี backdoor และข้อมูลการตรวจจับ

  • ซอร์สแพ็กเกจที่มี backdoor

    • xz-5.6.0
      • MD5: c518d573a716b2b2bc2413e6c9b5dbde
      • SHA1: e7bbec6f99b6b06c46420d4b6e5b6daa86948d3b
      • SHA256: 0f5c81f14171b74fcc9777d302304d964e63ffc2d7b634ef023a7249d9b5d875
    • xz-5.6.1
      • MD5: 5aeddab53ee2cbd694f901a080f84bf1
      • SHA1: 675fd58f48dba5eceaf8bfc259d0ea1aab7ad0a7
      • SHA256: 2398f4a8e53345325f44bdd9f0cc7401bd9025d736c6d43b372f4dea77bf75b8
  • อาร์ติแฟกต์หลักที่ถูกวิเคราะห์

    • bad-3-corrupt_lzma2.xz: 86fc2c94f8fa3938e3261d0b9eb4836be289f8ae
    • build-to-host.m4: b4dd2661a7c69e85f19216a6dbbb1664
    • good-large_compressed.lzma: 540c665dfcd4e5cfba5b72b4787fec4f
    • liblzma_la-crc64-fast.o: 212ffa0b24bb7d749532425a46764433
  • ไลบรารีที่ทราบว่ามี backdoor

    • Debian Sid liblzma.so.5.6.0
      • MD5: 4f0cf1d2a2d44b75079b3ea5ed28fe54
      • SHA1: 72e8163734d586b6360b24167a3aff2a3c961efb
      • SHA256: 319feb5a9cddd81955d915b5632b4a5f8f9080281fb46e2f6d69d53f693c23ae
    • Debian Sid liblzma.so.5.6.1
      • MD5: 53d82bb511b71a5d4794cf2d8a2072c1
      • SHA1: 8a75968834fc11ba774d7bbdc566d272ff45476c
      • SHA256: 605861f833fc181c7cdcabd5577ddb8989bea332648a8f498b4eef89b8f85ad4
  • ชื่อการตรวจจับ

    • ผลิตภัณฑ์ของ Kaspersky ตรวจจับออบเจ็กต์อันตรายที่เกี่ยวข้องกับการโจมตีนี้เป็น HEUR:Trojan.Script.XZ และ Trojan.Shell.XZ
    • Kaspersky Endpoint Security for Linux ตรวจจับโค้ดอันตรายในหน่วยความจำของโปรเซส SSHD เป็น MEM:Trojan.Linux.XZ ซึ่งเป็นส่วนหนึ่งของงาน Critical Areas Scan
    • กฎ Yara ที่ให้มาคือกฎ liblzma_get_cpuid_function สำหรับค้นหาฟังก์ชัน get_cpuid อันตรายที่เกี่ยวข้องกับ CVE-2024-3094

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

 
GN⁺ 2024-04-13
ความคิดเห็นจาก Hacker News
  • ประโยคนี้ดูเหมือนจะพูดให้สิ่งที่เกิดขึ้นจริงเบาลงเสียด้วยซ้ำ
    สิ่งที่น่ากลัวกว่าด้านเทคนิคของแบ็กดอร์คือ ปริมาณและระดับของวิศวกรรมสังคม แบ็กดอร์เป็นเพียงผลลัพธ์สุดท้าย และที่มันถูกใส่เข้าไปได้ก็เพราะ ณ จุดนั้น โปรเจกต์ xz ทั้งหมดถูกผู้ไม่หวังดี คือ “Jia Tan” และคนรอบตัว เข้าควบคุมมาเป็นเวลานานแล้ว มีการทำสงครามจิตวิทยากับผู้ดูแลนานกว่าหนึ่งปี โดยที่ผู้ดูแลหรือคนอื่น ๆ ไม่ทันสังเกตเห็น
    มันเหมือนเรื่องในนิยายสายลับ และถ้าเรื่องแบบนี้เป็นไปได้ ก็ทำให้อยากรู้ว่าตอนนี้ในโปรเจกต์อื่น ๆ กำลังเกิดอะไรขึ้นอีกบ้าง
    แนวคิดแบบเดียวกันนี้ยังปรากฏอยู่ในโค้ดแบ็กดอร์เองด้วย ไม่ใช่แค่พยายามทำให้ดูไม่มีพิษภัย แต่ยังสร้าง เรื่องเล่า อย่างแข็งขันผ่านข้อความ commit, คอมเมนต์, ชื่อตัวแปร, การเลือกคำสั่ง ฯลฯ ว่าภายนอกดูเหมือนมันทำอะไร ทั้งที่จริงแล้วถูกทำให้ทำอีกอย่างโดยสิ้นเชิง โครงสร้างคือทำให้คนที่ตรวจโค้ดก่อนสงสัยความเข้าใจของตัวเอง จากนั้นสงสัยว่าเป็นบั๊ก แล้วกว่าจะสงสัยว่าเป็นเจตนาร้ายก็ผ่านไปนานแล้ว

    • นี่อยู่ในระดับที่แทบไม่น่าเชื่อจริง ๆ อาจฟังดูเหมือนทฤษฎีสมคบคิด แต่ก็อดสงสัยไม่ได้ว่าอาจมี ปฏิบัติการจิตวิทยาในโลกจริง ที่ทำให้ผู้เขียนดั้งเดิมไม่มีเวลา และท้ายที่สุดต้องส่งต่อความเป็นเจ้าของให้ผู้ไม่หวังดีหรือไม่
      หวังว่าหน่วยข่าวกรองใด ๆ ก็ตามจะกำลังสืบสวนคดีนี้ให้ลึกขึ้น
    • หวังว่าเราจะเอาเรื่องนี้เป็นบทเรียนได้ จริง ๆ แล้วมีเรื่องแบบนี้เกิดขึ้นมากมาย ในบรรดาหน่วยงานที่ได้รับการสนับสนุนจากรัฐบาลทั่วโลกและองค์กรตลาดมืด มีจำนวนมากที่มีภารกิจคือ การได้มาซึ่งแบ็กดอร์ และมีเงินทุนเพียงพอ นั่นคืองานของพวกเขา
      เห็นทุกเธรด HN เรื่องแบ็กดอร์แล้วหงุดหงิดที่ความเป็นไปได้นี้ถูกปฏิเสธว่าเป็นความหวาดระแวงหรือพวกหมวกฟอยล์อะลูมิเนียม ทำเหมือนเป็นเรื่องที่ไม่เกิดขึ้น แต่ครั้งนี้เป็นแค่กรณีรูปธรรมที่ถูกจับได้เท่านั้น ยังมีอีกนับไม่ถ้วนที่ยังไม่ถูกจับได้
      กรณีนี้เป็นโปรเจกต์โอเพนซอร์ส จึงนับว่าค้นพบได้ค่อนข้างง่ายกว่า แต่ก็ยังถือว่าโชคดี ลองนึกถึงผลิตภัณฑ์ซอร์สปิดดู การใส่แบ็กดอร์จะลดรูปเหลือแค่ปัญหาการแทรกซึมหรือกดดันองค์กรหนึ่ง เรื่องแบบนี้เกิดขึ้นบ่อย ไม่มีใครอยากเชื่อ แต่เป็นเรื่องทั่วไป คนที่เคยทำงานในบริษัทโครงสร้างพื้นฐานทางเทคโนโลยีน่าจะมีเรื่องเล่าอยู่บ้าง แค่พูดยากเพราะ NDA หรือเหตุผลที่หนักกว่านั้น แต่มันเกิดขึ้นจริง
    • เห็นด้วยอย่างยิ่งกับประเด็นที่ว่ามันทำให้คนตรวจโค้ดสงสัยความเข้าใจของตัวเอง การชักใย ความประณีต ความอดทน และความดื้อดึง ที่ใส่ลงไปในเรื่องนี้น่าทึ่งมาก
      อาจเป็นผลลัพธ์จากความหมกมุ่นของใครสักคน หรืออาจเป็นงานของบริษัทรักษาความปลอดภัยเอกชนหรือผู้เล่นระดับรัฐที่ทำเรื่องแบบนี้กับหลายโปรเจกต์เป็นงานประจำ 9 โมงถึง 5 โมงก็ได้
  • เป็นเรื่องธรรมดาที่ความสนใจจนถึงตอนนี้จะไปอยู่ที่ว่าแบ็กดอร์ทำงานสำเร็จอย่างไรและบรรลุเป้าหมายด้วยวิธีไหน
    ถึงอย่างนั้นก็อยากเห็นการวิเคราะห์ที่ลึกขึ้นเกี่ยวกับข้อผิดพลาดและส่วนที่ออกแบบเกินจำเป็น ในบทสัมภาษณ์ Bryan Cantril [1] Andrés บอกว่าสิ่งนี้ดูเหมือนเป็น ชิ้นส่วนแบ็กดอร์สำเร็จรูป ที่ไม่ได้สร้างขึ้นโดยรู้รายละเอียดถึงวิธีแพ็กเกจและเผยแพร่ จึงมีจุดโง่ ๆ อยู่มาก ตัวอย่างเช่นการค้นหา symbol table ที่ทำให้เขาเริ่มสืบสวน
    เช่นเดียวกัน ก็สงสัยว่าทำไมถึงตัด 48 ไบต์ออกด้วย RC4 [2]
    อยากฟังเรื่องว่าถ้ามีเวลามากกว่านี้หรือมีทีมที่ดีกว่านี้ จะทำให้ดีขึ้นได้อย่างไร หรือพลาดหนักกว่านี้ตรงไหน
    [1] https://youtu.be/jg5F9UupL6I?si=gvXsYFXgagkGOMd4
    [2] https://twitter.com/matthew_d_green/status/17744729080201014...

  • ถ้าผมเข้าใจถูก มาตรการเสริมความแข็งแกร่งที่มีประโยชน์น่าจะเป็นการให้ไลบรารีลิงก์แบบไดนามิกแต่ละตัวมี GOT ของตัวเอง และหลังจากการลิงก์แบบไดนามิกเสร็จแล้วให้ทำเครื่องหมายตารางเป็นอ่านอย่างเดียว กล่าวคือเป็นวิธีที่ทำให้ไม่สามารถแพตช์รายการ ifunc ของอีกฝั่งข้ามขอบเขตไดนามิกได้
    วิธีนี้อาจช่วยปรับปรุง ความปลอดภัยของซัพพลายเชน สำหรับโค้ดที่ถูกลิงก์เข้าไปที่ใดที่หนึ่งแต่ไม่ได้ถูกเรียกใช้งาน
    ยิ่งไปกว่านั้น อาจดีกว่าถ้า implement ifunc ในรูปแบบ declarative เพื่อไม่ให้เกิดการรันโค้ดตามอำเภอใจจากแต่ละไลบรารีที่ลิงก์เข้ามา ตอนนี้คงทำได้ยากเพราะต้องรักษาความเข้ากันได้ย้อนหลัง แต่ในระยะยาวดูเหมือนจะค่อย ๆ นำมาใช้เป็นชั้น ๆ ได้ เช่น ถ้าสร้างไลบรารีหนึ่งด้วยบิตฟีเจอร์ “declarative linked ifunc” ก็ให้ dynamic linker ทำให้การรันล้มเหลวเมื่อไลบรารีทั้งหมดที่เชื่อมต่ออยู่ไม่มีแฟล็กฟีเจอร์เดียวกัน

    • มองอีกมุมหนึ่ง ระบบบิลด์ คือปัญหา
      ปัจจุบันการบิลด์ไลบรารีส่วนใหญ่เป็นการรันสคริปต์ที่ซับซ้อนและเข้าใจยากมาก ซึ่งต้องการสภาพแวดล้อมแบบ Turing-complete สิ่งนี้ให้พื้นผิวโจมตีไม่รู้จบแก่ผู้โจมตี และถ้ากระบวนการบิลด์ถูกยึด ก็จะเปิดโอกาสขึ้นมา
      การย้ายไปสู่ กระบวนการบิลด์แบบ declarative ที่ตัวรันเนอร์เป็นเพียง state machine แบบจำกัดน่าจะช่วยได้ ข้อกำหนดที่ว่าก้อนซอร์สทั้งหมดต้องทำซ้ำได้ก็น่าพิจารณาเช่นกัน
    • ทั้งใช่และไม่ใช่ แต่โดยรวมแล้วไม่ใช่ วิธีแบบนี้จะกันไม่ให้ใช้ ifunc อย่างง่าย ๆ ในลักษณะนี้ได้ แต่ประเด็นสำคัญคือผู้เขียนแบ็กดอร์รายนี้สามารถฉีด โค้ดตามอำเภอใจ เข้าไปในไลบรารีที่เข้าไปอยู่ใน address space ของโปรเซสที่อ่อนไหวได้
      ตั้งแต่จุดนั้น การป้องกันทั้งหมดก็ไร้ผล ถ้าต้องการก็สามารถแมป GOT ให้เขียนได้อีกครั้ง และแม้พฤติกรรมแบบนั้นอาจถูกตรวจพบว่า “น่าสงสัย” หรือระบบปฏิบัติการอาจขัดขวางการสลับนั้นได้ แต่โค้ดที่ถูกฉีดเข้าไปก็ยังสามารถพลิก control flow ได้อีกหลายร้อยวิธี อ่าน/เขียนตามอำเภอใจ รันโค้ด ทุกอย่างเป็นไปได้ ไม่มี security mitigation ใดที่จะหยุดการถูกเจาะในระดับนี้ได้ ถ้าต้องการก็สามารถรั่วไพรเวตคีย์แล้วส่งให้ผู้โจมตีโดยตรง หรือเปิดเชลล์ก็ได้ การพยายามออกแบบการป้องกันในขั้นนี้เป็นความพยายามที่เปล่าประโยชน์
    • การทำเครื่องหมายตารางเป็นอ่านอย่างเดียวหลังลิงก์แบบไดนามิกเสร็จแล้ว น่าเสียดายที่ใช้ไม่ได้ การลิงก์แบบไดนามิกเป็นแบบ lazy จึงไม่มีช่วงเวลาที่ถือว่า “เสร็จสิ้น”
      function pointer ที่ถูกต้องจะถูกโหลดเมื่อถูกเรียกครั้งแรก แล้วใส่ลงในตารางแทน stub และจุดเวลานั้นอาจอยู่ไกลในอนาคตแบบไม่แน่นอนก็ได้ ที่จริงแล้วในระบบนิเวศไลบรารีขนาดใหญ่เช่นแอป gtk ฟังก์ชันส่วนใหญ่ที่ถูกลิงก์เข้ามาไม่เคยถูกเรียกเลย
    • ถ้าบิลด์สำหรับสถาปัตยกรรมของโฮสต์ ก็สามารถปิด ifunc ได้ทั้งหมดโดยไม่เสียอะไร ใน Gentoo มักบิลด์ด้วย -march=native และถ้าตั้งค่า -multiarch ใน USE flag ของ glibc ก็ปิด ifunc ได้ง่าย ผมไม่เห็นผลกระทบเชิงลบใด ๆ
    • มีภาษาโปรแกรมไหนที่สามารถ แซนด์บ็อกซ์ การ import ไลบรารีได้ไหม?
  • สำหรับ 3 ขั้นตอนแรก บทความนี้ไม่ได้เพิ่มอะไรมากจากสิ่งที่รู้กันในช่วง 2 สัปดาห์ที่ผ่านมา ถือว่าเป็นบทความสรุปที่ดีพร้อมผังการทำงาน
    แต่ส่วนที่วิเคราะห์ไบนารีได้ละเอียดขนาดนั้นดูเหมือนจะเป็นเรื่องใหม่
    ซอร์สโค้ดที่อยู่ในนั้นถูกสร้างขึ้นมาได้อย่างไร? รัน disassembler แล้วทำความเข้าใจว่าโค้ดทำอะไร จากนั้นเปลี่ยนชื่อทั้งหมดให้เป็นชื่อเชิงอธิบายหรือ? ถ้าทำได้ภายใน 2 สัปดาห์ก็ดูเป็นผลงานที่น่าทึ่งทีเดียว

    • ผู้เขียนคือ GReAT
      Global Research & Analysis Team, Kaspersky Lab
      https://securelist.com/author/great/
      ดูเหมือนผู้เขียนบทความจะเป็นทีมวิเคราะห์มัลแวร์ของ Kaspersky Lab จึงมีความเป็นไปได้สูงว่าจะเชี่ยวชาญด้าน reverse engineering ไบนารีมาก
    • เครื่องมือในภาพหน้าจอพื้นหลังสีขาวคือ IDA Pro ซึ่งเป็น decompiler
      https://hex-rays.com/ida-pro/
  • สิ่งที่อยากรู้จริง ๆ คือ ดีเลย์เริ่มต้นของ SSH ที่เป็นชนวนให้มีการสอบสวน xz นั้นเกิดจากอะไรกันแน่ มีใครหาคำตอบได้หรือยัง?

    • มันทำ การคำนวณ ECC เพิ่มเติมในแต่ละการเชื่อมต่อ แต่บน CPU สมัยใหม่ไม่น่าจะใช้เวลาถึง 500ms
      ตามที่คนที่ reverse engineer โค้ดบอกไว้ ข้อความคำสั่งต้องถูกผูกกับ SSH host key ด้วย ดังนั้นถ้า host key เป็นคีย์ RSA ก็อาจมีการถอดรหัส RSA เพิ่มเติมต่อการเชื่อมต่อแต่ละครั้งด้วย
      ถ้าเป็นแบบนั้นก็น่าจะเพียงพอที่จะเป็นสาเหตุของดีเลย์
    • อาจตั้งใจทำเช่นนั้นก็ได้
      เป็นวิธีง่าย ๆ ในการตรวจจากภายนอกว่าเซิร์ฟเวอร์ติดเชื้อหรือไม่ โดยไม่ต้องพยายามฉีดโค้ดก่อน
  • ผู้เขียนเข้าใจ โครงสร้างภายในของ glibc อย่างลึกมาก เป็นเนื้อหาแบบที่ต้องจมอยู่กับซอร์สโค้ดจนถึงคอถึงจะรู้ได้ และยังมีเทคนิคใหม่ ๆ หลายอย่าง
    custom ELF parser กับ disassembler นั้นซับซ้อนมากจนยากจะจินตนาการว่าโค้ดนั้นไม่เคยถูกใช้ที่อื่นมาก่อน หรือจะไม่ถูกนำไปใช้อีกในอนาคต
    สงสัยว่าเหตุการณ์นี้จะได้รับการสอบสวนอย่างจริงจังในระดับที่สมควรหรือไม่ แต่ก็ดูไม่น่าจะเป็นเช่นนั้น

  • มีใครวิเคราะห์ บั๊กของแบ็กดอร์ ที่ทำให้เกิดข้อผิดพลาดใน Valgrind และทำให้ SSH ช้าลง จนสุดท้ายทำให้เรื่องนี้ถูกเปิดโปงหรือยัง?

    • ดูเหมือนจะเป็นการเขียนหน่วยความจำที่ผิดอย่างชัดเจน: https://www.mail-archive.com/valgrind-users@lists.sourceforg...
      “การแก้” สำหรับ Valgrind คือการปิดใช้งาน ifunc และผลก็คือแบ็กดอร์ถูกปิดใช้งาน ทำให้ข้อผิดพลาดหายไป
      เท่าที่ผมรู้ ความช้าลงมาจาก การค้นหา symbol และ instruction ทั้งหมดที่แบ็กดอร์ทำ
  • ถ้ามองแบบหักมุม เมื่อคิดถึงความพยายามที่ผู้โจมตีใส่ลงไปเพื่อหลบเลี่ยงการตรวจจับในสคริปต์และโค้ด โปรเจกต์ทั้งหมดนี้อาจเป็น ตัวเบี่ยงความสนใจ หรือเป็นแผนสำรองระหว่างที่มีความพยายามหลายอย่างดำเนินอยู่พร้อมกันก็ได้
    เราจะนำหน้าเรื่องแบบนี้ไปได้อย่างไร? การที่ชุมชนไปโฟกัสที่ SSHD จะส่งผลต่อส่วนอื่นของระบบโดยรวมหรือไม่? แล้วด้านเทคนิคอื่น ๆ หรือด้านสังคมล่ะ?
    หมวกฟอยล์อะลูมิเนียมนี่สนุกดี

    • ผมไม่ค่อยมองโลกในแง่ดีนัก แทบไม่มีใคร audit เนื้อหาของไบนารี flatpak ใน Flathub จริง ๆ ด้วยซ้ำ มันถูก build จากซอร์สจริงหรือ? ก็เป็นทำนองว่าให้ผู้เขียนพิสูจน์เองว่าใช่ กลไกการส่งมอบที่ซับซ้อนแบบแบ็กดอร์นี้อาจไม่จำเป็นด้วยซ้ำ
    • เราอาจเขียนทุกอย่างเอง และมีทีมเฉพาะที่ประกอบด้วยนักพัฒนาที่ผ่านการตรวจสอบแล้ว
      หรือไม่ก็ซื้อ closed source จากที่อย่าง Microsoft แล้วหวังว่าพวกเขาจะมีทรัพยากรและความตั้งใจที่จะตรวจทานโค้ดเข้มงวดกว่า
      และแนวทางที่มีได้เสมอคือการมี ทีมปฏิบัติการความปลอดภัย ที่ยอดเยี่ยมเพื่อตรวจจับกิจกรรมเครือข่ายผิดปกติและความพยายามยกระดับสิทธิ์
    • วิธีหนึ่งในการนำหน้าแบ็กดอร์ลักษณะคล้ายกัน คือคิดถึงการห่อทราฟฟิก sshd ด้วย spiped tunnel โดย Spiped คอมไพล์จากซอร์สและลิงก์แบบ static ส่วนเวอร์ชัน stable ล่าสุดเป็นของปี 2021
    • ไอเดียหมวกฟอยล์อะลูมิเนียมของผมคือให้สงสัยผู้มีส่วนร่วมในโอเพนซอร์ส ไม่ใช่เพราะมาจากประเทศใดประเทศหนึ่ง และไม่ใช่เพราะดูเหมือนไม่เคยพบตัวจริง
      แต่ผู้มีส่วนร่วมที่ไม่มีประวัติหรือร่องรอยอื่นใดนอกจากโปรเจกต์ที่กำลังทำอยู่ ควรถูกมองเป็น สัญญาณอันตราย ในอนาคต
    • ไม่จำเป็นต้องมีหมวกฟอยล์อะลูมิเนียมเลย โปรเจกต์ FOSS ถูกฝังแบ็กดอร์มาตั้งแต่ก่อนจะโด่งดังแล้ว ความแตกต่างครั้งนี้คือผู้ลงมือเป็น ผู้ปฏิบัติการที่ได้รับการสนับสนุนจากรัฐ
      กลุ่มยุคก่อนอย่าง GOBBLES, ADM, ac1db1tch3z, ~el8 ก็เคยทำเรื่องแบบนี้ และ “นักวิจัยความปลอดภัย” ภาคเอกชนอย่าง isec.pl ก็เคยทำเช่นกัน
      ที่ครั้งนี้เป็นปัญหาก็เพราะผู้ปฏิบัติการรัฐกำลังฉวยประโยชน์จากทุนนิยมองค์กรที่สร้างยุคซึ่งโปรเจกต์โครงสร้างพื้นฐานถูกค้ำจุนด้วยค่าตอบแทนต่ำ ผู้ไม่หวังดีมีทรัพยากรแทบไม่จำกัดเพื่อบรรลุเป้าหมาย
      เรื่องนั้นเองที่นำไปสู่ความต้องการและการถือกำเนิดขององค์กรอย่าง NSO, Zerodium
      ก่อนหน้านั้น exploit และแบ็กดอร์แทบไม่มีมูลค่า และแฮ็กเกอร์ก็คาดหวังการสนับสนุนหรือการจ้างงานจากบริษัทอย่าง Qualys
  • ผมเคยดูการวิเคราะห์การแฮ็กช่องโหว่ zero-day ของ Google อยู่หลายครั้ง ซึ่งพวกนั้นก็ยอดเยี่ยมจนดูเหนือจริงแล้ว แต่การแฮ็กครั้งนี้น่าจะเป็นหนึ่งในระดับตลอดกาล

  • ผมเห็นว่า repository ของ xz กลับขึ้น GitHub แล้ว และ Lasse กับผู้มีส่วนร่วมคนใหม่กำลังจัดการอยู่ พวกเขาลบการรองรับ ifunc ออก และ commit โค้ดสร้างไฟล์ทดสอบ ลง repository เพื่อให้สร้างไฟล์ทดสอบได้โดยไม่ต้องมี blob ดูเหมือนกำลังทำงานไปในทิศทางที่ดี