การเย็บเป็นเครื่องมือการวิเคราะห์ to-to-order-order-order (สำหรับ c) ตาม LLVM IR และสร้างขึ้นบน Dr. Checker (ขอบคุณผู้สร้าง!) สองไฮไลท์คือ:
เราตั้งชื่อมันเย็บด้วยความหวังว่ามันสามารถผ่าตัดได้อย่างแม่นยำในขณะที่สามารถเย็บฟังก์ชั่น syscalls/รายการหลายรายการเข้าด้วยกันเพื่อสร้างกระแสข้อมูลลำดับสูง สำหรับรายละเอียดเพิ่มเติมโปรดดูที่บทความของเรา: การค้นพบช่องโหว่แบบ Taint Style ลำดับสูงแบบคงที่ในเมล็ด OS ใน ACM CCS'21
โคลนครั้งแรก repo:
~$ git clone https://github.com/seclab-ucr/SUTURE.git suture
จากนั้นตั้งค่าสภาพแวดล้อม LLVM สำหรับการเย็บ:
~$ cd suture
~/suture$ python setup_suture.py -o ../suture_deps
ตัวเลือก (สำหรับ setup_suture.py ):
-b ระบุชื่อสาขาของ LLVM ที่จะตั้งค่าสำหรับการเย็บมันเป็นค่าเริ่มต้นเป็น "release_90" (เช่น LLVM 9.0) ใน LLVM Mirror Repo นี้-o ระบุโฟลเดอร์เพื่อโฮสต์สิ่งของทั้งหมดที่ต้องการโดยการเย็บ (เช่น LLVM) ใช้โฟลเดอร์ใด ๆ ที่คุณต้องการ การตั้งค่า LLVM อาจใช้เวลาพอสมควร หลังจากเสร็จสิ้นไฟล์ srcipt ชื่อ env.sh จะถูกสร้างขึ้นภายใต้โฟลเดอร์รูทเย็บมันมีคำสั่งเพื่อตั้งค่าตัวแปรสภาพแวดล้อมที่ใช้โดยรอยประสาน
สำคัญ : ตรวจสอบให้แน่ใจว่าได้เปิดใช้งาน env.sh นี้ทุกครั้งก่อนที่จะสร้าง/ใช้รอยประสาน (คุณสามารถเพิ่มคำสั่งที่มีอยู่ใน . bashrc สำหรับการเปิดใช้งานอัตโนมัติเมื่อเข้าสู่ระบบเชลล์)!
~/suture$ source env.sh
ต่อไปเราจะสร้างรอยประสาน:
~/suture$ cd llvm_analysis
~/suture/llvm_analysis$ ./build.sh
เมื่อสร้างที่ประสบความสำเร็จการเย็บพร้อมใช้งาน
การเย็บสามารถใช้เพื่อค้นหาช่องโหว่ที่มีการสั่งซื้อระดับสูงออกนอกกรอบในส่วนนี้เราเดินผ่านกระบวนการนี้โดยมีตัวอย่าง (เช่นตัวอย่างแรงจูงใจดังแสดงในส่วนที่ 2.1 ในบทความของเรา)
ในการค้นหาช่องโหว่การเย็บต้องใช้อินพุตสองประเภท: (1) โมดูลโปรแกรมที่รวบรวมไว้ใน LLVM BitCode (เช่นไฟล์ . BC ) และ (2) ไฟล์การกำหนดค่าสำหรับโมดูลที่แสดงฟังก์ชั่นรายการและอาร์กิวเมนต์ที่ควบคุมโดยผู้ใช้
ก่อนอื่นให้เตรียม BitCode LLVM สำหรับตัวอย่างแรงจูงใจของเรา:
~/suture$ cd benchmark
~/suture/benchmark$ ./gen.sh motivating_example
หมายเหตุ : เพื่อความสะดวกเราให้ gen.sh รวบรวม A.C ถึง . BC และ . LL (BitCode LLVM ที่อ่านได้ของมนุษย์) ด้วยระดับการเพิ่มประสิทธิภาพ -O1
ตอนนี้เราควรมี motivating_example.bc ภายใต้โฟลเดอร์ เกณฑ์มาตรฐาน เดียวกันนั่นคือโมดูลโปรแกรมอินพุตสำหรับการเย็บ
จากนั้นมาถึงไฟล์การกำหนดค่าเราได้เตรียมไว้แล้วสำหรับตัวอย่างที่สร้างแรงบันดาลใจ:
~/suture/benchmark$ cat conf_motivating_example
entry0 MY_IOCTL 1
entry1 NULL_ARG
entry2 NULL_ARG
คำอธิบาย : แต่ละบรรทัดในไฟล์กำหนดค่าอธิบายข้อมูลของฟังก์ชั่นหนึ่งรายการ (เช่นฟังก์ชั่นระดับบนสุดที่ไม่มีผู้โทรและมักจะทำหน้าที่เป็นอินเทอร์เฟซภายนอก) ในโมดูลโปรแกรมมันมีโทเค็นแยกอวกาศได้สูงสุด 3 รายการ:
entry_x MY_IOCTL 0_2ดังนั้นดังที่แสดงไว้ข้างต้น conf_motivating_example ระบุว่ามีฟังก์ชั่นรายการสามรายการใน Motivating_example.c : รายการ 0 (พารามิเตอร์ 1 คือการควบคุมผู้ใช้), entry1 และ entry2 (ไม่มีพารามิเตอร์ที่ผู้ใช้ควบคุม) สิ่งนี้ตรงกับรหัสของตัวอย่างที่สร้างแรงบันดาลใจ
เมื่อโปรแกรม BitCode และไฟล์กำหนดค่ารายการพร้อมแล้วเราสามารถรันรอยประสานเพื่อค้นหาช่องโหว่ Taint:
~/suture$ ./run_nohup.sh benchmark/motivating_example.bc benchmark/conf_motivating_example
คำอธิบาย : run_nohup.sh เป็นสคริปต์ง่ายๆที่เรียกใช้การวิเคราะห์ LLVM ที่รวบรวมผ่านการเย็บแผล:
~/suture$ ./run_nohup.sh [path/to/program.bc] [path/to/entry_func_config]
เมื่อเริ่มต้นขึ้นอยู่กับฮาร์ดแวร์ที่แท้จริงและความซับซ้อนของโปรแกรมเป้าหมายเวลาที่จำเป็นสำหรับการเย็บแผลในการวิเคราะห์และการค้นพบช่องโหว่จะแตกต่างกันมาก โปรแกรมง่ายๆเช่นตัวอย่างแรงจูงใจของเรามักจะเสร็จสิ้นทันที
ตัดสินใจว่าการวิเคราะห์เสร็จสิ้นหรือไม่ : ในระหว่างการดำเนินการเย็บจะทำการบันทึกลงในไฟล์ภายใต้ไดเรกทอรีเดียวกันของ ไฟล์กำหนดค่ารายการ สมมติว่าเส้นทางไฟล์กำหนดค่าคือ /path/to/conf_program ไฟล์บันทึกจะเป็น /path/to/conf_program.log เราสามารถตัดสินใจได้ว่าการวิเคราะห์เสร็จสิ้นโดยการตรวจสอบบันทึก:
~/suture$ grep "Bug Detection Phase finished" benchmark/conf_motivating_example.log
ไฟล์บันทึกดังกล่าวยังเป็นเอาท์พุทของรอยประสานเย็บจะฝังช่องโหว่ที่อาจเกิดขึ้นในไฟล์บันทึกซึ่งสามารถสกัดและจัดระเบียบลงในรายงานการเตือนครั้งสุดท้ายหลังจากการวิเคราะห์เสร็จสิ้น: เสร็จสิ้น
~/suture$ ./ext_warns.sh benchmark/conf_motivating_example.log
คำอธิบาย : ext_warns.sh จะแยกคำเตือนทั้งหมด (ใน JSON) ฝังอยู่ในไฟล์บันทึกที่กำหนดจัดระเบียบใหม่และพิมพ์พวกเขาลงในรายงานคำเตือนสุดท้าย รายงานการเตือนจะถูกใส่ลงในโฟลเดอร์ภายใต้เส้นทางเดียวกันของไฟล์บันทึกสมมติว่าไฟล์บันทึกคือ /path/to/conf_program.log โฟลเดอร์รายงานคำเตือนจะเป็น /path/to/warns-conf_program-yyyy-mm-dd
~/suture$ ls benchmark/warns-conf_motivating_example-2021-11-10/
all int_overflow taint_data_use taint_loopbound taint_ptr_def
ในโฟลเดอร์มีรายงานเตือน 5 รายงาน ทั้งหมด มีคำเตือนทุกประเภทที่จัดกลุ่มเข้าด้วยกันตามความสัมพันธ์ของข้อมูลการไหลของข้อมูลในขณะที่รายงานอื่น ๆ มีเพียงประเภทของคำเตือน (เช่นจำนวนเต็มล้น, ตัวชี้ที่เสียไป ฯลฯ ) รายละเอียดเพิ่มเติมเกี่ยวกับวิธีการเตือนกลุ่มเราสามารถพบได้ในกระดาษของเรา (มาตรา 4) เรามักจะใช้รายงานรวม ทั้งหมด เท่านั้น
~/suture$ cat -n benchmark/warns-conf_motivating_example-2021-11-10/all
1 =========================GROUP 0 (2 - 2)=========================
2 #####Warned Insts#####
3 (u'motivating_example.c', 30, [u'IntegerOverflowDetector'])
4 ######################
5
6 ++++++++++++++++WARN 0 (2 - 2)++++++++++++++++
7 IntegerOverflowDetector says: motivating_example.c@30 (bar : %add = add i8 %0, -16, !dbg !31)
8 ********Trace 0(2)********
9 #####CTX##### entry0
10 entry0 (motivating_example.c@18)
11 #####INSTS#####
12 >>>>>>>>>>>>>>>>>>tag: 0x55b206570420 tf: 0x55b20695b1b0 (2)>>>>>>>>>>>>>>>>>>
13 motivating_example.c@18 ( %cond = icmp eq i32 %cmd, 0, !dbg !31)
14 motivating_example.c@21 ( store i8 %user_input, i8* getelementptr inbounds (%struct.data, %struct.data* @d, i64 0, i32 1, i64 0), align 4, !dbg !32, !tbaa !34)
15 #####CTX##### entry1 -> bar
16 entry1 (motivating_example.c@35)
17 ----> (motivating_example.c@35 : %call = tail call i32 @bar(i8* bitcast (%struct.data* @d to i8*)), !dbg !27)
18 bar (motivating_example.c@30)
19 #####INSTS#####
20 >>>>>>>>>>>>>>>>>>tag: 0x55b2065e7050 tf: 0x55b2068174f0 (1)>>>>>>>>>>>>>>>>>>
21 motivating_example.c@30 ( %0 = load i8, i8* %add.ptr, align 1, !dbg !31, !tbaa !32)
22 motivating_example.c@30 ( %add = add i8 %0, -16, !dbg !31)
23
คำอธิบาย : ในระดับสูงรายงานคำเตือนมี กลุ่ม เตือนบางกลุ่มแต่ละกลุ่มมี คำเตือน หลายครั้งและคำเตือนแต่ละครั้งมี ร่องรอย ที่น่าเบื่อหลายอย่างที่มาจากอินพุตของผู้ใช้และจมลงในคำสั่งโปรแกรมที่ละเอียดอ่อนเดียวกัน กล่าวอีกนัยหนึ่ง คำเตือน หนึ่งครั้งจะถูกยกขึ้นสำหรับคำสั่งโปรแกรมบางอย่างและประเภทที่เฉพาะเจาะจง (เช่นจำนวนเต็มล้น) ในขณะที่ กลุ่ม มีคำเตือนที่เกี่ยวข้องอย่างใกล้ชิดหลายครั้งจากมุมมองการไหลของข้อมูล (ดูส่วนที่ 4 ในบทความของเรา) ดังนั้น กลุ่ม อาจมีคำสั่งโปรแกรมเตือนหลายรายการและรวมถึงประเภทการเตือนที่แตกต่างกัน
ใช้รายงานคำเตือนข้างต้นเป็นตัวอย่าง:
===GROUP No. (min_order - max_order)=== max_order ที่ min_order เป็นลำดับขั้นต่ำ (เช่นเพียงแค่ใส่ คำสั่ง คือเวลาของการเรียกใช้ฟังก์ชั่นการป้อนข้อมูลที่จำเป็นในการแพร่กระจาย taintWARN No. นั้นเป็นของท้องถิ่น***Trace No. (order)*** การติดตาม Taint มักจะมี คำสั่ง ที่ไม่ซ้ำกันที่สามารถคำนวณได้ (เช่นไม่ใช่ช่วง)รายงานคำเตือนระบุช่องโหว่จำนวนเต็มจำนวนเต็มที่ถูกต้องในตัวอย่างที่สร้างแรงบันดาลใจในขณะที่หลีกเลี่ยงการเตือนที่ผิดพลาดที่อาจเกิดขึ้นได้ว่าเครื่องมือการวิเคราะห์แบบคงที่ที่แม่นยำน้อยกว่าอาจสร้างรายละเอียดได้ในส่วนที่ 2.1 ของบทความของเรา
repo นี้ยังมีเครื่องมือ/สคริปต์อื่น ๆ ที่คุณอาจพบว่ามีประโยชน์
~/suture$ python llvm_analysis/AnalysisHelpers/EntryPointIdentifier/entry_point_identifier.py /path/to/prog_module.bc
~/suture$ cat /path/to/prog_module.bc.all_entries
คำอธิบาย : สคริปต์นี้สามารถระบุฟังก์ชั่นรายการทั่วไปบางอย่างในโมดูลไดรเวอร์อุปกรณ์ Linux (เช่น IOCTL () , อ่าน () , เขียน () , ฯลฯ ) ซึ่งช่วยในการสร้างไฟล์กำหนดค่ารายการเป็นอินพุตไปยังรอยประสาน ยูทิลิตี้นี้ส่วนใหญ่จะถูกนำไปใช้โดยดร. Checker ดั้งเดิมตามความรู้ของเคอร์เนลบางอย่าง (เช่นโครงสร้างข้อมูลเฉพาะเช่น file_operations ที่ใช้ในการกำหนดจุดป้อนไดรเวอร์) จากนั้นเราทำการปรับปรุงบางอย่าง (เช่นทำให้ฮิวริสติกมีความแข็งแกร่งมากขึ้น)
~/suture$ python flt_warns.py /path/to/warn_report [Regex] > /path/to/filtered_warn_report
คำอธิบาย : จากประสบการณ์ของเราการเตือนที่ผิดพลาดจำนวนมากในรายงานการเตือนมักจะแบ่งปันการติดตามย่อยที่มีปัญหาเดียวกัน (ดูหัวข้อ 6.3 ในบทความของเรา) ตราบใดที่ผู้ตรวจสอบคำเตือนตรวจสอบการเตือนที่ผิดพลาดหนึ่งครั้งและรับรู้ถึงการตรวจสอบย่อย FP ที่เกิดขึ้นตามธรรมชาติเธอสามารถพยายามแยกสัญญาณเตือนปลอมอื่น ๆ ที่คล้ายกันทั้งหมดที่มีการตรวจสอบย่อยเดียวกันโดยอัตโนมัติลดอัตราการเตือนที่ผิดพลาดของผู้ตรวจสอบ เพื่อจุดประสงค์นี้เราให้ Flt_warns.py ง่าย ๆ นี้ที่ใช้รายงานการเตือนเดิมและการแสดงออกปกติของ Python เป็นอินพุตจากนั้นจะจับคู่ใหม่กับการติดตาม Taint ทุกครั้งในรายงานเมื่อจับคู่การติดตาม Taint จะได้รับการแจ้งเตือนที่ผิดพลาด สคริปต์จะสร้างรายงานคำเตือนที่ผ่านการกรองใหม่ซึ่งไม่รวมร่องรอยที่มีการจับคู่ทั้งหมด
คุณอาจสนใจที่จะใช้การเย็บแผลเป็นการวิเคราะห์แบบคงที่โดยทั่วไป (เช่นรับชุดจุดต่อ/taint ของตัวแปรที่ตำแหน่งโปรแกรมบางแห่ง) นี่เป็นสิ่งที่ทำได้แน่นอน แต่แตกต่างจากการค้นพบช่องโหว่คุณต้องทำให้มือสกปรก ฉันหวังว่าเคล็ดลับต่อไปนี้จะช่วยได้:
LLVM วิวัฒนาการอย่างรวดเร็วโดยไม่มีการรับประกันความเข้ากันได้ย้อนหลัง มีโอกาสมากที่คุณจะพบข้อผิดพลาดในการรวบรวมบางอย่างเมื่อพยายามสร้างรอยประสานกับเวอร์ชัน LLVM รุ่นใหม่ (เช่น> 9.0) แต่โชคดีที่ข้อผิดพลาดในการรวบรวมดังกล่าวมักจะแก้ไขได้ง่าย (เช่นบ่อยครั้งที่เราต้องเปลี่ยน API LLVM ที่ล้าสมัยด้วยสิ่งที่ใหม่กว่า) ดังนั้นโดยทั่วไปในการปรับรอยเย็บเข้ากับเวอร์ชัน LLVM รุ่นใหม่ก่อนอื่นเราต้องตั้งค่า LLVM ที่ใหม่กว่าใน 0x0 (เช่นจำเป็นต้องปรับเปลี่ยน setup_suture.py เพื่อโคลน LLVM repo จากแหล่งที่ใช้งานและระบุชื่อสาขาที่ใหม่กว่า) แล้วลองสร้างเย็บแผล