มันทำอะไรกันแน่ ฉันไม่เข้าใจว่าคุณสามารถเข้าถึงหน่วยความจำพื้นฐานด้วยวิธีนี้ได้อย่างไร ... ดูเหมือนว่าจะแปลก ปลอดภัยไหม
dd if=/dev/urandom of=/dev/mem
มันทำอะไรกันแน่ ฉันไม่เข้าใจว่าคุณสามารถเข้าถึงหน่วยความจำพื้นฐานด้วยวิธีนี้ได้อย่างไร ... ดูเหมือนว่าจะแปลก ปลอดภัยไหม
dd if=/dev/urandom of=/dev/mem
คำตอบ:
ที่จริงแล้วในแพลตฟอร์มส่วนใหญ่มันล้มเหลวโดยมีข้อผิดพลาด แต่ขึ้นอยู่กับสถาปัตยกรรมฮาร์ดแวร์ ไม่มีการรับประกันแน่นอนว่าสิ่งนี้จะไม่เป็นอันตรายเว้นแต่คุณจะเรียกใช้คำสั่งในฐานะผู้ใช้ที่ไม่มีสิทธิพิเศษ ด้วยผู้ใช้ที่ไม่มีสิทธิพิเศษคำสั่งจะไม่เป็นอันตรายอย่างสมบูรณ์เพราะคุณไม่สามารถเปิด/dev/mem
ได้
เมื่อคุณเรียกใช้คำสั่งในฐานะรูทคุณควรจะรู้ว่าคุณกำลังทำอะไรอยู่ เคอร์เนลบางครั้งจะป้องกันไม่ให้คุณทำสิ่งที่อันตราย แต่ไม่เสมอไป /dev/mem
เป็นหนึ่งในสิ่งที่อาจเป็นอันตรายที่คุณควรรู้ว่าคุณกำลังทำอะไรอยู่
ฉันจะอธิบายวิธีการเขียนไปใช้/dev/mem
งานบน Linux หลักการทั่วไปจะเหมือนกันใน Unices อื่น ๆ แต่สิ่งต่าง ๆ เช่นตัวเลือกเคอร์เนลแตกต่างอย่างสิ้นเชิง
จะเกิดอะไรขึ้นเมื่อกระบวนการอ่านหรือเขียนไปยังไฟล์อุปกรณ์ขึ้นอยู่กับเคอร์เนล การเข้าถึงไฟล์อุปกรณ์จะเรียกใช้รหัสบางอย่างในไดรเวอร์ที่จัดการไฟล์อุปกรณ์นี้ ยกตัวอย่างเช่นการเขียนเพื่อ/dev/mem
เรียกฟังก์ชั่นในwrite_mem
drivers/char/mem.c
ฟังก์ชั่นนี้ใช้เวลา 4 ข้อโต้แย้ง: โครงสร้างข้อมูลที่แสดงถึงไฟล์ที่เปิดตัวชี้ไปยังข้อมูลที่จะเขียนจำนวนไบต์ที่จะเขียนและตำแหน่งปัจจุบันในไฟล์
โปรดทราบว่าคุณจะได้รับเมื่อผู้โทรได้รับอนุญาตให้เปิดไฟล์ตั้งแต่แรก ไฟล์อุปกรณ์เชื่อฟังการอนุญาตไฟล์ตามปกติ สิทธิ์ปกติของการ/dev/mem
เป็นcrw-r-----
เจ้าของroot:kmem
ดังนั้นหากคุณพยายามเปิดโดยไม่ต้องรูทคุณจะได้รับ“ สิทธิ์ถูกปฏิเสธ” (EACCESS) แต่ถ้าคุณรูท (หรือถ้ารูทเปลี่ยนสิทธิ์ของไฟล์นี้) การเปิดจะผ่านไปแล้วคุณสามารถลองเขียนได้
รหัสในwrite_mem
ฟังก์ชันทำให้การตรวจสอบมีสติ แต่การตรวจสอบเหล่านี้ไม่เพียงพอที่จะป้องกันทุกสิ่งที่ไม่ดี สิ่งแรกที่ทำคือแปลงตำแหน่งไฟล์ปัจจุบัน*ppos
เป็นที่อยู่จริง หากล้มเหลว (ในทางปฏิบัติเนื่องจากคุณอยู่บนแพลตฟอร์มที่มีที่อยู่ทางกายภาพ 32- บิต แต่ออฟเซ็ตไฟล์ 64- บิตและออฟเซ็ตไฟล์ใหญ่กว่า 2 ^ 32) การเขียนล้มเหลวด้วย EFBIG (ไฟล์ใหญ่เกินไป) การตรวจสอบครั้งต่อไปคือช่วงของที่อยู่ทางกายภาพในการเขียนที่ถูกต้องในสถาปัตยกรรมตัวประมวลผลนี้หรือไม่และมีความล้มเหลวส่งผลให้ EFAULT (ที่อยู่ไม่ถูกต้อง)
ถัดไปใน Sparc และ m68k ส่วนใดส่วนหนึ่งของการเขียนในหน้าฟิสิคัลแรกนั้นจะถูกข้ามอย่างเงียบ ๆ
ตอนนี้เรามาถึงลูปหลักซึ่งวนซ้ำข้อมูลในบล็อกที่สามารถใส่ได้ในหน้าMMUเดียว
/dev/mem
เข้าถึงหน่วยความจำกายภาพไม่ใช่หน่วยความจำเสมือน แต่ตัวประมวลผลคำแนะนำในการโหลดและเก็บข้อมูลในหน่วยความจำใช้ที่อยู่เสมือนดังนั้นรหัสจะต้องจัดเรียงเพื่อแมปหน่วยความจำกายภาพในที่อยู่เสมือนบางแห่ง บน Linux ขึ้นอยู่กับสถาปัตยกรรมตัวประมวลผลและการกำหนดค่าเคอร์เนลการแมปนี้มีอยู่อย่างอนุญาตหรือต้องทำทันที นั่นเป็นหน้าที่ของxlate_dev_mem_ptr
(และunxlate_dev_mem_ptr
ยกเลิกสิ่งที่xlate_dev_mem_ptr
ทำ) จากนั้นฟังก์ชั่นcopy_from_user
จะอ่านจากบัฟเฟอร์ที่ส่งผ่านไปยังwrite
การเรียกของระบบและเพิ่งเขียนไปยังที่อยู่เสมือนที่หน่วยความจำกายภาพถูกแมปในปัจจุบัน รหัสส่งคำแนะนำในการจัดเก็บหน่วยความจำปกติและสิ่งนี้หมายถึงอะไรขึ้นอยู่กับฮาร์ดแวร์
ก่อนที่ฉันจะพูดถึงว่าการเขียนไปยังที่อยู่ทางกายภาพนั้นฉันจะพูดถึงการตรวจสอบที่เกิดขึ้นก่อนการเขียนนี้ ภายในลูปฟังก์ชันpage_is_allowed
ปิดกั้นการเข้าถึงที่อยู่บางอย่างหากCONFIG_STRICT_DEVMEM
เปิดใช้งานตัวเลือกการกำหนดค่าเคอร์เนล(ซึ่งเป็นกรณีโดยค่าเริ่มต้น): เฉพาะที่อยู่ที่อนุญาตโดยdevmem_is_allowed
สามารถเข้าถึงได้ผ่าน/dev/mem
สำหรับคนอื่น ๆ การเขียนล้มเหลวด้วย EPERM คำอธิบายของตัวเลือกนี้ระบุ:
หากเปิดใช้งานตัวเลือกนี้และ IO_STRICT_DEVMEM = n ไฟล์ / dev / mem จะอนุญาตให้ผู้ใช้เข้าถึงพื้นที่ PCI และรหัส BIOS และเขตข้อมูลเท่านั้น นี่เพียงพอสำหรับ dosemu และ X และผู้ใช้ทั่วไปของ / dev / mem
นี่คือคำอธิบาย x86- ศูนย์กลางมาก ในความเป็นจริงโดยทั่วไปแล้วCONFIG_STRICT_DEVMEM
บล็อกการเข้าถึงที่อยู่หน่วยความจำกายภาพที่แมปกับ RAM แต่อนุญาตการเข้าถึงที่อยู่ที่ไม่ได้แมปกับ RAM รายละเอียดของช่วงที่อยู่ทางกายภาพที่ได้รับอนุญาตขึ้นอยู่กับสถาปัตยกรรมของโปรเซสเซอร์ แต่ทั้งหมดไม่รวม RAM ที่ข้อมูลของเคอร์เนลและกระบวนการผู้ใช้ที่ดินจะถูกเก็บไว้ ตัวเลือกเพิ่มเติมCONFIG_IO_STRICT_DEVMEM
(ปิดใช้งานในขณะที่ Ubuntu 18.04) บล็อกการเข้าถึงที่อยู่ทางกายภาพที่อ้างสิทธิ์โดยไดรเวอร์
อยู่หน่วยความจำทางกายภาพที่แมปไป RAM ดังนั้นมีที่อยู่หน่วยความจำกายภาพที่ไม่ได้แมปกับ RAM หรือไม่ ใช่. นั่นคือการสนทนาที่ฉันสัญญาไว้ข้างต้นเกี่ยวกับความหมายของการเขียนไปยังที่อยู่
คำสั่งที่เก็บหน่วยความจำไม่จำเป็นต้องเขียนลง RAM โปรเซสเซอร์จะสลายตัวที่อยู่และตัดสินใจว่าอุปกรณ์ต่อพ่วงใดที่จะส่งต่อร้านค้า (เมื่อฉันพูดว่า "ตัวประมวลผล" ฉันรวมตัวควบคุมอุปกรณ์ต่อพ่วงซึ่งอาจไม่ได้มาจากผู้ผลิตรายเดียวกัน) RAM เป็นเพียงหนึ่งในอุปกรณ์ต่อพ่วงเหล่านั้น วิธีการจัดส่งนั้นขึ้นอยู่กับสถาปัตยกรรมของโปรเซสเซอร์เป็นอย่างมาก แต่ปัจจัยพื้นฐานนั้นมีความเหมือนกันในทุกสถาปัตยกรรม หน่วยประมวลผลโดยทั่วไปจะสลายบิตที่สูงขึ้นของที่อยู่และค้นหามันในบางตารางที่มีประชากรอยู่บนพื้นฐานของข้อมูลที่ได้รับการเข้ารหัสข้อมูลที่ได้รับจากการตรวจสอบรถเมล์และข้อมูลที่กำหนดโดยซอฟต์แวร์ การแคชและการบัฟเฟอร์จำนวนมากอาจเกี่ยวข้อง แต่สรุปหลังจากการสลายตัวนี้รถบัสและจากนั้นขึ้นอยู่กับอุปกรณ์ต่อพ่วงเพื่อจัดการกับมัน (หรือผลลัพธ์ของการค้นหาตารางอาจเป็นเพราะไม่มีอุปกรณ์ต่อพ่วงที่ที่อยู่นี้ซึ่งในกรณีนี้โปรเซสเซอร์จะเข้าสู่สถานะของแทร็บซึ่งจะประมวลผลโค้ดบางส่วนในเคอร์เนลที่โดยปกติแล้วจะส่งผลให้SIGBUSสำหรับกระบวนการเรียก)
ร้านค้าไปยังที่อยู่ที่จับคู่กับ RAM จะไม่“ ทำ” สิ่งใดนอกจากเขียนทับค่าที่เก็บไว้ก่อนหน้านี้ที่อยู่นี้โดยสัญญาว่าการโหลดในภายหลังที่ที่อยู่เดียวกันจะให้ค่าที่เก็บไว้ล่าสุด แต่แม้ RAM จะมีที่อยู่ไม่กี่ที่ที่ไม่ทำงานเช่นนี้ แต่ก็มีรีจิสเตอร์บางตัวที่สามารถควบคุมสิ่งต่าง ๆ เช่นอัตราการรีเฟรชและแรงดันไฟฟ้า
โดยทั่วไปการอ่านหรือเขียนลงทะเบียนฮาร์ดแวร์จะทำสิ่งที่ฮาร์ดแวร์ถูกตั้งโปรแกรมให้ทำ การเข้าถึงฮาร์ดแวร์ส่วนใหญ่ทำงานด้วยวิธีนี้: ซอฟต์แวร์ (ปกติรหัสเคอร์เนล) เข้าถึงที่อยู่ทางกายภาพที่แน่นอนไปถึงรถบัสที่เชื่อมต่อโปรเซสเซอร์กับอุปกรณ์ต่อพ่วงและอุปกรณ์ต่อพ่วงทำหน้าที่ของมัน โปรเซสเซอร์บางตัว (โดยเฉพาะอย่างยิ่ง x86) มีคำสั่ง CPU แยกต่างหากซึ่งทำให้การอ่าน / เขียนไปยังอุปกรณ์ต่อพ่วงซึ่งแตกต่างจากหน่วยความจำโหลดและที่จัดเก็บ แต่แม้กระทั่งบน x86 อุปกรณ์ต่อพ่วงมากมายถึงโหลด / เก็บ
คำสั่งdd if=/dev/urandom of=/dev/mem
เขียนข้อมูลแบบสุ่มไปยังอุปกรณ์ต่อพ่วงใด ๆ ที่ถูกแมปที่ที่อยู่ 0 (และที่อยู่ที่ตามมาตราบใดที่การเขียนสำเร็จ) ในทางปฏิบัติฉันคาดหวังว่าในสถาปัตยกรรมจำนวนมากที่อยู่จริง 0 ไม่ได้ต่อพ่วงใด ๆ กับมันหรือมี RAM ดังนั้นความพยายามในการเขียนครั้งแรกจึงล้มเหลว แต่ถ้ามีการต่อพ่วงอุปกรณ์ต่อพ่วงที่ที่อยู่ 0 หรือถ้าคุณเปลี่ยนคำสั่งเพื่อเขียนไปยังที่อยู่อื่นคุณจะเรียกสิ่งที่ไม่สามารถคาดเดาได้ในอุปกรณ์ต่อพ่วง ด้วยข้อมูลแบบสุ่มที่เพิ่มที่อยู่จึงไม่น่าทำสิ่งที่น่าสนใจ แต่โดยหลักการแล้วมันสามารถปิดคอมพิวเตอร์ได้ (อาจมีที่อยู่ที่ใช้ทำสิ่งนี้) เขียนทับการตั้งค่า BIOS บางอย่างที่ทำให้ไม่สามารถบูตได้ อุปกรณ์ต่อพ่วง buggy ในลักษณะที่เสียหายมัน
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
CONFIG_STRICT_DEVMEM
เปิดใช้งาน
ต่อหน่วยความจำหน้าคู่มือ(4) :
/ dev / mem เป็นไฟล์อุปกรณ์อักขระที่เป็นรูปภาพของหน่วยความจำหลักของคอมพิวเตอร์ มันอาจถูกนำมาใช้เพื่อตรวจสอบ (และแม้กระทั่งการแก้ไข) ระบบ
ดังนั้นในทางทฤษฎีdd if=/dev/urandom of=/dev/mem
ควรเขียนทับพื้นที่แอดเดรสทั้งหมดของหน่วยความจำกายภาพที่คุณติดตั้งและเนื่องจากเคอร์เนลและโปรแกรมอื่น ๆ ที่เรียกใช้จากหน่วยความจำจึงควรทำให้ระบบขัดข้องอย่างมีประสิทธิภาพ ในทางปฏิบัติมีข้อ จำกัด จากหน้าคนเดียวกัน:
เนื่องจาก Linux 2.6.26 และขึ้นอยู่กับสถาปัตยกรรมตัวเลือกการกำหนดค่าเคอร์เนล CONFIG_STRICT_DEVMEM จำกัด พื้นที่ที่สามารถเข้าถึงได้ผ่านไฟล์นี้
ลองสิ่งนี้บนเครื่องเสมือน Ubuntu 18.04 มันจะส่งคืนข้อผิดพลาดdd: writing to '/dev/mem': Operation not permitted
แม้จะมีsudo
และแม้จะมีสิทธิ์ใช้งานสำหรับรูcrw-r-----
ท จากUbuntu Wiki :
การป้องกัน / dev / mem
แอปพลิเคชั่นบางตัว (Xorg) จำเป็นต้องเข้าถึงหน่วยความจำกายภาพโดยตรงจากพื้นที่ผู้ใช้ มีไฟล์ / dev / mem พิเศษอยู่เพื่อให้การเข้าถึงนี้ ในอดีตเป็นไปได้ที่จะดูและเปลี่ยนหน่วยความจำเคอร์เนลจากไฟล์นี้หากผู้โจมตีมีการเข้าถึงรูท ตัวเลือกเคอร์เนล CONFIG_STRICT_DEVMEM ถูกนำมาใช้เพื่อบล็อกการเข้าถึงหน่วยความจำที่ไม่ใช่อุปกรณ์ (แต่เดิมชื่อ CONFIG_NONPROMISC_DEVMEM)
ดังนั้นในทางเทคนิคแล้วมันไม่ปลอดภัย (เพราะมันจะทำให้ระบบล่ม) และหากตัวเลือกเคอร์เนลCONFIG_STRICT_DEVMEM
ถูกปิดใช้งานนั่นคือช่องโหว่ความปลอดภัย แต่จากสิ่งที่ฉันเห็นจนถึงตอนนี้คำสั่งจะไม่ทำงานหากเปิดใช้งานตัวเลือกนั้น ตามการข้ามไซต์ซ้ำการรีบูตจะแก้ไขปัญหาใด ๆ กับมัน แต่แน่นอนว่าข้อมูลใน RAM ในเวลานั้นจะหายไปและไม่ถูกฟลัชลงดิสก์ (ถ้ามี)
มีวิธีที่แนะนำในการทำสำเนาลิงก์ที่ใช้ก่อนหน้านี้busybox devmem
ดังนั้นหากคุณตั้งใจจะยุ่งกับ RAM อาจมีวิธีหลังจากทั้งหมด
CONFIG_STRICT_DEVMEM
/dev/mem
หากคุณเขียนข้อมูลแบบสุ่มไปยังอุปกรณ์ต่อพ่วงอาจมีอะไรเกิดขึ้น คุณได้รับ“ การดำเนินการที่ไม่ได้รับอนุญาต” หากคุณพยายามเข้าถึงที่อยู่ที่ไม่ได้ถูกแมปและคำสั่งจะเริ่มต้นที่ที่อยู่ 0 ไม่ว่าที่อยู่ 0 จะแมปสิ่งที่ไม่ดีขึ้นอยู่กับสถาปัตยกรรมฮาร์ดแวร์ ฉันรู้ว่ามันอาจไม่เคยแมปกับสิ่งใดบนพีซี แต่โดยทั่วไปจะไม่ปลอดภัย
head -c 1024 </dev/mem | od -tx1
) แต่ฉันไม่รู้ว่าสิ่งเหล่านี้ถูกใช้เมื่อตัวประมวลผลไม่ได้อยู่ในโหมดจริง (โหมด 8088) ฉันไม่คิดว่าจะสามารถใช้งานได้ในโหมด 64 บิต: หลังจากทั้งหมดเวกเตอร์ขัดจังหวะ 8088 มี 32 บิตสำหรับที่อยู่เท่านั้น และโดยวิธีการนี้สามารถเข้าถึงได้ด้วยCONFIG_STRICT_DEVMEM
ชุดดังนั้นฉันคิดว่า Linux ไม่ได้ใช้มัน