Python Digital Forensics - คู่มือฉบับย่อ
บทนี้จะให้ข้อมูลเบื้องต้นเกี่ยวกับสิ่งที่นิติดิจิทัลเป็นข้อมูลเกี่ยวกับและการทบทวนประวัติศาสตร์ นอกจากนี้คุณยังจะเข้าใจว่าคุณสามารถประยุกต์ใช้นิติวิทยาศาสตร์ดิจิทัลในชีวิตจริงและข้อ จำกัด ได้จากที่ใด
Digital Forensics คืออะไร?
นิติดิจิทัลอาจถูกกำหนดให้เป็นสาขาของนิติวิทยาศาสตร์ที่วิเคราะห์ตรวจสอบระบุและกู้คืนหลักฐานดิจิทัลที่อยู่ในอุปกรณ์อิเล็กทรอนิกส์ มักใช้สำหรับกฎหมายอาญาและการสืบสวนส่วนตัว
ตัวอย่างเช่นคุณสามารถใช้หลักฐานทางนิติวิทยาศาสตร์ดิจิทัลในกรณีที่มีคนขโมยข้อมูลบางอย่างในอุปกรณ์อิเล็กทรอนิกส์
การทบทวนทางประวัติศาสตร์โดยย่อของนิติดิจิทัล
ประวัติความเป็นมาของอาชญากรรมคอมพิวเตอร์และการทบทวนทางนิติวิทยาศาสตร์ในอดีตมีอธิบายไว้ในส่วนนี้ตามที่ระบุด้านล่าง -
1970-1980: อาชญากรรมคอมพิวเตอร์ครั้งแรก
ก่อนหน้านี้ทศวรรษที่ผ่านมาไม่มีการยอมรับอาชญากรรมคอมพิวเตอร์ อย่างไรก็ตามหากมันควรจะเกิดขึ้นกฎหมายที่มีอยู่จะจัดการกับพวกเขา ต่อมาในปี 1978 อาชญากรรมคอมพิวเตอร์ครั้งแรกได้รับการยอมรับใน Florida Computer Crime Act ซึ่งรวมถึงการออกกฎหมายต่อต้านการแก้ไขหรือลบข้อมูลในระบบคอมพิวเตอร์โดยไม่ได้รับอนุญาต แต่เมื่อเวลาผ่านไปเนื่องจากความก้าวหน้าของเทคโนโลยีการก่ออาชญากรรมทางคอมพิวเตอร์ก็เพิ่มขึ้นด้วย ในการจัดการกับอาชญากรรมที่เกี่ยวข้องกับลิขสิทธิ์ความเป็นส่วนตัวและภาพอนาจารของเด็กได้มีการผ่านกฎหมายอื่น ๆ
ทศวรรษที่ 1980-1990: ทศวรรษแห่งการพัฒนา
ทศวรรษนี้เป็นทศวรรษแห่งการพัฒนานิติวิทยาศาสตร์ดิจิทัลทั้งหมดนี้เป็นเพราะการสืบสวนครั้งแรก (1986) ที่ Cliff Stoll ติดตามแฮกเกอร์ชื่อ Markus Hess ในช่วงเวลานี้สาขาวิชานิติวิทยาศาสตร์ดิจิทัลสองประเภทได้รับการพัฒนาโดยประการแรกเกิดจากความช่วยเหลือของเครื่องมือและเทคนิคเฉพาะกิจที่พัฒนาโดยผู้ปฏิบัติงานซึ่งถือเป็นงานอดิเรกในขณะที่กลุ่มที่สองได้รับการพัฒนาโดยชุมชนวิทยาศาสตร์ ในปีพ. ศ“Computer Forensics”ถูกใช้ในวรรณคดีวิชาการ
2000s-2010s: ทศวรรษแห่งการมาตรฐาน
หลังจากการพัฒนานิติวิทยาศาสตร์ดิจิทัลไปถึงระดับหนึ่งแล้วจำเป็นต้องมีการสร้างมาตรฐานเฉพาะบางอย่างที่สามารถปฏิบัติตามได้ในขณะที่ทำการสอบสวน ดังนั้นหน่วยงานและหน่วยงานทางวิทยาศาสตร์หลายแห่งจึงได้เผยแพร่แนวทางสำหรับนิติวิทยาศาสตร์ดิจิทัล ในปี 2545 คณะทำงานทางวิทยาศาสตร์เกี่ยวกับหลักฐานดิจิทัล (SWGDE) ได้ตีพิมพ์บทความชื่อ“ แนวทางปฏิบัติที่ดีที่สุดสำหรับนิติคอมพิวเตอร์” ขนนกอีกอันในหมวกคือสนธิสัญญาระหว่างประเทศที่นำโดยยุโรปคือ“The Convention on Cybercrime”ลงนามโดย 43 ประเทศและให้สัตยาบันโดย 16 ประเทศ แม้ว่าจะผ่านมาตรฐานดังกล่าวแล้ว แต่ก็ยังมีความจำเป็นที่จะต้องแก้ไขปัญหาบางอย่างที่นักวิจัยระบุไว้
กระบวนการนิติวิทยาศาสตร์ดิจิทัล
นับตั้งแต่เกิดอาชญากรรมคอมพิวเตอร์ครั้งแรกในปี พ.ศ. 2521 มีกิจกรรมอาชญากรรมดิจิทัลเพิ่มขึ้นอย่างมาก เนื่องจากการเพิ่มขึ้นนี้มีความจำเป็นที่จะต้องมีโครงสร้างที่ดีในการจัดการกับสิ่งเหล่านี้ ในปีพ. ศ. 2527 ได้มีการนำกระบวนการที่เป็นทางการมาใช้และหลังจากนั้นได้มีการพัฒนากระบวนการตรวจสอบทางนิติวิทยาศาสตร์คอมพิวเตอร์ใหม่ ๆ และปรับปรุงใหม่จำนวนมาก
กระบวนการตรวจสอบทางนิติคอมพิวเตอร์เกี่ยวข้องกับสามขั้นตอนหลักดังที่อธิบายไว้ด้านล่าง -
ระยะที่ 1: การได้มาหรือการสร้างภาพของการจัดแสดง
ระยะแรกของการพิสูจน์หลักฐานดิจิทัลเกี่ยวข้องกับการบันทึกสถานะของระบบดิจิทัลเพื่อให้สามารถวิเคราะห์ได้ในภายหลัง คล้ายกับการถ่ายรูปตัวอย่างเลือด ฯลฯ จากสถานที่เกิดเหตุเป็นอย่างมาก ตัวอย่างเช่นเกี่ยวข้องกับการจับภาพของพื้นที่ที่จัดสรรและไม่ได้จัดสรรของฮาร์ดดิสก์หรือ RAM
ระยะที่ 2: การวิเคราะห์
อินพุตของเฟสนี้คือข้อมูลที่ได้มาจากขั้นตอนการได้มา ที่นี่ข้อมูลนี้ได้รับการตรวจสอบเพื่อระบุหลักฐาน ระยะนี้ให้หลักฐานสามประเภทดังนี้ -
Inculpatory evidences - หลักฐานเหล่านี้สนับสนุนประวัติศาสตร์ที่กำหนด
Exculpatory evidences - หลักฐานเหล่านี้ขัดแย้งกับประวัติศาสตร์ที่กำหนด
Evidence of tampering- หลักฐานเหล่านี้แสดงให้เห็นว่าระบบมีอารมณ์เพื่อหลีกเลี่ยงการระบุตัวตน รวมถึงการตรวจสอบไฟล์และเนื้อหาไดเร็กทอรีสำหรับการกู้คืนไฟล์ที่ถูกลบ
ระยะที่ 3: การนำเสนอหรือการรายงาน
ตามชื่อที่แนะนำระยะนี้จะนำเสนอข้อสรุปและหลักฐานที่เกี่ยวข้องจากการสอบสวน
การประยุกต์ใช้นิติดิจิทัล
นิติวิทยาศาสตร์ดิจิทัลเกี่ยวข้องกับการรวบรวมวิเคราะห์และรักษาหลักฐานที่มีอยู่ในอุปกรณ์ดิจิทัลใด ๆ การใช้นิติดิจิทัลขึ้นอยู่กับแอปพลิเคชัน ดังที่ได้กล่าวไว้ก่อนหน้านี้ส่วนใหญ่จะใช้ในสองแอพพลิเคชั่นต่อไปนี้ -
กฎหมายอาญา
ในกฎหมายอาญามีการรวบรวมพยานหลักฐานเพื่อสนับสนุนหรือคัดค้านสมมติฐานในศาล ขั้นตอนทางนิติวิทยาศาสตร์คล้ายกับที่ใช้ในการสืบสวนคดีอาชญากรรมมาก แต่มีข้อกำหนดและข้อ จำกัด ทางกฎหมายที่แตกต่างกัน
การสืบสวนส่วนตัว
โลกขององค์กรส่วนใหญ่ใช้นิติดิจิทัลสำหรับการสอบสวนส่วนตัว ใช้เมื่อ บริษัท ต่างๆสงสัยว่าพนักงานอาจทำกิจกรรมที่ผิดกฎหมายบนคอมพิวเตอร์ที่ขัดต่อนโยบายของ บริษัท นิติวิทยาศาสตร์ดิจิทัลเป็นหนึ่งในเส้นทางที่ดีที่สุดสำหรับ บริษัท หรือบุคคลที่จะดำเนินการเมื่อตรวจสอบบุคคลเกี่ยวกับการประพฤติมิชอบทางดิจิทัล
สาขานิติวิทยาศาสตร์ดิจิทัล
อาชญากรรมดิจิทัลไม่ได้ จำกัด อยู่ที่คอมพิวเตอร์เพียงอย่างเดียวอย่างไรก็ตามแฮกเกอร์และอาชญากรต่างก็ใช้อุปกรณ์ดิจิทัลขนาดเล็กเช่นแท็บเล็ตสมาร์ทโฟน ฯลฯ ในระดับที่ใหญ่มากเช่นกัน อุปกรณ์บางอย่างมีหน่วยความจำแบบระเหยในขณะที่อุปกรณ์อื่น ๆ มีหน่วยความจำแบบไม่ลบเลือน ดังนั้นขึ้นอยู่กับประเภทของอุปกรณ์นิติดิจิทัลมีสาขาดังต่อไปนี้ -
นิติคอมพิวเตอร์
สาขานิติวิทยาศาสตร์ดิจิทัลนี้เกี่ยวข้องกับคอมพิวเตอร์ระบบฝังตัวและหน่วยความจำแบบคงที่เช่นไดรฟ์ USB ข้อมูลหลากหลายตั้งแต่บันทึกไปจนถึงไฟล์จริงในไดรฟ์สามารถตรวจสอบได้ในนิติคอมพิวเตอร์
นิติมือถือ
ซึ่งเกี่ยวข้องกับการตรวจสอบข้อมูลจากอุปกรณ์เคลื่อนที่ สาขานี้แตกต่างจากนิติคอมพิวเตอร์ในแง่ที่ว่าอุปกรณ์พกพามีระบบการสื่อสารในตัวซึ่งมีประโยชน์ในการให้ข้อมูลที่เป็นประโยชน์เกี่ยวกับสถานที่
นิติเครือข่าย
สิ่งนี้เกี่ยวข้องกับการตรวจสอบและวิเคราะห์การรับส่งข้อมูลเครือข่ายคอมพิวเตอร์ทั้งในพื้นที่และ WAN (เครือข่ายบริเวณกว้าง) เพื่อวัตถุประสงค์ในการรวบรวมข้อมูลการรวบรวมหลักฐานหรือการตรวจจับการบุกรุก
นิติฐานข้อมูล
สาขานิติวิทยาศาสตร์ดิจิทัลนี้เกี่ยวข้องกับการศึกษาทางนิติวิทยาศาสตร์ของฐานข้อมูลและข้อมูลเมตา
ทักษะที่จำเป็นสำหรับการตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัล
ผู้ตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลช่วยในการติดตามแฮกเกอร์กู้คืนข้อมูลที่ถูกขโมยติดตามการโจมตีทางคอมพิวเตอร์กลับไปยังต้นทางและช่วยในการสืบสวนประเภทอื่น ๆ ที่เกี่ยวข้องกับคอมพิวเตอร์ ทักษะสำคัญบางประการที่จำเป็นในการเป็นผู้ตรวจสอบนิติวิทยาศาสตร์ดิจิทัลตามที่กล่าวไว้ด้านล่าง -
ความสามารถในการคิดที่โดดเด่น
ผู้ตรวจสอบนิติวิทยาศาสตร์ดิจิทัลต้องเป็นนักคิดที่โดดเด่นและควรมีความสามารถในการใช้เครื่องมือและวิธีการต่างๆในงานที่ได้รับมอบหมายเพื่อให้ได้ผลลัพธ์ เขา / เธอต้องสามารถค้นหารูปแบบที่แตกต่างกันและสร้างความสัมพันธ์ระหว่างกันได้
ทักษะทางเทคนิค
ผู้ตรวจสอบนิติวิทยาศาสตร์ดิจิทัลต้องมีทักษะทางเทคโนโลยีที่ดีเนื่องจากสาขานี้ต้องการความรู้เกี่ยวกับเครือข่ายวิธีการโต้ตอบของระบบดิจิทัล
หลงใหลใน Cyber Security
เนื่องจากสาขานิติวิทยาศาสตร์ดิจิทัลเป็นเรื่องเกี่ยวกับการแก้ปัญหาอาชญากรรมทางไซเบอร์และนี่เป็นงานที่น่าเบื่อจึงต้องการความกระตือรือร้นอย่างมากสำหรับคนที่จะมาเป็นผู้ตรวจสอบด้านนิติวิทยาศาสตร์ดิจิทัล
ความสามารถในการสื่อสาร
ทักษะการสื่อสารที่ดีเป็นสิ่งจำเป็นในการประสานงานกับทีมต่างๆและเพื่อดึงข้อมูลหรือข้อมูลที่ขาดหายไป
มีทักษะในการทำรายงาน
หลังจากการดำเนินการได้มาและการวิเคราะห์ประสบความสำเร็จผู้ตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลจะต้องกล่าวถึงผลการวิจัยทั้งหมดในรายงานขั้นสุดท้ายและการนำเสนอ ดังนั้นเขา / เธอต้องมีทักษะในการทำรายงานที่ดีและใส่ใจในรายละเอียด
ข้อ จำกัด
การตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลมีข้อ จำกัด บางประการตามที่กล่าวไว้ที่นี่
จำเป็นต้องสร้างหลักฐานที่น่าเชื่อถือ
ความพ่ายแพ้ที่สำคัญประการหนึ่งของการตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลคือผู้ตรวจสอบต้องปฏิบัติตามมาตรฐานที่จำเป็นสำหรับหลักฐานในศาลเนื่องจากข้อมูลสามารถถูกดัดแปลงได้ง่าย ในทางกลับกันผู้ตรวจสอบทางนิติวิทยาศาสตร์คอมพิวเตอร์จะต้องมีความรู้ครบถ้วนเกี่ยวกับข้อกำหนดทางกฎหมายการจัดการหลักฐานและขั้นตอนการจัดทำเอกสารเพื่อแสดงหลักฐานที่น่าเชื่อถือในศาลยุติธรรม
เครื่องมือตรวจสอบ
ประสิทธิผลของการสอบสวนทางดิจิทัลทั้งหมดขึ้นอยู่กับความเชี่ยวชาญของผู้ตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลและการเลือกเครื่องมือตรวจสอบที่เหมาะสม หากเครื่องมือที่ใช้ไม่เป็นไปตามมาตรฐานที่กำหนดในชั้นศาลผู้พิพากษาสามารถปฏิเสธพยานหลักฐานได้
ขาดความรู้ทางเทคนิคในหมู่ผู้ชม
ข้อ จำกัด อีกประการหนึ่งคือบางคนไม่คุ้นเคยกับนิติคอมพิวเตอร์ ดังนั้นหลายคนไม่เข้าใจสาขานี้ นักวิจัยต้องแน่ใจว่าได้แจ้งสิ่งที่พบกับศาลเพื่อช่วยให้ทุกคนเข้าใจผลลัพธ์
ค่าใช้จ่าย
การผลิตหลักฐานดิจิทัลและการเก็บรักษาไว้นั้นมีค่าใช้จ่ายสูงมาก ดังนั้นกระบวนการนี้อาจไม่ถูกเลือกโดยคนจำนวนมากที่ไม่สามารถจ่ายค่าใช้จ่ายได้
ในบทที่แล้วเราได้เรียนรู้พื้นฐานของนิติดิจิทัลข้อดีและข้อ จำกัด บทนี้จะทำให้คุณคุ้นเคยกับ Python ซึ่งเป็นเครื่องมือสำคัญที่เราใช้ในการตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลนี้
ทำไมต้อง Python สำหรับ Digital Forensics
Python เป็นภาษาโปรแกรมยอดนิยมและใช้เป็นเครื่องมือในการรักษาความปลอดภัยทางไซเบอร์การทดสอบการเจาะและการตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัล เมื่อคุณเลือก Python เป็นเครื่องมือสำหรับนิติวิทยาศาสตร์ดิจิทัลคุณไม่จำเป็นต้องใช้ซอฟต์แวร์ของบุคคลที่สามอื่นใดในการทำงานให้เสร็จสิ้น
คุณลักษณะเฉพาะบางประการของภาษาโปรแกรม Python ที่เหมาะสำหรับโครงการนิติวิทยาศาสตร์ดิจิทัลมีดังต่อไปนี้ -
Simplicity of Syntax - ไวยากรณ์ของ Python นั้นเรียบง่ายเมื่อเทียบกับภาษาอื่น ๆ ซึ่งทำให้ง่ายต่อการเรียนรู้และนำไปใช้กับนิติดิจิทัล
Comprehensive inbuilt modules - โมดูลในตัวที่ครอบคลุมของ Python เป็นตัวช่วยที่ดีเยี่ยมสำหรับการดำเนินการตรวจสอบทางนิติวิทยาศาสตร์แบบดิจิทัลที่สมบูรณ์
Help and Support - Python เป็นภาษาการเขียนโปรแกรมแบบโอเพนซอร์สจึงได้รับการสนับสนุนที่ดีเยี่ยมจากชุมชนของผู้พัฒนาและผู้ใช้
คุณสมบัติของ Python
Python ซึ่งเป็นภาษาสคริปต์ระดับสูงตีความโต้ตอบและเชิงวัตถุมีคุณสมบัติดังต่อไปนี้ -
Easy to Learn - Python เป็นนักพัฒนาที่เป็นมิตรและเรียนรู้ภาษาได้ง่ายเนื่องจากมีคีย์เวิร์ดน้อยกว่าและโครงสร้างที่เรียบง่ายที่สุด
Expressive and Easy to read- ภาษา Python แสดงออกได้อย่างมีธรรมชาติ ด้วยเหตุนี้รหัสจึงเป็นที่เข้าใจและอ่านได้มากขึ้น
Cross-platform Compatible - Python เป็นภาษาที่รองรับข้ามแพลตฟอร์มซึ่งหมายความว่าสามารถทำงานได้อย่างมีประสิทธิภาพบนแพลตฟอร์มต่างๆเช่น UNIX, Windows และ Macintosh
Interactive Mode Programming - เราสามารถทำการทดสอบแบบโต้ตอบและการดีบักโค้ดได้เนื่องจาก Python รองรับโหมดโต้ตอบสำหรับการเขียนโปรแกรม
Provides Various Modules and Functions - Python มีไลบรารีมาตรฐานขนาดใหญ่ซึ่งช่วยให้เราใช้ชุดโมดูลและฟังก์ชันมากมายสำหรับสคริปต์ของเรา
Supports Dynamic Type Checking - Python รองรับการตรวจสอบประเภทไดนามิกและให้ประเภทข้อมูลไดนามิกระดับสูงมาก
GUI Programming - Python รองรับการเขียนโปรแกรม GUI เพื่อพัฒนาส่วนต่อประสานผู้ใช้แบบกราฟิก
Integration with other programming languages - Python สามารถรวมเข้ากับภาษาโปรแกรมอื่น ๆ เช่น C, C ++, JAVA เป็นต้น
การติดตั้ง Python
การแจกจ่าย Python พร้อมใช้งานสำหรับแพลตฟอร์มต่างๆเช่น Windows, UNIX, Linux และ Mac เราจำเป็นต้องดาวน์โหลดรหัสไบนารีตามแพลตฟอร์มของเราเท่านั้น ในกรณีที่ไม่มีรหัสไบนารีสำหรับแพลตฟอร์มใด ๆ เราต้องมีคอมไพเลอร์ C เพื่อให้สามารถรวบรวมซอร์สโค้ดได้ด้วยตนเอง
ส่วนนี้จะทำให้คุณคุ้นเคยกับการติดตั้ง Python บนแพลตฟอร์มต่างๆ
การติดตั้ง Python บน Unix และ Linux
คุณสามารถทำตามขั้นตอนที่แสดงด้านล่างเพื่อติดตั้ง Python บนเครื่อง Unix / Linux
Step 1- เปิดเว็บเบราว์เซอร์ พิมพ์และเข้าสู่www.python.org/downloads/
Step 2 - ดาวน์โหลดซอร์สโค้ดแบบซิปสำหรับ Unix / Linux
Step 3 - แตกไฟล์ซิปที่ดาวน์โหลดมา
Step 4 - หากคุณต้องการปรับแต่งตัวเลือกบางอย่างคุณสามารถแก้ไขไฟล์ Modules/Setup file.
Step 5 - ใช้คำสั่งต่อไปนี้เพื่อทำการติดตั้งให้เสร็จสิ้น -
run ./configure script
make
make install
เมื่อคุณทำตามขั้นตอนข้างต้นสำเร็จแล้ว Python จะถูกติดตั้งที่ตำแหน่งมาตรฐาน /usr/local/bin และห้องสมุดที่ /usr/local/lib/pythonXX โดยที่ XX คือเวอร์ชันของ Python
การติดตั้ง Python บน Windows
เราสามารถทำตามขั้นตอนง่ายๆต่อไปนี้เพื่อติดตั้ง Python บนเครื่อง Windows
Step 1- เปิดเว็บเบราว์เซอร์ พิมพ์และเข้าสู่www.python.org/downloads/
Step 2 - ดาวน์โหลดตัวติดตั้ง Windows python-XYZ.msi ไฟล์โดย XYZ เป็นเวอร์ชันที่เราต้องติดตั้ง
Step 3 - ตอนนี้เรียกใช้ไฟล์ MSI นั้นหลังจากบันทึกไฟล์ตัวติดตั้งลงในเครื่องของคุณ
Step 4 - เรียกใช้ไฟล์ที่ดาวน์โหลดมาซึ่งจะแสดงวิซาร์ดการติดตั้ง Python
การติดตั้ง Python บน Macintosh
สำหรับการติดตั้ง Python 3 บน Mac OS X เราต้องใช้โปรแกรมติดตั้งแพ็คเกจชื่อ Homebrew.
คุณสามารถใช้คำสั่งต่อไปนี้เพื่อติดตั้ง Homebrew ในกรณีที่คุณไม่มีในระบบของคุณ -
$ ruby -e "$(curl -fsSL
https://raw.githubusercontent.com/Homebrew/install/master/install)"
หากคุณต้องการอัปเดตตัวจัดการแพ็คเกจคุณสามารถทำได้ด้วยความช่วยเหลือของคำสั่งต่อไปนี้ -
$ brew update
ตอนนี้ใช้คำสั่งต่อไปนี้เพื่อติดตั้ง Python3 บนระบบของคุณ -
$ brew install python3
การตั้งค่า PATH
เราจำเป็นต้องกำหนดเส้นทางสำหรับการติดตั้ง Python ซึ่งแตกต่างกับแพลตฟอร์มเช่น UNIX, WINDOWS หรือ MAC
การตั้งค่าพา ธ ที่ Unix / Linux
คุณสามารถใช้ตัวเลือกต่อไปนี้เพื่อกำหนดเส้นทางบน Unix / Linux -
If using csh shell - ประเภท setenv PATH "$PATH:/usr/local/bin/python" จากนั้นกด Enter
If using bash shell (Linux) - ประเภท export ATH="$PATH:/usr/local/bin/python" จากนั้นกด Enter
If using sh or ksh shell - ประเภท PATH="$PATH:/usr/local/bin/python" จากนั้นกด Enter
การตั้งค่าเส้นทางที่ Windows
ประเภท path %path%;C:\Python ที่พรอมต์คำสั่งจากนั้นกด Enter
กำลังรัน Python
คุณสามารถเลือกวิธีใดก็ได้จากสามวิธีต่อไปนี้เพื่อเริ่มตัวแปล Python -
วิธีที่ 1: การใช้อินเตอร์พรีเตอร์แบบโต้ตอบ
ระบบที่จัดเตรียมล่ามบรรทัดคำสั่งหรือเชลล์สามารถใช้สำหรับเริ่ม Python ได้อย่างง่ายดาย ตัวอย่างเช่น Unix, DOS เป็นต้นคุณสามารถทำตามขั้นตอนด้านล่างเพื่อเริ่มการเข้ารหัสในล่ามเชิงโต้ตอบ -
Step 1 - เข้า python ที่บรรทัดคำสั่ง
Step 2 - เริ่มเขียนโค้ดได้ทันทีในล่ามโต้ตอบโดยใช้คำสั่งที่แสดงด้านล่าง -
$python # Unix/Linux
or
python% # Unix/Linux
or
C:> python # Windows/DOS
วิธีที่ 2: การใช้สคริปต์จากบรรทัดคำสั่ง
นอกจากนี้เรายังสามารถเรียกใช้สคริปต์ Python ที่บรรทัดคำสั่งโดยเรียกใช้ล่ามในแอปพลิเคชันของเรา คุณสามารถใช้คำสั่งที่แสดงด้านล่าง -
$python script.py # Unix/Linux
or
python% script.py # Unix/Linux
or
C: >python script.py # Windows/DOS
วิธีที่ 3: สภาพแวดล้อมการพัฒนาแบบบูรณาการ
หากระบบมีแอปพลิเคชัน GUI ที่รองรับ Python สามารถเรียกใช้ Python จากสภาพแวดล้อม GUI นั้นได้ IDE บางส่วนสำหรับแพลตฟอร์มต่างๆมีให้ด้านล่าง -
Unix IDE - UNIX มี IDLE IDE สำหรับ Python
Windows IDE - Windows มี PythonWin ซึ่งเป็นอินเทอร์เฟซ Windows ตัวแรกสำหรับ Python พร้อมกับ GUI
Macintosh IDE - Macintosh มี IDLE IDE ซึ่งหาได้จากเว็บไซต์หลักดาวน์โหลดได้ทั้งไฟล์ MacBinary หรือ BinHex'd
ตอนนี้คุณพอใจกับการติดตั้งและเรียกใช้คำสั่ง Python บนระบบภายในของคุณแล้วให้เราเข้าสู่แนวคิดของนิติเวชโดยละเอียด บทนี้จะอธิบายแนวคิดต่างๆที่เกี่ยวข้องกับการจัดการกับสิ่งประดิษฐ์ใน Python digital forensics
ต้องการการสร้างรายงาน
กระบวนการของนิติดิจิทัลรวมถึงการรายงานเป็นระยะที่สาม นี่เป็นส่วนที่สำคัญที่สุดส่วนหนึ่งของกระบวนการทางนิติวิทยาศาสตร์ดิจิทัล จำเป็นต้องสร้างรายงานเนื่องจากสาเหตุต่อไปนี้ -
เป็นเอกสารที่ผู้ตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลสรุปกระบวนการสอบสวนและการค้นพบ
ผู้ตรวจสอบอีกคนสามารถอ้างอิงรายงานทางนิติวิทยาศาสตร์ดิจิทัลที่ดีเพื่อให้ได้ผลลัพธ์เดียวกันโดยใช้ที่เก็บเดียวกัน
เป็นเอกสารทางเทคนิคและทางวิทยาศาสตร์ที่มีข้อเท็จจริงที่พบภายใน 1s และ 0s ของหลักฐานดิจิทัล
หลักเกณฑ์ทั่วไปสำหรับการสร้างรายงาน
รายงานถูกเขียนขึ้นเพื่อให้ข้อมูลแก่ผู้อ่านและต้องเริ่มต้นด้วยรากฐานที่มั่นคง ผู้ตรวจสอบสามารถเผชิญกับความยากลำบากในการนำเสนอสิ่งที่ค้นพบได้อย่างมีประสิทธิภาพหากรายงานนั้นจัดทำขึ้นโดยไม่มีหลักเกณฑ์หรือมาตรฐานทั่วไป หลักเกณฑ์ทั่วไปบางประการที่ต้องปฏิบัติตามในขณะที่สร้างรายงานทางนิติวิทยาศาสตร์ดิจิทัลมีให้ด้านล่าง -
Summary - รายงานต้องมีข้อมูลสรุปสั้น ๆ เพื่อให้ผู้อ่านสามารถยืนยันวัตถุประสงค์ของรายงานได้
Tools used - เราต้องพูดถึงเครื่องมือที่ใช้ในการดำเนินกระบวนการนิติวิทยาศาสตร์ดิจิทัลรวมถึงวัตถุประสงค์
Repository - สมมติว่าเราตรวจสอบคอมพิวเตอร์ของใครบางคนจากนั้นสรุปหลักฐานและการวิเคราะห์เนื้อหาที่เกี่ยวข้องเช่นอีเมลประวัติการค้นหาภายในเป็นต้นจากนั้นจะต้องรวมไว้ในรายงานเพื่อให้สามารถนำเสนอกรณีได้อย่างชัดเจน
Recommendations for counsel - รายงานต้องมีคำแนะนำสำหรับที่ปรึกษาเพื่อดำเนินการต่อหรือยุติการสอบสวนตามผลการวิจัยในรายงาน
การสร้างรายงานประเภทต่างๆ
ในส่วนข้างต้นเรามาทำความรู้จักกับความสำคัญของรายงานในนิติวิทยาศาสตร์ดิจิทัลพร้อมกับแนวทางในการสร้างแบบเดียวกัน รูปแบบบางส่วนใน Python สำหรับการสร้างรายงานประเภทต่างๆมีการกล่าวถึงด้านล่าง -
รายงาน CSV
รูปแบบผลลัพธ์ที่พบมากที่สุดรูปแบบหนึ่งของรายงานคือรายงานสเปรดชีต CSV คุณสามารถสร้าง CSV เพื่อสร้างรายงานข้อมูลที่ประมวลผลโดยใช้โค้ด Python ดังที่แสดงด้านล่าง -
ขั้นแรกให้นำเข้าไลบรารีที่มีประโยชน์สำหรับการเขียนสเปรดชีต -
from __future__ import print_function
import csv
import os
import sys
ตอนนี้เรียกวิธีการต่อไปนี้ -
Write_csv(TEST_DATA_LIST, ["Name", "Age", "City", "Job description"], os.getcwd())
เรากำลังใช้ตัวแปรส่วนกลางต่อไปนี้เพื่อแสดงประเภทข้อมูลตัวอย่าง -
TEST_DATA_LIST = [["Ram", 32, Bhopal, Manager],
["Raman", 42, Indore, Engg.],
["Mohan", 25, Chandigarh, HR],
["Parkash", 45, Delhi, IT]]
ต่อไปให้เรากำหนดวิธีการดำเนินการสำหรับการดำเนินการต่อไป เราเปิดไฟล์ในโหมด“ w” และตั้งค่าอาร์กิวเมนต์คำหลักขึ้นบรรทัดใหม่เป็นสตริงว่าง
def Write_csv(data, header, output_directory, name = None):
if name is None:
name = "report1.csv"
print("[+] Writing {} to {}".format(name, output_directory))
with open(os.path.join(output_directory, name), "w", newline = "") as \ csvfile:
writer = csv.writer(csvfile)
writer.writerow(header)
writer.writerow(data)
หากคุณเรียกใช้สคริปต์ข้างต้นคุณจะได้รับรายละเอียดต่อไปนี้เก็บไว้ในไฟล์ report1.csv
ชื่อ | อายุ | เมือง | การกำหนด |
---|---|---|---|
แกะ | 32 | โภปาล | ผู้จัดการ |
รามัน | 42 | อินดอร์ | อังกฤษ |
โมฮัน | 25 | จั ณ ฑีครห์ | ชม |
Parkash | 45 | เดลี | มัน |
รายงาน Excel
รูปแบบผลลัพธ์ทั่วไปของรายงานอื่นคือรายงานสเปรดชีต Excel (.xlsx) เราสามารถสร้างตารางและพล็อตกราฟได้โดยใช้ Excel เราสามารถสร้างรายงานข้อมูลที่ประมวลผลในรูปแบบ Excel โดยใช้รหัส Python ดังที่แสดงด้านล่าง −
ขั้นแรกให้นำเข้าโมดูล XlsxWriter เพื่อสร้างสเปรดชีต -
import xlsxwriter
ตอนนี้สร้างวัตถุสมุดงาน สำหรับสิ่งนี้เราจำเป็นต้องใช้ตัวสร้าง Workbook ()
workbook = xlsxwriter.Workbook('report2.xlsx')
ตอนนี้สร้างแผ่นงานใหม่โดยใช้โมดูล add_worksheet ()
worksheet = workbook.add_worksheet()
จากนั้นเขียนข้อมูลต่อไปนี้ลงในแผ่นงาน -
report2 = (['Ram', 32, ‘Bhopal’],['Mohan',25, ‘Chandigarh’] ,['Parkash',45, ‘Delhi’])
row = 0
col = 0
คุณสามารถทำซ้ำข้อมูลนี้และเขียนได้ดังนี้ -
for item, cost in (a):
worksheet.write(row, col, item)
worksheet.write(row, col+1, cost)
row + = 1
ตอนนี้ให้เราปิดไฟล์ Excel นี้โดยใช้เมธอด close ()
workbook.close()
สคริปต์ด้านบนจะสร้างไฟล์ Excel ชื่อ report2.xlsx โดยมีข้อมูลต่อไปนี้ -
แกะ | 32 | โภปาล |
โมฮัน | 25 | จั ณ ฑีครห์ |
Parkash | 45 | เดลี |
สื่อการได้มาซึ่งการสืบสวน
เป็นสิ่งสำคัญสำหรับผู้ตรวจสอบที่จะต้องมีบันทึกการสืบสวนโดยละเอียดเพื่อเรียกคืนสิ่งที่ค้นพบหรือรวบรวมชิ้นส่วนของการสอบสวนทั้งหมดเข้าด้วยกัน ภาพหน้าจอมีประโยชน์มากในการติดตามขั้นตอนสำหรับการตรวจสอบโดยเฉพาะ ด้วยความช่วยเหลือของรหัส Python ต่อไปนี้เราสามารถจับภาพหน้าจอและบันทึกลงในฮาร์ดดิสก์เพื่อใช้ในอนาคต
ขั้นแรกให้ติดตั้งโมดูล Python ชื่อ pysc screenshot โดยใช้คำสั่งต่อไปนี้ -
Pip install pyscreenshot
ตอนนี้นำเข้าโมดูลที่จำเป็นดังที่แสดง -
import pyscreenshot as ImageGrab
ใช้โค้ดบรรทัดต่อไปนี้เพื่อรับภาพหน้าจอ -
image = ImageGrab.grab()
ใช้โค้ดบรรทัดต่อไปนี้เพื่อบันทึกภาพหน้าจอไปยังตำแหน่งที่กำหนด -
image.save('d:/image123.png')
ตอนนี้หากคุณต้องการแสดงภาพหน้าจอเป็นกราฟคุณสามารถใช้รหัส Python ต่อไปนี้ -
import numpy as np
import matplotlib.pyplot as plt
import pyscreenshot as ImageGrab
imageg = ImageGrab.grab()
plt.imshow(image, cmap='gray', interpolation='bilinear')
plt.show()
บทนี้จะอธิบายนิติดิจิทัลของ Python บนอุปกรณ์มือถือและแนวคิดที่เกี่ยวข้อง
บทนำ
นิติเวชอุปกรณ์เคลื่อนที่เป็นสาขาของนิติวิทยาศาสตร์ดิจิทัลที่เกี่ยวข้องกับการได้มาและการวิเคราะห์อุปกรณ์เคลื่อนที่เพื่อกู้คืนหลักฐานดิจิทัลที่น่าสนใจในการสืบสวน สาขานี้แตกต่างจากนิติคอมพิวเตอร์เนื่องจากอุปกรณ์พกพามีระบบสื่อสารในตัวซึ่งเป็นประโยชน์สำหรับการให้ข้อมูลที่เป็นประโยชน์เกี่ยวกับสถานที่ตั้ง
แม้ว่าการใช้สมาร์ทโฟนจะเพิ่มมากขึ้นในการพิสูจน์หลักฐานทางดิจิทัลในแต่ละวัน แต่ก็ยังถือว่าไม่ได้มาตรฐานเนื่องจากความแตกต่างกัน ในทางกลับกันฮาร์ดแวร์คอมพิวเตอร์เช่นฮาร์ดดิสก์ถือได้ว่าเป็นมาตรฐานและได้รับการพัฒนาให้มีระเบียบวินัยที่มั่นคงเกินไป ในอุตสาหกรรมนิติวิทยาศาสตร์ดิจิทัลมีการถกเถียงกันมากมายเกี่ยวกับเทคนิคที่ใช้กับอุปกรณ์ที่ไม่ได้มาตรฐานโดยมีหลักฐานชั่วคราวเช่นสมาร์ทโฟน
สิ่งประดิษฐ์ที่แยกได้จากอุปกรณ์พกพา
อุปกรณ์พกพาสมัยใหม่มีข้อมูลดิจิทัลจำนวนมากเมื่อเทียบกับโทรศัพท์รุ่นเก่าที่มีเพียงบันทึกการโทรหรือข้อความ SMS ดังนั้นอุปกรณ์เคลื่อนที่สามารถให้ข้อมูลเชิงลึกเกี่ยวกับผู้ใช้แก่ผู้ตรวจสอบได้ สิ่งประดิษฐ์บางอย่างที่สามารถดึงออกมาจากอุปกรณ์มือถือมีดังต่อไปนี้ -
Messages - สิ่งเหล่านี้เป็นสิ่งประดิษฐ์ที่มีประโยชน์ซึ่งสามารถเปิดเผยสภาพจิตใจของเจ้าของและยังสามารถให้ข้อมูลที่ไม่รู้จักก่อนหน้านี้แก่ผู้ตรวจสอบได้
Location History- ข้อมูลประวัติตำแหน่งเป็นสิ่งประดิษฐ์ที่มีประโยชน์ซึ่งผู้ตรวจสอบสามารถใช้เพื่อตรวจสอบความถูกต้องเกี่ยวกับตำแหน่งเฉพาะของบุคคล
Applications Installed - โดยการเข้าถึงประเภทของแอปพลิเคชันที่ติดตั้งผู้ตรวจสอบจะได้รับข้อมูลเชิงลึกเกี่ยวกับนิสัยและความคิดของผู้ใช้มือถือ
แหล่งที่มาของหลักฐานและการประมวลผลใน Python
สมาร์ทโฟนมีฐานข้อมูล SQLite และไฟล์ PLIST เป็นแหล่งหลักฐานสำคัญ ในส่วนนี้เราจะประมวลผลแหล่งที่มาของหลักฐานใน python
การวิเคราะห์ไฟล์ PLIST
PLIST (รายการทรัพย์สิน) เป็นรูปแบบที่ยืดหยุ่นและสะดวกในการจัดเก็บข้อมูลแอปพลิเคชันโดยเฉพาะบนอุปกรณ์ iPhone มันใช้ส่วนขยาย.plist. ไฟล์ประเภทนี้ใช้ในการจัดเก็บข้อมูลเกี่ยวกับบันเดิลและแอปพลิเคชัน สามารถมีได้สองรูปแบบ:XML และ binary. รหัส Python ต่อไปนี้จะเปิดและอ่านไฟล์ PLIST โปรดทราบว่าก่อนที่จะดำเนินการนี้เราต้องสร้างของเราเองInfo.plist ไฟล์.
ขั้นแรกให้ติดตั้งไลบรารีของบุคคลที่สามชื่อ biplist โดยคำสั่งต่อไปนี้ -
Pip install biplist
ตอนนี้นำเข้าไลบรารีที่มีประโยชน์เพื่อประมวลผลไฟล์ plist -
import biplist
import os
import sys
ตอนนี้ใช้คำสั่งต่อไปนี้ภายใต้วิธีการหลักสามารถใช้เพื่ออ่านไฟล์ plist เป็นตัวแปร -
def main(plist):
try:
data = biplist.readPlist(plist)
except (biplist.InvalidPlistException,biplist.NotBinaryPlistException) as e:
print("[-] Invalid PLIST file - unable to be opened by biplist")
sys.exit(1)
ตอนนี้เราสามารถอ่านข้อมูลบนคอนโซลหรือพิมพ์โดยตรงจากตัวแปรนี้
ฐานข้อมูล SQLite
SQLite ทำหน้าที่เป็นที่เก็บข้อมูลหลักบนอุปกรณ์มือถือ SQLite ไลบรารีในกระบวนการที่ใช้เอ็นจินฐานข้อมูล SQL ที่มีการทำธุรกรรมในตัวไม่มีเซิร์ฟเวอร์ตั้งค่าเป็นศูนย์ เป็นฐานข้อมูลที่ไม่มีการกำหนดค่าเป็นศูนย์คุณไม่จำเป็นต้องกำหนดค่าในระบบของคุณซึ่งแตกต่างจากฐานข้อมูลอื่น ๆ
หากคุณเป็นมือใหม่หรือไม่คุ้นเคยกับฐานข้อมูล SQLite คุณสามารถไปที่ลิงค์www.tutorialspoint.com/sqlite/index.htmนอกจากนี้คุณสามารถไปที่ลิงค์www.tutorialspoint.com/sqlite/sqlite_python.htmในกรณีที่คุณต้องการ เข้าสู่รายละเอียดของ SQLite ด้วย Python
ในระหว่างการพิสูจน์หลักฐานมือถือเราสามารถโต้ตอบกับไฟล์ sms.db ไฟล์ของอุปกรณ์พกพาและสามารถดึงข้อมูลที่มีค่าจาก messageตาราง. Python มีไลบรารีในตัวชื่อsqlite3สำหรับเชื่อมต่อกับฐานข้อมูล SQLite คุณสามารถนำเข้าสิ่งเดียวกันโดยใช้คำสั่งต่อไปนี้ -
import sqlite3
ตอนนี้ด้วยความช่วยเหลือของคำสั่งต่อไปนี้เราสามารถเชื่อมต่อกับฐานข้อมูลพูด sms.db ในกรณีของอุปกรณ์มือถือ -
Conn = sqlite3.connect(‘sms.db’)
C = conn.cursor()
ที่นี่ C คือวัตถุเคอร์เซอร์ด้วยความช่วยเหลือซึ่งเราสามารถโต้ตอบกับฐานข้อมูลได้
ตอนนี้สมมติว่าถ้าเราต้องการเรียกใช้คำสั่งเฉพาะให้พูดเพื่อรับรายละเอียดจากไฟล์ abc tableสามารถทำได้ด้วยความช่วยเหลือของคำสั่งต่อไปนี้ -
c.execute(“Select * from abc”)
c.close()
ผลลัพธ์ของคำสั่งดังกล่าวจะถูกเก็บไว้ในไฟล์ cursorวัตถุ. ในทำนองเดียวกันเราสามารถใช้fetchall() วิธีการถ่ายโอนผลลัพธ์ไปยังตัวแปรที่เราสามารถจัดการได้
เราสามารถใช้คำสั่งต่อไปนี้เพื่อรับข้อมูลชื่อคอลัมน์ของตารางข้อความใน sms.db -
c.execute(“pragma table_info(message)”)
table_data = c.fetchall()
columns = [x[1] for x in table_data
สังเกตว่าที่นี่เรากำลังใช้คำสั่ง SQLite PRAGMA ซึ่งเป็นคำสั่งพิเศษที่ใช้ในการควบคุมตัวแปรสภาพแวดล้อมต่างๆและแฟล็กสถานะภายในสภาพแวดล้อม SQLite ในคำสั่งด้านบนไฟล์fetchall()วิธีการคืนค่าทูเพิลของผลลัพธ์ ชื่อของแต่ละคอลัมน์จะถูกเก็บไว้ในดัชนีแรกของแต่ละทูเปิล
ตอนนี้ด้วยความช่วยเหลือของคำสั่งต่อไปนี้เราสามารถสืบค้นตารางสำหรับข้อมูลทั้งหมดและเก็บไว้ในตัวแปรที่ชื่อ data_msg -
c.execute(“Select * from message”)
data_msg = c.fetchall()
คำสั่งดังกล่าวจะจัดเก็บข้อมูลในตัวแปรและนอกจากนี้เรายังสามารถเขียนข้อมูลข้างต้นในไฟล์ CSV ได้โดยใช้ csv.writer() วิธี.
การสำรองข้อมูล iTunes
การพิสูจน์หลักฐานมือถือ iPhone สามารถดำเนินการกับข้อมูลสำรองที่ทำโดย iTunes ผู้ตรวจสอบทางนิติวิทยาศาสตร์อาศัยการวิเคราะห์การสำรองข้อมูลเชิงตรรกะของ iPhone ที่ได้รับผ่าน iTunes iTunes ใช้โปรโตคอล AFC (การเชื่อมต่อไฟล์ Apple) เพื่อสำรองข้อมูล นอกจากนี้กระบวนการสำรองข้อมูลจะไม่แก้ไขอะไรบน iPhone ยกเว้นบันทึกคีย์ Escrow
ตอนนี้คำถามเกิดขึ้นว่าเหตุใดผู้เชี่ยวชาญด้านนิติวิทยาศาสตร์ดิจิทัลจึงมีความสำคัญในการทำความเข้าใจเทคนิคในการสำรองข้อมูล iTunes เป็นสิ่งสำคัญในกรณีที่เราสามารถเข้าถึงคอมพิวเตอร์ของผู้ต้องสงสัยแทน iPhone ได้โดยตรงเนื่องจากเมื่อมีการใช้คอมพิวเตอร์เพื่อซิงค์กับ iPhone ข้อมูลส่วนใหญ่บน iPhone มักจะถูกสำรองไว้ในคอมพิวเตอร์
กระบวนการสำรองข้อมูลและที่ตั้ง
เมื่อใดก็ตามที่สำรองข้อมูลผลิตภัณฑ์ Apple ไว้ในคอมพิวเตอร์ผลิตภัณฑ์นั้นจะซิงค์กับ iTunes และจะมีโฟลเดอร์เฉพาะที่มี ID เฉพาะของอุปกรณ์ ในรูปแบบการสำรองข้อมูลล่าสุดไฟล์จะถูกเก็บไว้ในโฟลเดอร์ย่อยที่มีอักขระเลขฐานสิบหกสองตัวแรกของชื่อไฟล์ จากไฟล์สำรองเหล่านี้มีบางไฟล์เช่น info.plist ซึ่งมีประโยชน์พร้อมกับฐานข้อมูลชื่อ Manifest.db ตารางต่อไปนี้แสดงตำแหน่งการสำรองข้อมูลซึ่งแตกต่างกันไปตามระบบปฏิบัติการของการสำรองข้อมูล iTunes -
ระบบปฏิบัติการ | ตำแหน่งสำรอง |
---|---|
ชนะ 7 | C: \ Users \ [ชื่อผู้ใช้] \ AppData \ Roaming \ AppleComputer \ MobileSync \ Backup \ |
MAC OS X | ~ / Library / Application Suport / MobileSync / สำรอง / |
สำหรับการประมวลผลข้อมูลสำรอง iTunes ด้วย Python ก่อนอื่นเราจำเป็นต้องระบุข้อมูลสำรองทั้งหมดในตำแหน่งสำรองตามระบบปฏิบัติการของเรา จากนั้นเราจะทำซ้ำในการสำรองข้อมูลแต่ละครั้งและอ่านฐานข้อมูล Manifest.db
ตอนนี้ด้วยความช่วยเหลือของการทำตามรหัส Python เราสามารถทำได้เช่นเดียวกัน -
ขั้นแรกให้นำเข้าไลบรารีที่จำเป็นดังต่อไปนี้ -
from __future__ import print_function
import argparse
import logging
import os
from shutil import copyfile
import sqlite3
import sys
logger = logging.getLogger(__name__)
ตอนนี้ให้สองอาร์กิวเมนต์ตำแหน่งคือ INPUT_DIR และ OUTPUT_DIR ซึ่งเป็นตัวแทนของการสำรองข้อมูล iTunes และโฟลเดอร์ผลลัพธ์ที่ต้องการ -
if __name__ == "__main__":
parser.add_argument("INPUT_DIR",help = "Location of folder containing iOS backups, ""e.g. ~\Library\Application Support\MobileSync\Backup folder")
parser.add_argument("OUTPUT_DIR", help = "Output Directory")
parser.add_argument("-l", help = "Log file path",default = __file__[:-2] + "log")
parser.add_argument("-v", help = "Increase verbosity",action = "store_true") args = parser.parse_args()
ตอนนี้ตั้งค่าบันทึกดังนี้ -
if args.v:
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
ตอนนี้ตั้งค่ารูปแบบข้อความสำหรับบันทึกนี้ดังนี้ -
msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-13s""%(levelname)-8s %(message)s")
strhndl = logging.StreamHandler(sys.stderr)
strhndl.setFormatter(fmt = msg_fmt)
fhndl = logging.FileHandler(args.l, mode = 'a')
fhndl.setFormatter(fmt = msg_fmt)
logger.addHandler(strhndl)
logger.addHandler(fhndl)
logger.info("Starting iBackup Visualizer")
logger.debug("Supplied arguments: {}".format(" ".join(sys.argv[1:])))
logger.debug("System: " + sys.platform)
logger.debug("Python Version: " + sys.version)
บรรทัดรหัสต่อไปนี้จะสร้างโฟลเดอร์ที่จำเป็นสำหรับไดเร็กทอรีเอาต์พุตที่ต้องการโดยใช้ os.makedirs() ฟังก์ชัน -
if not os.path.exists(args.OUTPUT_DIR):
os.makedirs(args.OUTPUT_DIR)
ตอนนี้ส่งผ่านไดเร็กทอรีอินพุตและเอาต์พุตที่ให้มาไปยังฟังก์ชัน main () ดังนี้ -
if os.path.exists(args.INPUT_DIR) and os.path.isdir(args.INPUT_DIR):
main(args.INPUT_DIR, args.OUTPUT_DIR)
else:
logger.error("Supplied input directory does not exist or is not ""a directory")
sys.exit(1)
ตอนนี้เขียน main() ซึ่งจะเรียกต่อไป backup_summary() ฟังก์ชันเพื่อระบุข้อมูลสำรองทั้งหมดที่มีอยู่ในโฟลเดอร์อินพุต -
def main(in_dir, out_dir):
backups = backup_summary(in_dir)
def backup_summary(in_dir):
logger.info("Identifying all iOS backups in {}".format(in_dir))
root = os.listdir(in_dir)
backups = {}
for x in root:
temp_dir = os.path.join(in_dir, x)
if os.path.isdir(temp_dir) and len(x) == 40:
num_files = 0
size = 0
for root, subdir, files in os.walk(temp_dir):
num_files += len(files)
size += sum(os.path.getsize(os.path.join(root, name))
for name in files)
backups[x] = [temp_dir, num_files, size]
return backups
ตอนนี้พิมพ์สรุปของการสำรองข้อมูลแต่ละรายการไปยังคอนโซลดังนี้ -
print("Backup Summary")
print("=" * 20)
if len(backups) > 0:
for i, b in enumerate(backups):
print("Backup No.: {} \n""Backup Dev. Name: {} \n""# Files: {} \n""Backup Size (Bytes): {}\n".format(i, b, backups[b][1], backups[b][2]))
ตอนนี้ถ่ายโอนเนื้อหาของไฟล์ Manifest.db ไปยังตัวแปรชื่อ db_items
try:
db_items = process_manifest(backups[b][0])
except IOError:
logger.warn("Non-iOS 10 backup encountered or " "invalid backup. Continuing to next backup.")
continue
ตอนนี้ให้เรากำหนดฟังก์ชันที่จะใช้เส้นทางไดเรกทอรีของการสำรองข้อมูล -
def process_manifest(backup):
manifest = os.path.join(backup, "Manifest.db")
if not os.path.exists(manifest):
logger.error("Manifest DB not found in {}".format(manifest))
raise IOError
ตอนนี้ใช้ SQLite3 เราจะเชื่อมต่อกับฐานข้อมูลโดยเคอร์เซอร์ชื่อ c -
c = conn.cursor()
items = {}
for row in c.execute("SELECT * from Files;"):
items[row[0]] = [row[2], row[1], row[3]]
return items
create_files(in_dir, out_dir, b, db_items)
print("=" * 20)
else:
logger.warning("No valid backups found. The input directory should be
" "the parent-directory immediately above the SHA-1 hash " "iOS device backups")
sys.exit(2)
ตอนนี้กำหนด create_files() วิธีการดังนี้ -
def create_files(in_dir, out_dir, b, db_items):
msg = "Copying Files for backup {} to {}".format(b, os.path.join(out_dir, b))
logger.info(msg)
ตอนนี้ทำซ้ำผ่านแต่ละคีย์ในไฟล์ db_items พจนานุกรม -
for x, key in enumerate(db_items):
if db_items[key][0] is None or db_items[key][0] == "":
continue
else:
dirpath = os.path.join(out_dir, b,
os.path.dirname(db_items[key][0]))
filepath = os.path.join(out_dir, b, db_items[key][0])
if not os.path.exists(dirpath):
os.makedirs(dirpath)
original_dir = b + "/" + key[0:2] + "/" + key
path = os.path.join(in_dir, original_dir)
if os.path.exists(filepath):
filepath = filepath + "_{}".format(x)
ตอนนี้ใช้ shutil.copyfile() วิธีคัดลอกไฟล์ที่สำรองไว้ดังนี้ -
try:
copyfile(path, filepath)
except IOError:
logger.debug("File not found in backup: {}".format(path))
files_not_found += 1
if files_not_found > 0:
logger.warning("{} files listed in the Manifest.db not" "found in
backup".format(files_not_found))
copyfile(os.path.join(in_dir, b, "Info.plist"), os.path.join(out_dir, b,
"Info.plist"))
copyfile(os.path.join(in_dir, b, "Manifest.db"), os.path.join(out_dir, b,
"Manifest.db"))
copyfile(os.path.join(in_dir, b, "Manifest.plist"), os.path.join(out_dir, b,
"Manifest.plist"))
copyfile(os.path.join(in_dir, b, "Status.plist"),os.path.join(out_dir, b,
"Status.plist"))
ด้วยสคริปต์ Python ด้านบนเราสามารถรับโครงสร้างไฟล์สำรองที่อัปเดตในโฟลเดอร์ผลลัพธ์ของเรา เราสามารถใช้pycrypto ไลบรารี python เพื่อถอดรหัสการสำรองข้อมูล
Wi - Fi
สามารถใช้อุปกรณ์เคลื่อนที่เพื่อเชื่อมต่อกับโลกภายนอกได้โดยเชื่อมต่อผ่านเครือข่าย Wi-Fi ซึ่งมีอยู่ทุกที่ บางครั้งอุปกรณ์จะเชื่อมต่อกับเครือข่ายแบบเปิดเหล่านี้โดยอัตโนมัติ
ในกรณีของ iPhone รายการการเชื่อมต่อ Wi-Fi แบบเปิดที่อุปกรณ์เชื่อมต่อจะถูกเก็บไว้ในไฟล์ PLIST ชื่อ com.apple.wifi.plist. ไฟล์นี้จะมี Wi-Fi SSID, BSSID และเวลาในการเชื่อมต่อ
เราจำเป็นต้องแยกรายละเอียด Wi-Fi จากรายงาน Cellebrite XML มาตรฐานโดยใช้ Python สำหรับสิ่งนี้เราจำเป็นต้องใช้ API จาก Wireless Geographic Logging Engine (WIGLE) ซึ่งเป็นแพลตฟอร์มยอดนิยมที่สามารถใช้ในการค้นหาตำแหน่งของอุปกรณ์โดยใช้ชื่อของเครือข่าย Wi-Fi
เราสามารถใช้ไลบรารี Python ที่ชื่อ requestsเพื่อเข้าถึง API จาก WIGLE สามารถติดตั้งได้ดังนี้ -
pip install requests
API จาก WIGLE
เราจำเป็นต้องลงทะเบียนบนเว็บไซต์ของ WIGLE https://wigle.net/accountเพื่อรับ API ฟรีจาก WIGLE สคริปต์ Python สำหรับรับข้อมูลเกี่ยวกับอุปกรณ์ผู้ใช้และการเชื่อมต่อผ่าน API ของ WIGEL จะกล่าวถึงด้านล่าง -
ขั้นแรกให้นำเข้าไลบรารีต่อไปนี้เพื่อจัดการสิ่งต่างๆ -
from __future__ import print_function
import argparse
import csv
import os
import sys
import xml.etree.ElementTree as ET
import requests
ตอนนี้ให้สองอาร์กิวเมนต์ตำแหน่งคือ INPUT_FILE และ OUTPUT_CSV ซึ่งจะแสดงไฟล์อินพุตด้วยที่อยู่ MAC ของ Wi-Fi และไฟล์ CSV เอาต์พุตที่ต้องการตามลำดับ -
if __name__ == "__main__":
parser.add_argument("INPUT_FILE", help = "INPUT FILE with MAC Addresses")
parser.add_argument("OUTPUT_CSV", help = "Output CSV File")
parser.add_argument("-t", help = "Input type: Cellebrite XML report or TXT
file",choices = ('xml', 'txt'), default = "xml")
parser.add_argument('--api', help = "Path to API key
file",default = os.path.expanduser("~/.wigle_api"),
type = argparse.FileType('r'))
args = parser.parse_args()
ตอนนี้บรรทัดของโค้ดต่อไปนี้จะตรวจสอบว่ามีไฟล์อินพุตอยู่หรือไม่และเป็นไฟล์ ถ้าไม่มันออกจากสคริปต์ -
if not os.path.exists(args.INPUT_FILE) or \ not os.path.isfile(args.INPUT_FILE):
print("[-] {} does not exist or is not a
file".format(args.INPUT_FILE))
sys.exit(1)
directory = os.path.dirname(args.OUTPUT_CSV)
if directory != '' and not os.path.exists(directory):
os.makedirs(directory)
api_key = args.api.readline().strip().split(":")
ตอนนี้ส่งอาร์กิวเมนต์ไปที่ main ดังนี้ -
main(args.INPUT_FILE, args.OUTPUT_CSV, args.t, api_key)
def main(in_file, out_csv, type, api_key):
if type == 'xml':
wifi = parse_xml(in_file)
else:
wifi = parse_txt(in_file)
query_wigle(wifi, out_csv, api_key)
ตอนนี้เราจะแยกวิเคราะห์ไฟล์ XML ดังนี้ -
def parse_xml(xml_file):
wifi = {}
xmlns = "{http://pa.cellebrite.com/report/2.0}"
print("[+] Opening {} report".format(xml_file))
xml_tree = ET.parse(xml_file)
print("[+] Parsing report for all connected WiFi addresses")
root = xml_tree.getroot()
ตอนนี้วนซ้ำผ่านองค์ประกอบลูกของรูทดังนี้ -
for child in root.iter():
if child.tag == xmlns + "model":
if child.get("type") == "Location":
for field in child.findall(xmlns + "field"):
if field.get("name") == "TimeStamp":
ts_value = field.find(xmlns + "value")
try:
ts = ts_value.text
except AttributeError:
continue
ตอนนี้เราจะตรวจสอบว่ามีสตริง 'ssid' อยู่ในข้อความของค่าหรือไม่ -
if "SSID" in value.text:
bssid, ssid = value.text.split("\t")
bssid = bssid[7:]
ssid = ssid[6:]
ตอนนี้เราต้องเพิ่ม BSSID, SSID และการประทับเวลาลงในพจนานุกรม wifi ดังนี้ -
if bssid in wifi.keys():
wifi[bssid]["Timestamps"].append(ts)
wifi[bssid]["SSID"].append(ssid)
else:
wifi[bssid] = {"Timestamps": [ts], "SSID":
[ssid],"Wigle": {}}
return wifi
ตัวแยกวิเคราะห์ข้อความซึ่งง่ายกว่ามากที่ตัวแยกวิเคราะห์ XML แสดงไว้ด้านล่าง -
def parse_txt(txt_file):
wifi = {}
print("[+] Extracting MAC addresses from {}".format(txt_file))
with open(txt_file) as mac_file:
for line in mac_file:
wifi[line.strip()] = {"Timestamps": ["N/A"], "SSID":
["N/A"],"Wigle": {}}
return wifi
ตอนนี้ให้เราใช้โมดูลคำขอเพื่อสร้าง WIGLE APIโทรและจำเป็นต้องไปยังไฟล์ query_wigle() วิธีการ -
def query_wigle(wifi_dictionary, out_csv, api_key):
print("[+] Querying Wigle.net through Python API for {} "
"APs".format(len(wifi_dictionary)))
for mac in wifi_dictionary:
wigle_results = query_mac_addr(mac, api_key)
def query_mac_addr(mac_addr, api_key):
query_url = "https://api.wigle.net/api/v2/network/search?" \
"onlymine = false&freenet = false&paynet = false" \ "&netid = {}".format(mac_addr)
req = requests.get(query_url, auth = (api_key[0], api_key[1]))
return req.json()
จริงๆแล้วมีขีด จำกัด ต่อวันสำหรับการเรียก WIGLE API หากเกินขีด จำกัด นั้นจะต้องแสดงข้อผิดพลาดดังนี้ -
try:
if wigle_results["resultCount"] == 0:
wifi_dictionary[mac]["Wigle"]["results"] = []
continue
else:
wifi_dictionary[mac]["Wigle"] = wigle_results
except KeyError:
if wigle_results["error"] == "too many queries today":
print("[-] Wigle daily query limit exceeded")
wifi_dictionary[mac]["Wigle"]["results"] = []
continue
else:
print("[-] Other error encountered for " "address {}: {}".format(mac,
wigle_results['error']))
wifi_dictionary[mac]["Wigle"]["results"] = []
continue
prep_output(out_csv, wifi_dictionary)
ตอนนี้เราจะใช้ prep_output() วิธีการแบนพจนานุกรมเป็นชิ้นที่เขียนได้ง่าย -
def prep_output(output, data):
csv_data = {}
google_map = https://www.google.com/maps/search/
ตอนนี้เข้าถึงข้อมูลทั้งหมดที่เรารวบรวมไว้ดังนี้ -
for x, mac in enumerate(data):
for y, ts in enumerate(data[mac]["Timestamps"]):
for z, result in enumerate(data[mac]["Wigle"]["results"]):
shortres = data[mac]["Wigle"]["results"][z]
g_map_url = "{}{},{}".format(google_map, shortres["trilat"],shortres["trilong"])
ตอนนี้เราสามารถเขียนผลลัพธ์ในไฟล์ CSV ได้ตามที่เราเคยทำในสคริปต์ก่อนหน้านี้ในบทนี้โดยใช้ write_csv() ฟังก์ชัน
ในบทนี้เราจะเรียนรู้รายละเอียดเกี่ยวกับการตรวจสอบข้อมูลเมตาที่ฝังไว้โดยใช้ Python digital forensics
บทนำ
ข้อมูลเมตาแบบฝังคือข้อมูลเกี่ยวกับข้อมูลที่จัดเก็บในไฟล์เดียวกันซึ่งมีออบเจ็กต์ที่อธิบายโดยข้อมูลนั้น กล่าวอีกนัยหนึ่งก็คือข้อมูลเกี่ยวกับสินทรัพย์ดิจิทัลที่เก็บไว้ในไฟล์ดิจิทัลนั้นเอง มันเชื่อมโยงกับไฟล์เสมอและไม่สามารถแยกออกจากกันได้
ในกรณีของนิติดิจิทัลเราไม่สามารถดึงข้อมูลทั้งหมดเกี่ยวกับไฟล์ใดไฟล์หนึ่งได้ ในอีกด้านหนึ่งข้อมูลเมตาที่ฝังไว้สามารถให้ข้อมูลที่สำคัญต่อการตรวจสอบแก่เรา ตัวอย่างเช่นข้อมูลเมตาของไฟล์ข้อความอาจมีข้อมูลเกี่ยวกับผู้เขียนความยาววันที่เขียนและแม้แต่สรุปสั้น ๆ เกี่ยวกับเอกสารนั้น ภาพดิจิทัลอาจมีข้อมูลเมตาเช่นความยาวของภาพความเร็วชัตเตอร์เป็นต้น
อาร์ติแฟกต์ที่มีแอตทริบิวต์ข้อมูลเมตาและการแยก
ในส่วนนี้เราจะเรียนรู้เกี่ยวกับอาร์ติแฟกต์ต่างๆที่มีแอตทริบิวต์ข้อมูลเมตาและกระบวนการแยกโดยใช้ Python
เสียงและวิดีโอ
สิ่งเหล่านี้เป็นสิ่งประดิษฐ์ทั่วไปสองรายการที่มีข้อมูลเมตาฝังอยู่ ข้อมูลเมตานี้สามารถแยกออกมาเพื่อวัตถุประสงค์ในการตรวจสอบ
คุณสามารถใช้สคริปต์ Python ต่อไปนี้เพื่อแยกแอตทริบิวต์หรือข้อมูลเมตาทั่วไปจากไฟล์เสียงหรือ MP3 และวิดีโอหรือไฟล์ MP4
โปรดทราบว่าสำหรับสคริปต์นี้เราจำเป็นต้องติดตั้งไลบรารี python ของบุคคลที่สามชื่อ mutagen ซึ่งช่วยให้เราสามารถแยกข้อมูลเมตาจากไฟล์เสียงและวิดีโอได้ สามารถติดตั้งได้ด้วยความช่วยเหลือของคำสั่งต่อไปนี้ -
pip install mutagen
ไลบรารีที่มีประโยชน์บางส่วนที่เราต้องนำเข้าสำหรับสคริปต์ Python นี้มีดังนี้ -
from __future__ import print_function
import argparse
import json
import mutagen
ตัวจัดการบรรทัดคำสั่งจะใช้อาร์กิวเมนต์หนึ่งรายการซึ่งแสดงถึงเส้นทางไปยังไฟล์ MP3 หรือ MP4 จากนั้นเราจะใช้mutagen.file() วิธีการเปิดจุดจับไฟล์ดังต่อไปนี้ -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Python Metadata Extractor')
parser.add_argument("AV_FILE", help="File to extract metadata from")
args = parser.parse_args()
av_file = mutagen.File(args.AV_FILE)
file_ext = args.AV_FILE.rsplit('.', 1)[-1]
if file_ext.lower() == 'mp3':
handle_id3(av_file)
elif file_ext.lower() == 'mp4':
handle_mp4(av_file)
ตอนนี้เราต้องใช้ที่จับสองอันอันหนึ่งเพื่อดึงข้อมูลจาก MP3 และอีกอันเพื่อดึงข้อมูลจากไฟล์ MP4 เราสามารถกำหนดจุดจับเหล่านี้ได้ดังนี้ -
def handle_id3(id3_file):
id3_frames = {'TIT2': 'Title', 'TPE1': 'Artist', 'TALB': 'Album','TXXX':
'Custom', 'TCON': 'Content Type', 'TDRL': 'Date released','COMM': 'Comments',
'TDRC': 'Recording Date'}
print("{:15} | {:15} | {:38} | {}".format("Frame", "Description","Text","Value"))
print("-" * 85)
for frames in id3_file.tags.values():
frame_name = id3_frames.get(frames.FrameID, frames.FrameID)
desc = getattr(frames, 'desc', "N/A")
text = getattr(frames, 'text', ["N/A"])[0]
value = getattr(frames, 'value', "N/A")
if "date" in frame_name.lower():
text = str(text)
print("{:15} | {:15} | {:38} | {}".format(
frame_name, desc, text, value))
def handle_mp4(mp4_file):
cp_sym = u"\u00A9"
qt_tag = {
cp_sym + 'nam': 'Title', cp_sym + 'art': 'Artist',
cp_sym + 'alb': 'Album', cp_sym + 'gen': 'Genre',
'cpil': 'Compilation', cp_sym + 'day': 'Creation Date',
'cnID': 'Apple Store Content ID', 'atID': 'Album Title ID',
'plID': 'Playlist ID', 'geID': 'Genre ID', 'pcst': 'Podcast',
'purl': 'Podcast URL', 'egid': 'Episode Global ID',
'cmID': 'Camera ID', 'sfID': 'Apple Store Country',
'desc': 'Description', 'ldes': 'Long Description'}
genre_ids = json.load(open('apple_genres.json'))
ตอนนี้เราต้องวนซ้ำผ่านไฟล์ MP4 นี้ดังนี้ -
print("{:22} | {}".format('Name', 'Value'))
print("-" * 40)
for name, value in mp4_file.tags.items():
tag_name = qt_tag.get(name, name)
if isinstance(value, list):
value = "; ".join([str(x) for x in value])
if name == 'geID':
value = "{}: {}".format(
value, genre_ids[str(value)].replace("|", " - "))
print("{:22} | {}".format(tag_name, value))
สคริปต์ด้านบนจะให้ข้อมูลเพิ่มเติมเกี่ยวกับไฟล์ MP3 และไฟล์ MP4
รูปภาพ
รูปภาพอาจมีข้อมูลเมตาประเภทต่างๆขึ้นอยู่กับรูปแบบไฟล์ อย่างไรก็ตามภาพส่วนใหญ่ฝังข้อมูล GPS เราสามารถดึงข้อมูล GPS นี้ได้โดยใช้ไลบรารี Python ของบุคคลที่สาม คุณสามารถใช้สคริปต์ Python ต่อไปนี้เพื่อทำเช่นเดียวกัน -
ขั้นแรกให้ดาวน์โหลดไลบรารี python ของบุคคลที่สามที่ชื่อ Python Imaging Library (PIL) ดังต่อไปนี้ -
pip install pillow
สิ่งนี้จะช่วยให้เราดึงข้อมูลเมตาจากรูปภาพได้
นอกจากนี้เรายังสามารถเขียนรายละเอียด GPS ที่ฝังอยู่ในรูปภาพไปยังไฟล์ KML ได้ แต่สำหรับสิ่งนี้เราจำเป็นต้องดาวน์โหลดไลบรารี Python ของบุคคลที่สามชื่อ simplekml ดังต่อไปนี้ -
pip install simplekml
ในสคริปต์นี้ก่อนอื่นเราต้องนำเข้าไลบรารีต่อไปนี้ -
from __future__ import print_function
import argparse
from PIL import Image
from PIL.ExifTags import TAGS
import simplekml
import sys
ตอนนี้ตัวจัดการบรรทัดคำสั่งจะยอมรับอาร์กิวเมนต์ตำแหน่งหนึ่งซึ่งโดยพื้นฐานแล้วแสดงถึงเส้นทางไฟล์ของรูปภาพ
parser = argparse.ArgumentParser('Metadata from images')
parser.add_argument('PICTURE_FILE', help = "Path to picture")
args = parser.parse_args()
ตอนนี้เราจำเป็นต้องระบุ URL ที่จะเติมข้อมูลพิกัด URL คือgmaps และ open_maps. เรายังต้องการฟังก์ชั่นในการแปลงพิกัดทูเพิลดีกรีนาทีวินาที (DMS) ซึ่งจัดทำโดยไลบรารี PIL เป็นทศนิยม สามารถทำได้ดังนี้ -
gmaps = "https://www.google.com/maps?q={},{}"
open_maps = "http://www.openstreetmap.org/?mlat={}&mlon={}"
def process_coords(coord):
coord_deg = 0
for count, values in enumerate(coord):
coord_deg += (float(values[0]) / values[1]) / 60**count
return coord_deg
ตอนนี้เราจะใช้ image.open() เพื่อเปิดไฟล์เป็นวัตถุ PIL
img_file = Image.open(args.PICTURE_FILE)
exif_data = img_file._getexif()
if exif_data is None:
print("No EXIF data found")
sys.exit()
for name, value in exif_data.items():
gps_tag = TAGS.get(name, name)
if gps_tag is not 'GPSInfo':
continue
หลังจากพบไฟล์ GPSInfo เราจะจัดเก็บข้อมูลอ้างอิง GPS และประมวลผลพิกัดด้วยไฟล์ process_coords() วิธี.
lat_ref = value[1] == u'N'
lat = process_coords(value[2])
if not lat_ref:
lat = lat * -1
lon_ref = value[3] == u'E'
lon = process_coords(value[4])
if not lon_ref:
lon = lon * -1
ตอนนี้เริ่มต้น kml วัตถุจาก simplekml ห้องสมุดดังนี้ -
kml = simplekml.Kml()
kml.newpoint(name = args.PICTURE_FILE, coords = [(lon, lat)])
kml.save(args.PICTURE_FILE + ".kml")
ตอนนี้เราสามารถพิมพ์พิกัดจากข้อมูลที่ประมวลผลได้แล้วดังนี้ -
print("GPS Coordinates: {}, {}".format(lat, lon))
print("Google Maps URL: {}".format(gmaps.format(lat, lon)))
print("OpenStreetMap URL: {}".format(open_maps.format(lat, lon)))
print("KML File {} created".format(args.PICTURE_FILE + ".kml"))
เอกสาร PDF
เอกสาร PDF มีสื่อที่หลากหลายรวมถึงรูปภาพข้อความแบบฟอร์มและอื่น ๆ เมื่อเราดึงข้อมูลเมตาที่ฝังไว้ในเอกสาร PDF เราอาจได้รับข้อมูลผลลัพธ์ในรูปแบบที่เรียกว่า Extensible Metadata Platform (XMP) เราสามารถแยกข้อมูลเมตาด้วยความช่วยเหลือของรหัส Python ต่อไปนี้ -
ขั้นแรกให้ติดตั้งไลบรารี Python ของบุคคลที่สามชื่อ PyPDF2เพื่ออ่านข้อมูลเมตาที่จัดเก็บในรูปแบบ XMP สามารถติดตั้งได้ดังนี้ -
pip install PyPDF2
ตอนนี้นำเข้าไลบรารีต่อไปนี้เพื่อแยกข้อมูลเมตาจากไฟล์ PDF -
from __future__ import print_function
from argparse import ArgumentParser, FileType
import datetime
from PyPDF2 import PdfFileReader
import sys
ตอนนี้ตัวจัดการบรรทัดคำสั่งจะยอมรับอาร์กิวเมนต์ตำแหน่งหนึ่งซึ่งโดยทั่วไปแสดงถึงเส้นทางไฟล์ของไฟล์ PDF
parser = argparse.ArgumentParser('Metadata from PDF')
parser.add_argument('PDF_FILE', help='Path to PDF file',type=FileType('rb'))
args = parser.parse_args()
ตอนนี้เราสามารถใช้ getXmpMetadata() วิธีการจัดเตรียมวัตถุที่มีข้อมูลเมตาที่มีดังต่อไปนี้ -
pdf_file = PdfFileReader(args.PDF_FILE)
xmpm = pdf_file.getXmpMetadata()
if xmpm is None:
print("No XMP metadata found in document.")
sys.exit()
เราสามารถใช้ custom_print() วิธีการแยกและพิมพ์ค่าที่เกี่ยวข้องเช่นชื่อผู้สร้างผู้มีส่วนร่วม ฯลฯ ดังต่อไปนี้ -
custom_print("Title: {}", xmpm.dc_title)
custom_print("Creator(s): {}", xmpm.dc_creator)
custom_print("Contributors: {}", xmpm.dc_contributor)
custom_print("Subject: {}", xmpm.dc_subject)
custom_print("Description: {}", xmpm.dc_description)
custom_print("Created: {}", xmpm.xmp_createDate)
custom_print("Modified: {}", xmpm.xmp_modifyDate)
custom_print("Event Dates: {}", xmpm.dc_date)
เรายังสามารถกำหนด custom_print() วิธีการในกรณีที่สร้าง PDF โดยใช้ซอฟต์แวร์หลายตัวดังนี้ -
def custom_print(fmt_str, value):
if isinstance(value, list):
print(fmt_str.format(", ".join(value)))
elif isinstance(value, dict):
fmt_value = [":".join((k, v)) for k, v in value.items()]
print(fmt_str.format(", ".join(value)))
elif isinstance(value, str) or isinstance(value, bool):
print(fmt_str.format(value))
elif isinstance(value, bytes):
print(fmt_str.format(value.decode()))
elif isinstance(value, datetime.datetime):
print(fmt_str.format(value.isoformat()))
elif value is None:
print(fmt_str.format("N/A"))
else:
print("warn: unhandled type {} found".format(type(value)))
นอกจากนี้เรายังสามารถดึงคุณสมบัติที่กำหนดเองอื่น ๆ ที่ซอฟต์แวร์บันทึกไว้ได้ดังนี้ -
if xmpm.custom_properties:
print("Custom Properties:")
for k, v in xmpm.custom_properties.items():
print("\t{}: {}".format(k, v))
สคริปต์ด้านบนจะอ่านเอกสาร PDF และจะพิมพ์ข้อมูลเมตาที่จัดเก็บในรูปแบบ XMP รวมถึงคุณสมบัติที่กำหนดเองบางอย่างที่ซอฟต์แวร์จัดเก็บไว้ด้วยความช่วยเหลือของ PDF นั้น
ไฟล์ปฏิบัติการ Windows
บางครั้งเราอาจพบไฟล์ปฏิบัติการที่น่าสงสัยหรือไม่ได้รับอนุญาต แต่เพื่อวัตถุประสงค์ในการตรวจสอบอาจเป็นประโยชน์เนื่องจากข้อมูลเมตาที่ฝังไว้ เราสามารถรับข้อมูลเช่นตำแหน่งที่ตั้งวัตถุประสงค์และคุณสมบัติอื่น ๆ เช่นผู้ผลิตวันที่รวบรวมเป็นต้นด้วยความช่วยเหลือของการทำตามสคริปต์ Python เราจะได้รับวันที่รวบรวมข้อมูลที่เป็นประโยชน์จากส่วนหัวและนำเข้ารวมทั้งสัญลักษณ์ที่ส่งออก
เพื่อจุดประสงค์นี้อันดับแรกให้ติดตั้งไลบรารี Python ของบุคคลที่สามก่อน pefile. สามารถทำได้ดังนี้ -
pip install pefile
เมื่อคุณติดตั้งสำเร็จแล้วให้นำเข้าไลบรารีต่อไปนี้ดังนี้ -
from __future__ import print_function
import argparse
from datetime import datetime
from pefile import PE
ตอนนี้ตัวจัดการบรรทัดคำสั่งจะยอมรับอาร์กิวเมนต์ตำแหน่งหนึ่งซึ่งโดยพื้นฐานแล้วแสดงถึงเส้นทางไฟล์ของไฟล์ปฏิบัติการ คุณยังสามารถเลือกรูปแบบของเอาต์พุตได้ไม่ว่าคุณจะต้องการแบบละเอียดและแบบละเอียดหรือในลักษณะที่เรียบง่าย สำหรับสิ่งนี้คุณต้องให้อาร์กิวเมนต์ที่เป็นทางเลือกดังที่แสดงด้านล่าง -
parser = argparse.ArgumentParser('Metadata from executable file')
parser.add_argument("EXE_FILE", help = "Path to exe file")
parser.add_argument("-v", "--verbose", help = "Increase verbosity of output",
action = 'store_true', default = False)
args = parser.parse_args()
ตอนนี้เราจะโหลดไฟล์ปฏิบัติการอินพุตโดยใช้คลาส PE นอกจากนี้เราจะถ่ายโอนข้อมูลที่ปฏิบัติการได้ไปยังวัตถุพจนานุกรมโดยใช้dump_dict() วิธี.
pe = PE(args.EXE_FILE)
ped = pe.dump_dict()
เราสามารถแยกข้อมูลเมตาของไฟล์พื้นฐานเช่นการเขียนแบบฝังเวอร์ชันและเวลาในการรวบรวมโดยใช้รหัสที่แสดงด้านล่าง -
file_info = {}
for structure in pe.FileInfo:
if structure.Key == b'StringFileInfo':
for s_table in structure.StringTable:
for key, value in s_table.entries.items():
if value is None or len(value) == 0:
value = "Unknown"
file_info[key] = value
print("File Information: ")
print("==================")
for k, v in file_info.items():
if isinstance(k, bytes):
k = k.decode()
if isinstance(v, bytes):
v = v.decode()
print("{}: {}".format(k, v))
comp_time = ped['FILE_HEADER']['TimeDateStamp']['Value']
comp_time = comp_time.split("[")[-1].strip("]")
time_stamp, timezone = comp_time.rsplit(" ", 1)
comp_time = datetime.strptime(time_stamp, "%a %b %d %H:%M:%S %Y")
print("Compiled on {} {}".format(comp_time, timezone.strip()))
เราสามารถดึงข้อมูลที่เป็นประโยชน์จากส่วนหัวได้ดังนี้ -
for section in ped['PE Sections']:
print("Section '{}' at {}: {}/{} {}".format(
section['Name']['Value'], hex(section['VirtualAddress']['Value']),
section['Misc_VirtualSize']['Value'],
section['SizeOfRawData']['Value'], section['MD5'])
)
ตอนนี้แยกรายการการนำเข้าและส่งออกจากไฟล์ปฏิบัติการดังที่แสดงด้านล่าง -
if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
print("\nImports: ")
print("=========")
for dir_entry in pe.DIRECTORY_ENTRY_IMPORT:
dll = dir_entry.dll
if not args.verbose:
print(dll.decode(), end=", ")
continue
name_list = []
for impts in dir_entry.imports:
if getattr(impts, "name", b"Unknown") is None:
name = b"Unknown"
else:
name = getattr(impts, "name", b"Unknown")
name_list.append([name.decode(), hex(impts.address)])
name_fmt = ["{} ({})".format(x[0], x[1]) for x in name_list]
print('- {}: {}'.format(dll.decode(), ", ".join(name_fmt)))
if not args.verbose:
print()
ตอนนี้พิมพ์ exports, names และ addresses โดยใช้รหัสที่แสดงด้านล่าง -
if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
print("\nExports: ")
print("=========")
for sym in pe.DIRECTORY_ENTRY_EXPORT.symbols:
print('- {}: {}'.format(sym.name.decode(), hex(sym.address)))
สคริปต์ด้านบนจะดึงข้อมูลเมตาพื้นฐานข้อมูลจากส่วนหัวจากไฟล์ปฏิบัติการของ Windows
ข้อมูลเมตาของเอกสาร Office
งานส่วนใหญ่ในคอมพิวเตอร์จะทำในโปรแกรม MS Office สามโปรแกรม ได้แก่ Word, PowerPoint และ Excel ไฟล์เหล่านี้มีข้อมูลเมตาขนาดใหญ่ซึ่งสามารถเปิดเผยข้อมูลที่น่าสนใจเกี่ยวกับการประพันธ์และประวัติของพวกเขา
โปรดทราบว่าข้อมูลเมตาจากรูปแบบ 2007 ของ word (.docx), excel (.xlsx) และ powerpoint (.pptx) จะถูกเก็บไว้ในไฟล์ XML เราสามารถประมวลผลไฟล์ XML เหล่านี้ใน Python ด้วยความช่วยเหลือของสคริปต์ Python ที่แสดงด้านล่าง -
ขั้นแรกให้นำเข้าไลบรารีที่ต้องการดังที่แสดงด้านล่าง -
from __future__ import print_function
from argparse import ArgumentParser
from datetime import datetime as dt
from xml.etree import ElementTree as etree
import zipfile
parser = argparse.ArgumentParser('Office Document Metadata’)
parser.add_argument("Office_File", help="Path to office file to read")
args = parser.parse_args()
ตอนนี้ตรวจสอบว่าไฟล์นั้นเป็นไฟล์ ZIP หรือไม่ มิฉะนั้นให้เพิ่มข้อผิดพลาด ตอนนี้เปิดไฟล์และแยกองค์ประกอบสำคัญสำหรับการประมวลผลโดยใช้รหัสต่อไปนี้ -
zipfile.is_zipfile(args.Office_File)
zfile = zipfile.ZipFile(args.Office_File)
core_xml = etree.fromstring(zfile.read('docProps/core.xml'))
app_xml = etree.fromstring(zfile.read('docProps/app.xml'))
ตอนนี้สร้างพจนานุกรมสำหรับการเริ่มต้นการแยกข้อมูลเมตา -
core_mapping = {
'title': 'Title',
'subject': 'Subject',
'creator': 'Author(s)',
'keywords': 'Keywords',
'description': 'Description',
'lastModifiedBy': 'Last Modified By',
'modified': 'Modified Date',
'created': 'Created Date',
'category': 'Category',
'contentStatus': 'Status',
'revision': 'Revision'
}
ใช้ iterchildren() วิธีการเข้าถึงแต่ละแท็กภายในไฟล์ XML -
for element in core_xml.getchildren():
for key, title in core_mapping.items():
if key in element.tag:
if 'date' in title.lower():
text = dt.strptime(element.text, "%Y-%m-%dT%H:%M:%SZ")
else:
text = element.text
print("{}: {}".format(title, text))
ในทำนองเดียวกันให้ทำเช่นนี้สำหรับไฟล์ app.xml ซึ่งมีข้อมูลทางสถิติเกี่ยวกับเนื้อหาของเอกสาร -
app_mapping = {
'TotalTime': 'Edit Time (minutes)',
'Pages': 'Page Count',
'Words': 'Word Count',
'Characters': 'Character Count',
'Lines': 'Line Count',
'Paragraphs': 'Paragraph Count',
'Company': 'Company',
'HyperlinkBase': 'Hyperlink Base',
'Slides': 'Slide count',
'Notes': 'Note Count',
'HiddenSlides': 'Hidden Slide Count',
}
for element in app_xml.getchildren():
for key, title in app_mapping.items():
if key in element.tag:
if 'date' in title.lower():
text = dt.strptime(element.text, "%Y-%m-%dT%H:%M:%SZ")
else:
text = element.text
print("{}: {}".format(title, text))
หลังจากเรียกใช้สคริปต์ด้านบนแล้วเราจะได้รับรายละเอียดต่างๆเกี่ยวกับเอกสารนั้น ๆ โปรดทราบว่าเราสามารถใช้สคริปต์นี้กับเอกสาร Office 2007 หรือเวอร์ชันที่ใหม่กว่าเท่านั้น
บทนี้จะอธิบายพื้นฐานที่เกี่ยวข้องในการดำเนินการนิติเครือข่ายโดยใช้ Python
การทำความเข้าใจนิติเครือข่าย
นิติเครือข่ายเป็นสาขาหนึ่งของนิติดิจิทัลที่เกี่ยวข้องกับการตรวจสอบและวิเคราะห์การรับส่งข้อมูลเครือข่ายคอมพิวเตอร์ทั้งในพื้นที่และ WAN (เครือข่ายบริเวณกว้าง) เพื่อวัตถุประสงค์ในการรวบรวมข้อมูลการรวบรวมหลักฐานหรือการตรวจจับการบุกรุก นิติเครือข่ายมีบทบาทสำคัญในการตรวจสอบอาชญากรรมดิจิทัลเช่นการขโมยทรัพย์สินทางปัญญาหรือการรั่วไหลของข้อมูล ภาพของการสื่อสารบนเครือข่ายช่วยให้ผู้ตรวจสอบสามารถแก้คำถามที่สำคัญได้ดังต่อไปนี้ -
เข้าเว็บไซต์อะไรบ้าง
มีการอัปโหลดเนื้อหาประเภทใดในเครือข่ายของเรา
มีการดาวน์โหลดเนื้อหาประเภทใดจากเครือข่ายของเรา
มีการเข้าถึงเซิร์ฟเวอร์ใดบ้าง
มีใครส่งข้อมูลที่ละเอียดอ่อนออกไปนอกไฟร์วอลล์ของ บริษัท หรือไม่
Internet Evidence Finder (IEF)
IEF เป็นเครื่องมือทางนิติวิทยาศาสตร์ดิจิทัลในการค้นหาวิเคราะห์และนำเสนอหลักฐานดิจิทัลที่พบในสื่อดิจิทัลต่างๆเช่นคอมพิวเตอร์สมาร์ทโฟนแท็บเล็ตเป็นต้นเป็นที่นิยมและใช้โดยผู้เชี่ยวชาญด้านนิติเวชหลายพันคน
การใช้ IEF
เนื่องจากความนิยม IEF จึงถูกใช้โดยผู้เชี่ยวชาญด้านนิติเวชในระดับมาก การใช้ IEF บางส่วนมีดังนี้ -
เนื่องจากความสามารถในการค้นหาที่มีประสิทธิภาพจึงใช้เพื่อค้นหาไฟล์หรือสื่อข้อมูลหลายไฟล์พร้อมกัน
นอกจากนี้ยังใช้เพื่อกู้คืนข้อมูลที่ถูกลบจากพื้นที่ว่างที่ไม่ได้จัดสรรของ RAM ผ่านเทคนิคการแกะสลักใหม่
หากผู้ตรวจสอบต้องการสร้างหน้าเว็บใหม่ในรูปแบบเดิมในวันที่เปิดก็สามารถใช้ IEF ได้
นอกจากนี้ยังใช้เพื่อค้นหาโลจิคัลดิสก์หรือฟิสิคัลวอลุ่ม
การทิ้งรายงานจาก IEF เป็น CSV โดยใช้ Python
IEF จัดเก็บข้อมูลในฐานข้อมูล SQLite และตามสคริปต์ Python จะระบุตารางผลลัพธ์แบบไดนามิกภายในฐานข้อมูล IEF และถ่ายโอนข้อมูลไปยังไฟล์ CSV ที่เกี่ยวข้อง
ขั้นตอนนี้ทำได้ตามขั้นตอนที่แสดงด้านล่าง
ขั้นแรกให้สร้างฐานข้อมูลผลลัพธ์ IEF ซึ่งจะเป็นไฟล์ฐานข้อมูล SQLite ที่ลงท้ายด้วยนามสกุล. db
จากนั้นค้นหาฐานข้อมูลนั้นเพื่อระบุตารางทั้งหมด
สุดท้ายเขียนตารางผลลัพธ์นี้ลงในไฟล์ CSV แต่ละไฟล์
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
สำหรับสคริปต์ Python ให้นำเข้าไลบรารีที่จำเป็นดังต่อไปนี้ -
from __future__ import print_function
import argparse
import csv
import os
import sqlite3
import sys
ตอนนี้เราต้องระบุเส้นทางไปยังไฟล์ฐานข้อมูล IEF -
if __name__ == '__main__':
parser = argparse.ArgumentParser('IEF to CSV')
parser.add_argument("IEF_DATABASE", help="Input IEF database")
parser.add_argument("OUTPUT_DIR", help="Output DIR")
args = parser.parse_args()
ตอนนี้เราจะยืนยันการมีอยู่ของฐานข้อมูล IEF ดังนี้ -
if not os.path.exists(args.OUTPUT_DIR):
os.makedirs(args.OUTPUT_DIR)
if os.path.exists(args.IEF_DATABASE) and \ os.path.isfile(args.IEF_DATABASE):
main(args.IEF_DATABASE, args.OUTPUT_DIR)
else:
print("[-] Supplied input file {} does not exist or is not a " "file".format(args.IEF_DATABASE))
sys.exit(1)
ตอนนี้ตามที่เราทำในสคริปต์ก่อนหน้านี้ให้ทำการเชื่อมต่อกับฐานข้อมูล SQLite ดังต่อไปนี้เพื่อดำเนินการค้นหาผ่านเคอร์เซอร์ -
def main(database, out_directory):
print("[+] Connecting to SQLite database")
conn = sqlite3.connect(database)
c = conn.cursor()
โค้ดบรรทัดต่อไปนี้จะดึงชื่อของตารางจากฐานข้อมูล -
print("List of all tables to extract")
c.execute("select * from sqlite_master where type = 'table'")
tables = [x[2] for x in c.fetchall() if not x[2].startswith('_') and not x[2].endswith('_DATA')]
ตอนนี้เราจะเลือกข้อมูลทั้งหมดจากตารางและโดยใช้ fetchall() วิธีการบนวัตถุเคอร์เซอร์เราจะจัดเก็บรายการสิ่งทอที่มีข้อมูลของตารางอย่างครบถ้วนในตัวแปร -
print("Dumping {} tables to CSV files in {}".format(len(tables), out_directory))
for table in tables:
c.execute("pragma table_info('{}')".format(table))
table_columns = [x[1] for x in c.fetchall()]
c.execute("select * from '{}'".format(table))
table_data = c.fetchall()
ตอนนี้โดยใช้ CSV_Writer() วิธีการที่เราจะเขียนเนื้อหาในไฟล์ CSV -
csv_name = table + '.csv'
csv_path = os.path.join(out_directory, csv_name)
print('[+] Writing {} table to {} CSV file'.format(table,csv_name))
with open(csv_path, "w", newline = "") as csvfile:
csv_writer = csv.writer(csvfile)
csv_writer.writerow(table_columns)
csv_writer.writerows(table_data)
สคริปต์ด้านบนจะดึงข้อมูลทั้งหมดจากตารางของฐานข้อมูล IEF และเขียนเนื้อหาลงในไฟล์ CSV ที่เราเลือก
การทำงานกับข้อมูลแคช
จากฐานข้อมูลผลลัพธ์ของ IEF เราสามารถดึงข้อมูลเพิ่มเติมที่ IEF ไม่จำเป็นต้องรองรับ เราสามารถดึงข้อมูลแคชผลิตภัณฑ์ bi สำหรับข้อมูลจากผู้ให้บริการอีเมลเช่น Yahoo, Google ฯลฯ โดยใช้ฐานข้อมูลผลลัพธ์ IEF
ต่อไปนี้เป็นสคริปต์ Python สำหรับเข้าถึงข้อมูลแคชจาก Yahoo mail ซึ่งเข้าถึงได้จาก Google Chrome โดยใช้ฐานข้อมูล IEF โปรดทราบว่าขั้นตอนต่างๆจะมากหรือน้อยเหมือนกับที่ทำตามในสคริปต์ Python สุดท้าย
ขั้นแรกให้นำเข้าไลบรารีที่จำเป็นสำหรับ Python ดังนี้ -
from __future__ import print_function
import argparse
import csv
import os
import sqlite3
import sys
import json
ตอนนี้ให้เส้นทางไปยังไฟล์ฐานข้อมูล IEF พร้อมกับอาร์กิวเมนต์ตำแหน่งสองตัวที่ตัวจัดการบรรทัดคำสั่งยอมรับตามที่ทำในสคริปต์สุดท้าย -
if __name__ == '__main__':
parser = argparse.ArgumentParser('IEF to CSV')
parser.add_argument("IEF_DATABASE", help="Input IEF database")
parser.add_argument("OUTPUT_DIR", help="Output DIR")
args = parser.parse_args()
ตอนนี้ยืนยันการมีอยู่ของฐานข้อมูล IEF ดังนี้ -
directory = os.path.dirname(args.OUTPUT_CSV)
if not os.path.exists(directory):os.makedirs(directory)
if os.path.exists(args.IEF_DATABASE) and \ os.path.isfile(args.IEF_DATABASE):
main(args.IEF_DATABASE, args.OUTPUT_CSV)
else: print("Supplied input file {} does not exist or is not a " "file".format(args.IEF_DATABASE))
sys.exit(1)
ตอนนี้ทำการเชื่อมต่อกับฐานข้อมูล SQLite ดังต่อไปนี้เพื่อดำเนินการค้นหาผ่านเคอร์เซอร์ -
def main(database, out_csv):
print("[+] Connecting to SQLite database")
conn = sqlite3.connect(database)
c = conn.cursor()
คุณสามารถใช้โค้ดบรรทัดต่อไปนี้เพื่อดึงอินสแตนซ์ของบันทึกแคชของผู้ติดต่อ Yahoo Mail -
print("Querying IEF database for Yahoo Contact Fragments from " "the Chrome Cache Records Table")
try:
c.execute("select * from 'Chrome Cache Records' where URL like " "'https://data.mail.yahoo.com" "/classicab/v2/contacts/?format=json%'")
except sqlite3.OperationalError:
print("Received an error querying the database -- database may be" "corrupt or not have a Chrome Cache Records table")
sys.exit(2)
ตอนนี้รายการสิ่งที่ส่งคืนจากแบบสอบถามด้านบนจะถูกบันทึกลงในตัวแปรดังนี้ -
contact_cache = c.fetchall()
contact_data = process_contacts(contact_cache)
write_csv(contact_data, out_csv)
โปรดทราบว่าที่นี่เราจะใช้สองวิธีคือ process_contacts() สำหรับการตั้งค่ารายการผลลัพธ์ตลอดจนการทำซ้ำผ่านระเบียนแคชของผู้ติดต่อแต่ละรายการและ json.loads() เพื่อจัดเก็บข้อมูล JSON ที่ดึงมาจากตารางลงในตัวแปรสำหรับการจัดการเพิ่มเติม -
def process_contacts(contact_cache):
print("[+] Processing {} cache files matching Yahoo contact cache " " data".format(len(contact_cache)))
results = []
for contact in contact_cache:
url = contact[0]
first_visit = contact[1]
last_visit = contact[2]
last_sync = contact[3]
loc = contact[8]
contact_json = json.loads(contact[7].decode())
total_contacts = contact_json["total"]
total_count = contact_json["count"]
if "contacts" not in contact_json:
continue
for c in contact_json["contacts"]:
name, anni, bday, emails, phones, links = ("", "", "", "", "", "")
if "name" in c:
name = c["name"]["givenName"] + " " + \ c["name"]["middleName"] + " " + c["name"]["familyName"]
if "anniversary" in c:
anni = c["anniversary"]["month"] + \"/" + c["anniversary"]["day"] + "/" + \c["anniversary"]["year"]
if "birthday" in c:
bday = c["birthday"]["month"] + "/" + \c["birthday"]["day"] + "/" + c["birthday"]["year"]
if "emails" in c:
emails = ', '.join([x["ep"] for x in c["emails"]])
if "phones" in c:
phones = ', '.join([x["ep"] for x in c["phones"]])
if "links" in c:
links = ', '.join([x["ep"] for x in c["links"]])
ตอนนี้สำหรับ บริษัท ชื่อและบันทึกจะใช้วิธีการรับดังที่แสดงด้านล่าง -
company = c.get("company", "")
title = c.get("jobTitle", "")
notes = c.get("notes", "")
ตอนนี้ให้เราผนวกรายการข้อมูลเมตาและแยกองค์ประกอบข้อมูลในรายการผลลัพธ์ดังนี้ -
results.append([url, first_visit, last_visit, last_sync, loc, name, bday,anni, emails, phones, links, company, title, notes,total_contacts, total_count])
return results
ตอนนี้โดยใช้ CSV_Writer() วิธีการเราจะเขียนเนื้อหาในไฟล์ CSV -
def write_csv(data, output):
print("[+] Writing {} contacts to {}".format(len(data), output))
with open(output, "w", newline="") as csvfile:
csv_writer = csv.writer(csvfile)
csv_writer.writerow([
"URL", "First Visit (UTC)", "Last Visit (UTC)",
"Last Sync (UTC)", "Location", "Contact Name", "Bday",
"Anniversary", "Emails", "Phones", "Links", "Company", "Title",
"Notes", "Total Contacts", "Count of Contacts in Cache"])
csv_writer.writerows(data)
ด้วยความช่วยเหลือของสคริปต์ข้างต้นเราสามารถประมวลผลข้อมูลแคชจาก Yahoo mail โดยใช้ฐานข้อมูล IEF
บทก่อนหน้านี้เกี่ยวกับแนวคิดบางประการของนิติเครือข่ายโดยใช้ Python ในบทนี้ให้เราเข้าใจนิติเครือข่ายโดยใช้ Python ในระดับที่ลึกขึ้น
การเก็บรักษาหน้าเว็บด้วยซุปที่สวยงาม
เวิลด์ไวด์เว็บ (WWW) เป็นแหล่งข้อมูลเฉพาะ อย่างไรก็ตามมรดกมีความเสี่ยงสูงเนื่องจากเนื้อหาสูญหายในอัตราที่น่าตกใจ มรดกทางวัฒนธรรมและสถาบันการศึกษาองค์กรไม่แสวงหาผลกำไรและธุรกิจเอกชนหลายแห่งได้สำรวจปัญหาที่เกี่ยวข้องและมีส่วนร่วมในการพัฒนาโซลูชันทางเทคนิคสำหรับการจัดเก็บถาวรบนเว็บ
การเก็บรักษาหน้าเว็บหรือการเก็บถาวรเว็บเป็นกระบวนการรวบรวมข้อมูลจากเวิลด์ไวด์เว็บเพื่อให้แน่ใจว่าข้อมูลจะถูกเก็บรักษาไว้ในที่เก็บถาวรและทำให้สามารถใช้งานได้สำหรับนักวิจัยนักประวัติศาสตร์และสาธารณชนในอนาคต ก่อนที่จะดำเนินการต่อในการเก็บรักษาหน้าเว็บให้เราหารือเกี่ยวกับประเด็นสำคัญบางประการที่เกี่ยวข้องกับการเก็บรักษาหน้าเว็บตามที่ระบุด้านล่าง -
Change in Web Resources - ทรัพยากรบนเว็บมีการเปลี่ยนแปลงทุกวันซึ่งเป็นความท้าทายสำหรับการรักษาหน้าเว็บ
Large Quantity of Resources - อีกปัญหาหนึ่งที่เกี่ยวข้องกับการเก็บรักษาหน้าเว็บคือทรัพยากรจำนวนมากที่จะต้องเก็บรักษาไว้
Integrity - หน้าเว็บจะต้องได้รับการปกป้องจากการแก้ไขการลบหรือการลบโดยไม่ได้รับอนุญาตเพื่อปกป้องความสมบูรณ์
Dealing with multimedia data - ในขณะที่รักษาหน้าเว็บเราจำเป็นต้องจัดการกับข้อมูลมัลติมีเดียด้วยและสิ่งเหล่านี้อาจทำให้เกิดปัญหาในขณะที่ทำเช่นนั้น
Providing access - นอกจากการรักษาแล้วปัญหาของการให้การเข้าถึงทรัพยากรบนเว็บและการจัดการกับปัญหาการเป็นเจ้าของก็ต้องได้รับการแก้ไขเช่นกัน
ในบทนี้เราจะใช้ไลบรารี Python ที่ชื่อ Beautiful Soup สำหรับการเก็บรักษาหน้าเว็บ
Beautiful Soup คืออะไร?
Beautiful Soup เป็นไลบรารี Python สำหรับดึงข้อมูลออกจากไฟล์ HTML และ XML สามารถใช้กับurlibเนื่องจากต้องมีอินพุต (เอกสารหรือ url) เพื่อสร้างวัตถุซุปเนื่องจากไม่สามารถดึงข้อมูลหน้าเว็บได้ คุณสามารถเรียนรู้โดยละเอียดเกี่ยวกับเรื่องนี้ได้ที่www.crummy.com/software/BeautifulSoup/bs4/doc/
โปรดทราบว่าก่อนใช้งานเราต้องติดตั้งไลบรารีของบุคคลที่สามโดยใช้คำสั่งต่อไปนี้ -
pip install bs4
จากนั้นใช้ตัวจัดการแพ็คเกจ Anaconda เราสามารถติดตั้ง Beautiful Soup ได้ดังนี้ -
conda install -c anaconda beautifulsoup4
Python Script สำหรับการรักษาหน้าเว็บ
สคริปต์ Python สำหรับการรักษาหน้าเว็บโดยใช้ไลบรารีของบุคคลที่สามที่เรียกว่า Beautiful Soup จะกล่าวถึงที่นี่ -
ขั้นแรกให้นำเข้าไลบรารีที่ต้องการดังนี้ -
from __future__ import print_function
import argparse
from bs4 import BeautifulSoup, SoupStrainer
from datetime import datetime
import hashlib
import logging
import os
import ssl
import sys
from urllib.request import urlopen
import urllib.error
logger = logging.getLogger(__name__)
โปรดทราบว่าสคริปต์นี้จะใช้อาร์กิวเมนต์ตำแหน่งสองอาร์กิวเมนต์หนึ่งคือ URL ซึ่งจะถูกเก็บรักษาและอื่น ๆ คือไดเร็กทอรีเอาต์พุตที่ต้องการดังที่แสดงด้านล่าง -
if __name__ == "__main__":
parser = argparse.ArgumentParser('Web Page preservation')
parser.add_argument("DOMAIN", help="Website Domain")
parser.add_argument("OUTPUT_DIR", help="Preservation Output Directory")
parser.add_argument("-l", help="Log file path",
default=__file__[:-3] + ".log")
args = parser.parse_args()
ตอนนี้ตั้งค่าการบันทึกสำหรับสคริปต์โดยระบุไฟล์และตัวจัดการสตรีมสำหรับการวนซ้ำและบันทึกขั้นตอนการได้มาดังที่แสดง -
logger.setLevel(logging.DEBUG)
msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-10s""%(levelname)-8s %(message)s")
strhndl = logging.StreamHandler(sys.stderr)
strhndl.setFormatter(fmt=msg_fmt)
fhndl = logging.FileHandler(args.l, mode='a')
fhndl.setFormatter(fmt=msg_fmt)
logger.addHandler(strhndl)
logger.addHandler(fhndl)
logger.info("Starting BS Preservation")
logger.debug("Supplied arguments: {}".format(sys.argv[1:]))
logger.debug("System " + sys.platform)
logger.debug("Version " + sys.version)
ตอนนี้ให้เราทำการตรวจสอบอินพุตบนไดเร็กทอรีเอาต์พุตที่ต้องการดังนี้ -
if not os.path.exists(args.OUTPUT_DIR):
os.makedirs(args.OUTPUT_DIR)
main(args.DOMAIN, args.OUTPUT_DIR)
ตอนนี้เราจะกำหนด main() ซึ่งจะดึงชื่อฐานของเว็บไซต์ออกโดยลบองค์ประกอบที่ไม่จำเป็นก่อนชื่อจริงพร้อมกับการตรวจสอบความถูกต้องเพิ่มเติมเกี่ยวกับ URL อินพุตดังนี้ -
def main(website, output_dir):
base_name = website.replace("https://", "").replace("http://", "").replace("www.", "")
link_queue = set()
if "http://" not in website and "https://" not in website:
logger.error("Exiting preservation - invalid user input: {}".format(website))
sys.exit(1)
logger.info("Accessing {} webpage".format(website))
context = ssl._create_unverified_context()
ตอนนี้เราต้องเปิดการเชื่อมต่อกับ URL โดยใช้ urlopen () method ให้เราใช้ try-except block ดังนี้ -
try:
index = urlopen(website, context=context).read().decode("utf-8")
except urllib.error.HTTPError as e:
logger.error("Exiting preservation - unable to access page: {}".format(website))
sys.exit(2)
logger.debug("Successfully accessed {}".format(website))
บรรทัดถัดไปของโค้ดประกอบด้วยฟังก์ชันสามอย่างตามที่อธิบายไว้ด้านล่าง -
write_output() เพื่อเขียนเว็บเพจแรกไปยังไดเร็กทอรีเอาต์พุต
find_links() ฟังก์ชันเพื่อระบุลิงก์ในหน้าเว็บนี้
recurse_pages() ทำหน้าที่วนซ้ำและค้นหาลิงก์ทั้งหมดบนหน้าเว็บ
write_output(website, index, output_dir)
link_queue = find_links(base_name, index, link_queue)
logger.info("Found {} initial links on webpage".format(len(link_queue)))
recurse_pages(website, link_queue, context, output_dir)
logger.info("Completed preservation of {}".format(website))
ตอนนี้ให้เรากำหนด write_output() วิธีการดังนี้ -
def write_output(name, data, output_dir, counter=0):
name = name.replace("http://", "").replace("https://", "").rstrip("//")
directory = os.path.join(output_dir, os.path.dirname(name))
if not os.path.exists(directory) and os.path.dirname(name) != "":
os.makedirs(directory)
เราจำเป็นต้องบันทึกรายละเอียดบางอย่างเกี่ยวกับหน้าเว็บจากนั้นเราจึงบันทึกแฮชของข้อมูลโดยใช้ hash_data() วิธีการดังนี้ -
logger.debug("Writing {} to {}".format(name, output_dir)) logger.debug("Data Hash: {}".format(hash_data(data)))
path = os.path.join(output_dir, name)
path = path + "_" + str(counter)
with open(path, "w") as outfile:
outfile.write(data)
logger.debug("Output File Hash: {}".format(hash_file(path)))
ตอนนี้กำหนด hash_data() วิธีการด้วยความช่วยเหลือซึ่งเราอ่านไฟล์ UTF-8 ข้อมูลที่เข้ารหัสแล้วสร้างไฟล์ SHA-256 แฮชของมันดังนี้ -
def hash_data(data):
sha256 = hashlib.sha256()
sha256.update(data.encode("utf-8"))
return sha256.hexdigest()
def hash_file(file):
sha256 = hashlib.sha256()
with open(file, "rb") as in_file:
sha256.update(in_file.read())
return sha256.hexdigest()
ตอนนี้ให้เราสร้างไฟล์ Beautifulsoup ออกจากข้อมูลหน้าเว็บภายใต้ find_links() วิธีการดังนี้ -
def find_links(website, page, queue):
for link in BeautifulSoup(page, "html.parser",parse_only = SoupStrainer("a", href = True)):
if website in link.get("href"):
if not os.path.basename(link.get("href")).startswith("#"):
queue.add(link.get("href"))
return queue
ตอนนี้เราต้องกำหนด recurse_pages() โดยระบุอินพุตของ URL เว็บไซต์คิวลิงก์ปัจจุบันบริบท SSL ที่ไม่ได้รับการยืนยันและไดเร็กทอรีเอาต์พุตดังต่อไปนี้ -
def recurse_pages(website, queue, context, output_dir):
processed = []
counter = 0
while True:
counter += 1
if len(processed) == len(queue):
break
for link in queue.copy(): if link in processed:
continue
processed.append(link)
try:
page = urlopen(link, context=context).read().decode("utf-8")
except urllib.error.HTTPError as e:
msg = "Error accessing webpage: {}".format(link)
logger.error(msg)
continue
ตอนนี้เขียนผลลัพธ์ของแต่ละหน้าเว็บที่เข้าถึงในไฟล์โดยส่งชื่อลิงค์ข้อมูลเพจไดเร็กทอรีเอาต์พุตและตัวนับดังนี้ -
write_output(link, page, output_dir, counter)
queue = find_links(website, page, queue)
logger.info("Identified {} links throughout website".format(
len(queue)))
ตอนนี้เมื่อเราเรียกใช้สคริปต์นี้โดยระบุ URL ของเว็บไซต์ไดเรกทอรีผลลัพธ์และเส้นทางไปยังไฟล์บันทึกเราจะได้รับรายละเอียดเกี่ยวกับหน้าเว็บนั้นที่สามารถใช้เพื่อใช้ในอนาคตได้
การล่าไวรัส
คุณเคยสงสัยหรือไม่ว่านักวิเคราะห์ทางนิติวิทยาศาสตร์นักวิจัยด้านความปลอดภัยและผู้ตอบเหตุการณ์สามารถเข้าใจความแตกต่างระหว่างซอฟต์แวร์และมัลแวร์ที่มีประโยชน์ได้อย่างไร คำตอบอยู่ในคำถามนั้นเองเนื่องจากหากไม่ได้ศึกษาเกี่ยวกับมัลแวร์ที่แฮกเกอร์สร้างขึ้นอย่างรวดเร็วจึงเป็นไปไม่ได้เลยที่นักวิจัยและผู้เชี่ยวชาญจะบอกความแตกต่างระหว่างซอฟต์แวร์ที่มีประโยชน์และมัลแวร์ ในส่วนนี้ให้เราพูดคุยเกี่ยวกับVirusShareซึ่งเป็นเครื่องมือในการทำงานนี้ให้สำเร็จ
ทำความเข้าใจเกี่ยวกับ VirusShare
VirusShare เป็นคอลเล็กชันตัวอย่างมัลแวร์ที่เป็นของเอกชนที่ใหญ่ที่สุดเพื่อให้นักวิจัยด้านความปลอดภัยผู้เผชิญเหตุและนักวิเคราะห์ทางนิติวิทยาศาสตร์ได้ทดลองใช้โค้ดที่เป็นอันตราย มีมากกว่า 30 ล้านตัวอย่าง
ประโยชน์ของ VirusShare คือรายการแฮชมัลแวร์ที่พร้อมใช้งานฟรี ทุกคนสามารถใช้แฮชเหล่านี้เพื่อสร้างชุดแฮชที่ครอบคลุมมากและใช้เพื่อระบุไฟล์ที่อาจเป็นอันตราย แต่ก่อนที่จะใช้ VirusShare เราขอแนะนำให้คุณเข้าไปที่https://virusshare.com สำหรับรายละเอียดเพิ่มเติม
การสร้าง Newline-Delimited Hash List จาก VirusShare โดยใช้ Python
รายการแฮชจาก VirusShare สามารถใช้โดยเครื่องมือทางนิติวิทยาศาสตร์ต่างๆเช่น X-ways และ EnCase ในสคริปต์ที่กล่าวถึงด้านล่างเราจะทำการดาวน์โหลดรายการแฮชจาก VirusShare โดยอัตโนมัติเพื่อสร้างรายการแฮชที่คั่นด้วยบรรทัดใหม่
สำหรับสคริปต์นี้เราต้องการไลบรารี Python ของบุคคลที่สาม tqdm ซึ่งสามารถดาวน์โหลดได้ดังนี้ -
pip install tqdm
โปรดทราบว่าในสคริปต์นี้อันดับแรกเราจะอ่านหน้าแฮช VirusShare และระบุรายการแฮชล่าสุดแบบไดนามิก จากนั้นเราจะเริ่มต้นแถบความคืบหน้าและดาวน์โหลดรายการแฮชในช่วงที่ต้องการ
ก่อนอื่นให้นำเข้าไลบรารีต่อไปนี้ -
from __future__ import print_function
import argparse
import os
import ssl
import sys
import tqdm
from urllib.request import urlopen
import urllib.error
สคริปต์นี้จะใช้อาร์กิวเมนต์ตำแหน่งหนึ่งซึ่งจะเป็นเส้นทางที่ต้องการสำหรับชุดแฮช -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Hash set from VirusShare')
parser.add_argument("OUTPUT_HASH", help = "Output Hashset")
parser.add_argument("--start", type = int, help = "Optional starting location")
args = parser.parse_args()
ตอนนี้เราจะดำเนินการตรวจสอบอินพุตมาตรฐานดังต่อไปนี้ -
directory = os.path.dirname(args.OUTPUT_HASH)
if not os.path.exists(directory):
os.makedirs(directory)
if args.start:
main(args.OUTPUT_HASH, start=args.start)
else:
main(args.OUTPUT_HASH)
ตอนนี้เราต้องกำหนด main() ฟังก์ชั่นกับ **kwargs เป็นอาร์กิวเมนต์เนื่องจากสิ่งนี้จะสร้างพจนานุกรมที่เราสามารถอ้างถึงการสนับสนุนอาร์กิวเมนต์สำคัญที่ให้มาดังที่แสดงด้านล่าง -
def main(hashset, **kwargs):
url = "https://virusshare.com/hashes.4n6"
print("[+] Identifying hash set range from {}".format(url))
context = ssl._create_unverified_context()
ตอนนี้เราต้องเปิดหน้าแฮช VirusShare โดยใช้ไฟล์ urlib.request.urlopen()วิธี. เราจะใช้ try-except block ดังต่อไปนี้ -
try:
index = urlopen(url, context = context).read().decode("utf-8")
except urllib.error.HTTPError as e:
print("[-] Error accessing webpage - exiting..")
sys.exit(1)
ตอนนี้ระบุรายการแฮชล่าสุดจากหน้าที่ดาวน์โหลด คุณสามารถทำได้โดยค้นหาอินสแตนซ์สุดท้ายของ HTMLhrefแท็กไปยังรายการแฮช VirusShare สามารถทำได้โดยใช้โค้ดบรรทัดต่อไปนี้ -
tag = index.rfind(r'a href = "hashes/VirusShare_')
stop = int(index[tag + 27: tag + 27 + 5].lstrip("0"))
if "start" not in kwa<rgs:
start = 0
else:
start = kwargs["start"]
if start < 0 or start > stop:
print("[-] Supplied start argument must be greater than or equal ""to zero but less than the latest hash list, ""currently: {}".format(stop))
sys.exit(2)
print("[+] Creating a hashset from hash lists {} to {}".format(start, stop))
hashes_downloaded = 0
ตอนนี้เราจะใช้ tqdm.trange() วิธีการสร้างลูปและแถบความคืบหน้าดังนี้ -
for x in tqdm.trange(start, stop + 1, unit_scale=True,desc="Progress"):
url_hash = "https://virusshare.com/hashes/VirusShare_"\"{}.md5".format(str(x).zfill(5))
try:
hashes = urlopen(url_hash, context=context).read().decode("utf-8")
hashes_list = hashes.split("\n")
except urllib.error.HTTPError as e:
print("[-] Error accessing webpage for hash list {}"" - continuing..".format(x))
continue
หลังจากทำตามขั้นตอนข้างต้นเรียบร้อยแล้วเราจะเปิดไฟล์ข้อความชุดแฮชในโหมด + เพื่อต่อท้ายไฟล์ข้อความ
with open(hashset, "a+") as hashfile:
for line in hashes_list:
if not line.startswith("#") and line != "":
hashes_downloaded += 1
hashfile.write(line + '\n')
print("[+] Finished downloading {} hashes into {}".format(
hashes_downloaded, hashset))
หลังจากเรียกใช้สคริปต์ข้างต้นคุณจะได้รับรายการแฮชล่าสุดที่มีค่าแฮช MD5 ในรูปแบบข้อความ
บทก่อนหน้านี้ได้กล่าวถึงความสำคัญและกระบวนการของนิติเครือข่ายและแนวคิดที่เกี่ยวข้อง ในบทนี้ให้เราเรียนรู้เกี่ยวกับบทบาทของอีเมลในนิติดิจิทัลและการตรวจสอบโดยใช้ Python
บทบาทของอีเมลในการตรวจสอบ
อีเมลมีบทบาทสำคัญมากในการสื่อสารทางธุรกิจและกลายเป็นหนึ่งในแอปพลิเคชันที่สำคัญที่สุดบนอินเทอร์เน็ต เป็นโหมดที่สะดวกสำหรับการส่งข้อความและเอกสารไม่เพียง แต่จากคอมพิวเตอร์เท่านั้น แต่ยังรวมถึงอุปกรณ์อิเล็กทรอนิกส์อื่น ๆ เช่นโทรศัพท์มือถือและแท็บเล็ต
ด้านลบของอีเมลคืออาชญากรอาจรั่วไหลข้อมูลสำคัญเกี่ยวกับ บริษัท ของพวกเขา ดังนั้นบทบาทของอีเมลในนิติดิจิทัลจึงเพิ่มขึ้นในช่วงไม่กี่ปีที่ผ่านมา ในทางนิติวิทยาศาสตร์อีเมลถือเป็นหลักฐานสำคัญและการวิเคราะห์ส่วนหัวอีเมลกลายเป็นสิ่งสำคัญในการรวบรวมหลักฐานในระหว่างกระบวนการทางนิติวิทยาศาสตร์
ผู้ตรวจสอบมีเป้าหมายดังต่อไปนี้ในขณะที่ดำเนินการทางอีเมล -
- เพื่อระบุตัวคนร้ายหลัก
- เพื่อรวบรวมหลักฐานที่จำเป็น
- เพื่อนำเสนอข้อค้นพบ
- เพื่อสร้างเคส
ความท้าทายในนิติอีเมล
นิติเวชอีเมลมีบทบาทสำคัญมากในการตรวจสอบเนื่องจากการสื่อสารส่วนใหญ่ในยุคปัจจุบันต้องอาศัยอีเมล อย่างไรก็ตามผู้ตรวจสอบทางนิติวิทยาศาสตร์ทางอีเมลอาจเผชิญกับความท้าทายต่อไปนี้ในระหว่างการสอบสวน -
อีเมลปลอม
ความท้าทายที่ยิ่งใหญ่ที่สุดในการพิสูจน์หลักฐานทางอีเมลคือการใช้อีเมลปลอมที่สร้างขึ้นโดยการจัดการและการเขียนสคริปต์ส่วนหัวเป็นต้นอาชญากรประเภทนี้ยังใช้อีเมลชั่วคราวซึ่งเป็นบริการที่อนุญาตให้ผู้ใช้ที่ลงทะเบียนรับอีเมลตามที่อยู่ชั่วคราวที่หมดอายุ หลังจากช่วงเวลาหนึ่ง
การปลอมแปลง
ความท้าทายอีกประการหนึ่งในการพิสูจน์หลักฐานทางอีเมลคือการปลอมแปลงซึ่งอาชญากรใช้ในการนำเสนออีเมลเป็นของคนอื่น ในกรณีนี้เครื่องจะได้รับทั้งที่อยู่ IP ปลอมและที่อยู่เดิม
การส่งอีเมลซ้ำแบบไม่ระบุตัวตน
ที่นี่เซิร์ฟเวอร์อีเมลจะดึงข้อมูลการระบุตัวตนจากข้อความอีเมลก่อนที่จะส่งต่อต่อไป สิ่งนี้นำไปสู่ความท้าทายครั้งใหญ่อีกครั้งสำหรับการตรวจสอบอีเมล
เทคนิคที่ใช้ในการตรวจสอบทางนิติวิทยาศาสตร์ทางอีเมล
นิติอีเมลคือการศึกษาแหล่งที่มาและเนื้อหาของอีเมลเพื่อเป็นหลักฐานในการระบุผู้ส่งและผู้รับที่แท้จริงของข้อความพร้อมกับข้อมูลอื่น ๆ เช่นวันที่ / เวลาในการส่งและความตั้งใจของผู้ส่ง เกี่ยวข้องกับการตรวจสอบข้อมูลเมตาการสแกนพอร์ตและการค้นหาคำหลัก
เทคนิคทั่วไปบางประการที่สามารถใช้สำหรับการตรวจสอบทางนิติวิทยาศาสตร์ทางอีเมล ได้แก่
- การวิเคราะห์ส่วนหัว
- การตรวจสอบเซิร์ฟเวอร์
- การตรวจสอบอุปกรณ์เครือข่าย
- ลายนิ้วมือของผู้ส่งจดหมาย
- Software Embedded Identifiers
ในส่วนต่อไปนี้เราจะเรียนรู้วิธีดึงข้อมูลโดยใช้ Python เพื่อจุดประสงค์ในการตรวจสอบอีเมล
การแยกข้อมูลจากไฟล์ EML
ไฟล์ EML เป็นอีเมลในรูปแบบไฟล์ซึ่งใช้กันอย่างแพร่หลายในการจัดเก็บข้อความอีเมล ไฟล์เหล่านี้เป็นไฟล์ข้อความที่มีโครงสร้างซึ่งเข้ากันได้กับไคลเอนต์อีเมลหลายตัวเช่น Microsoft Outlook, Outlook Express และ Windows Live Mail
ไฟล์ EML เก็บส่วนหัวของอีเมลเนื้อหาเนื้อหาข้อมูลไฟล์แนบเป็นข้อความธรรมดา ใช้ base64 เพื่อเข้ารหัสข้อมูลไบนารีและการเข้ารหัส Quoted-Printable (QP) เพื่อจัดเก็บข้อมูลเนื้อหา สคริปต์ Python ที่สามารถใช้ดึงข้อมูลจากไฟล์ EML ได้รับด้านล่าง -
ขั้นแรกให้นำเข้าไลบรารี Python ต่อไปนี้ตามที่แสดงด้านล่าง -
from __future__ import print_function
from argparse import ArgumentParser, FileType
from email import message_from_file
import os
import quopri
import base64
ในไลบรารีข้างต้น quopriใช้เพื่อถอดรหัสค่าที่เข้ารหัส QP จากไฟล์ EML ข้อมูลที่เข้ารหัส base64 ใด ๆ สามารถถอดรหัสได้ด้วยความช่วยเหลือของbase64 ห้องสมุด.
ต่อไปให้เราจัดเตรียมอาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง โปรดทราบว่าที่นี่จะยอมรับเพียงอาร์กิวเมนต์เดียวซึ่งจะเป็นเส้นทางไปยังไฟล์ EML ดังที่แสดงด้านล่าง -
if __name__ == '__main__':
parser = ArgumentParser('Extracting information from EML file')
parser.add_argument("EML_FILE",help="Path to EML File", type=FileType('r'))
args = parser.parse_args()
main(args.EML_FILE)
ตอนนี้เราต้องกำหนด main() ซึ่งเราจะใช้เมธอดชื่อ message_from_file()จากไลบรารีอีเมลเพื่ออ่านไฟล์เช่น object ที่นี่เราจะเข้าถึงส่วนหัวเนื้อหาเนื้อหาไฟล์แนบและข้อมูลเพย์โหลดอื่น ๆ โดยใช้ตัวแปรผลลัพธ์ที่ชื่อemlfile ดังแสดงในรหัสที่ระบุด้านล่าง -
def main(input_file):
emlfile = message_from_file(input_file)
for key, value in emlfile._headers:
print("{}: {}".format(key, value))
print("\nBody\n")
if emlfile.is_multipart():
for part in emlfile.get_payload():
process_payload(part)
else:
process_payload(emlfile[1])
ตอนนี้เราต้องกำหนด process_payload() วิธีการที่เราจะแยกเนื้อหาของข้อความโดยใช้ get_payload()วิธี. เราจะถอดรหัสข้อมูลที่เข้ารหัส QP โดยใช้ไฟล์quopri.decodestring()ฟังก์ชัน นอกจากนี้เราจะตรวจสอบประเภท MIME ของเนื้อหาเพื่อให้สามารถจัดการการจัดเก็บอีเมลได้อย่างถูกต้อง สังเกตรหัสที่ระบุด้านล่าง -
def process_payload(payload):
print(payload.get_content_type() + "\n" + "=" * len(payload.get_content_type()))
body = quopri.decodestring(payload.get_payload())
if payload.get_charset():
body = body.decode(payload.get_charset())
else:
try:
body = body.decode()
except UnicodeDecodeError:
body = body.decode('cp1252')
if payload.get_content_type() == "text/html":
outfile = os.path.basename(args.EML_FILE.name) + ".html"
open(outfile, 'w').write(body)
elif payload.get_content_type().startswith('application'):
outfile = open(payload.get_filename(), 'wb')
body = base64.b64decode(payload.get_payload())
outfile.write(body)
outfile.close()
print("Exported: {}\n".format(outfile.name))
else:
print(body)
หลังจากเรียกใช้สคริปต์ข้างต้นแล้วเราจะได้รับข้อมูลส่วนหัวพร้อมกับเพย์โหลดต่างๆบนคอนโซล
การวิเคราะห์ไฟล์ MSG โดยใช้ Python
ข้อความอีเมลมีหลายรูปแบบ MSG เป็นรูปแบบหนึ่งที่ Microsoft Outlook และ Exchange ใช้ ไฟล์ที่มีนามสกุล MSG อาจมีข้อความ ASCII ธรรมดาสำหรับส่วนหัวและเนื้อหาของข้อความหลักตลอดจนไฮเปอร์ลิงก์และไฟล์แนบ
ในส่วนนี้เราจะเรียนรู้วิธีดึงข้อมูลจากไฟล์ MSG โดยใช้ Outlook API โปรดทราบว่าสคริปต์ Python ต่อไปนี้จะใช้ได้กับ Windows เท่านั้น สำหรับสิ่งนี้เราต้องติดตั้งไลบรารี Python ของบุคคลที่สามที่ชื่อpywin32 ดังต่อไปนี้ -
pip install pywin32
ตอนนี้นำเข้าไลบรารีต่อไปนี้โดยใช้คำสั่งที่แสดง -
from __future__ import print_function
from argparse import ArgumentParser
import os
import win32com.client
import pywintypes
ตอนนี้ให้เราระบุอาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสองอาร์กิวเมนต์หนึ่งจะเป็นพา ธ ไปยังไฟล์ MSG และอื่น ๆ จะเป็นโฟลเดอร์ผลลัพธ์ที่ต้องการดังนี้ -
if __name__ == '__main__':
parser = ArgumentParser(‘Extracting information from MSG file’)
parser.add_argument("MSG_FILE", help="Path to MSG file")
parser.add_argument("OUTPUT_DIR", help="Path to output folder")
args = parser.parse_args()
out_dir = args.OUTPUT_DIR
if not os.path.exists(out_dir):
os.makedirs(out_dir)
main(args.MSG_FILE, args.OUTPUT_DIR)
ตอนนี้เราต้องกำหนด main() ฟังก์ชันที่เราจะเรียกใช้ win32com ห้องสมุดสำหรับการตั้งค่า Outlook API ซึ่งช่วยให้เข้าถึงไฟล์ MAPI เนมสเปซ
def main(msg_file, output_dir):
mapi = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
msg = mapi.OpenSharedItem(os.path.abspath(args.MSG_FILE))
display_msg_attribs(msg)
display_msg_recipients(msg)
extract_msg_body(msg, output_dir)
extract_attachments(msg, output_dir)
ตอนนี้กำหนดฟังก์ชันต่างๆที่เราใช้ในสคริปต์นี้ รหัสที่ระบุด้านล่างแสดงการกำหนดไฟล์display_msg_attribs() ฟังก์ชันที่ช่วยให้เราสามารถแสดงคุณลักษณะต่างๆของข้อความเช่น subject, to, BCC, CC, Size, SenderName, send เป็นต้น
def display_msg_attribs(msg):
attribs = [
'Application', 'AutoForwarded', 'BCC', 'CC', 'Class',
'ConversationID', 'ConversationTopic', 'CreationTime',
'ExpiryTime', 'Importance', 'InternetCodePage', 'IsMarkedAsTask',
'LastModificationTime', 'Links','ReceivedTime', 'ReminderSet',
'ReminderTime', 'ReplyRecipientNames', 'Saved', 'Sender',
'SenderEmailAddress', 'SenderEmailType', 'SenderName', 'Sent',
'SentOn', 'SentOnBehalfOfName', 'Size', 'Subject',
'TaskCompletedDate', 'TaskDueDate', 'To', 'UnRead'
]
print("\nMessage Attributes")
for entry in attribs:
print("{}: {}".format(entry, getattr(msg, entry, 'N/A')))
ตอนนี้กำหนด display_msg_recipeints() ฟังก์ชันที่วนซ้ำผ่านข้อความและแสดงรายละเอียดผู้รับ
def display_msg_recipients(msg):
recipient_attrib = ['Address', 'AutoResponse', 'Name', 'Resolved', 'Sendable']
i = 1
while True:
try:
recipient = msg.Recipients(i)
except pywintypes.com_error:
break
print("\nRecipient {}".format(i))
print("=" * 15)
for entry in recipient_attrib:
print("{}: {}".format(entry, getattr(recipient, entry, 'N/A')))
i += 1
ต่อไปเราจะกำหนด extract_msg_body() ฟังก์ชันที่แยกเนื้อหาเนื้อหา HTML และข้อความธรรมดาออกจากข้อความ
def extract_msg_body(msg, out_dir):
html_data = msg.HTMLBody.encode('cp1252')
outfile = os.path.join(out_dir, os.path.basename(args.MSG_FILE))
open(outfile + ".body.html", 'wb').write(html_data)
print("Exported: {}".format(outfile + ".body.html"))
body_data = msg.Body.encode('cp1252')
open(outfile + ".body.txt", 'wb').write(body_data)
print("Exported: {}".format(outfile + ".body.txt"))
ต่อไปเราจะกำหนด extract_attachments() ฟังก์ชันที่ส่งออกข้อมูลสิ่งที่แนบไปยังไดเร็กทอรีเอาต์พุตที่ต้องการ
def extract_attachments(msg, out_dir):
attachment_attribs = ['DisplayName', 'FileName', 'PathName', 'Position', 'Size']
i = 1 # Attachments start at 1
while True:
try:
attachment = msg.Attachments(i)
except pywintypes.com_error:
break
เมื่อกำหนดฟังก์ชันทั้งหมดแล้วเราจะพิมพ์แอตทริบิวต์ทั้งหมดไปยังคอนโซลด้วยรหัสบรรทัดต่อไปนี้ -
print("\nAttachment {}".format(i))
print("=" * 15)
for entry in attachment_attribs:
print('{}: {}'.format(entry, getattr(attachment, entry,"N/A")))
outfile = os.path.join(os.path.abspath(out_dir),os.path.split(args.MSG_FILE)[-1])
if not os.path.exists(outfile):
os.makedirs(outfile)
outfile = os.path.join(outfile, attachment.FileName)
attachment.SaveAsFile(outfile)
print("Exported: {}".format(outfile))
i += 1
หลังจากเรียกใช้สคริปต์ข้างต้นเราจะได้รับคุณลักษณะของข้อความและสิ่งที่แนบมาในหน้าต่างคอนโซลพร้อมกับไฟล์ต่างๆในไดเรกทอรีผลลัพธ์
การจัดโครงสร้างไฟล์ MBOX จาก Google Takeout โดยใช้ Python
ไฟล์ MBOX เป็นไฟล์ข้อความที่มีการจัดรูปแบบพิเศษซึ่งแบ่งข้อความที่เก็บไว้ภายใน มักพบในระบบ UNIX, Thunderbolt และ Google Takeouts
ในส่วนนี้คุณจะเห็นสคริปต์ Python ซึ่งเราจะจัดโครงสร้างไฟล์ MBOX ที่ได้รับจาก Google Takeouts แต่ก่อนหน้านั้นเราต้องรู้ว่าเราจะสร้างไฟล์ MBOX เหล่านี้ได้อย่างไรโดยใช้บัญชี Google หรือบัญชี Gmail ของเรา
การรับกล่องจดหมายของบัญชี Google เป็นรูปแบบ MBX
การได้รับกล่องจดหมายบัญชี Google หมายถึงการสำรองข้อมูลบัญชี Gmail ของเรา การสำรองข้อมูลสามารถทำได้ด้วยเหตุผลส่วนตัวหรือทางวิชาชีพต่างๆ โปรดทราบว่า Google ให้การสำรองข้อมูล Gmail ในการรับกล่องจดหมายบัญชี Google ของเราในรูปแบบ MBOX คุณต้องทำตามขั้นตอนด้านล่าง -
เปิด My account แผงควบคุม.
ไปที่ส่วนข้อมูลส่วนบุคคลและความเป็นส่วนตัวแล้วเลือกลิงก์ควบคุมเนื้อหาของคุณ
คุณสามารถสร้างที่เก็บถาวรใหม่หรือสามารถจัดการที่มีอยู่ได้ ถ้าเราคลิกCREATE ARCHIVE จากนั้นเราจะได้รับช่องทำเครื่องหมายสำหรับผลิตภัณฑ์ Google แต่ละรายการที่เราต้องการรวมไว้
หลังจากเลือกผลิตภัณฑ์แล้วเราจะได้รับอิสระในการเลือกประเภทไฟล์และขนาดสูงสุดสำหรับไฟล์เก็บถาวรของเราพร้อมวิธีการจัดส่งเพื่อเลือกจากรายการ
สุดท้ายเราจะได้รับข้อมูลสำรองนี้ในรูปแบบ MBOX
รหัส Python
ตอนนี้ไฟล์ MBOX ที่กล่าวถึงข้างต้นสามารถจัดโครงสร้างโดยใช้ Python ดังที่แสดงด้านล่าง -
ก่อนอื่นต้องนำเข้าไลบรารี Python ดังนี้ -
from __future__ import print_function
from argparse import ArgumentParser
import mailbox
import os
import time
import csv
from tqdm import tqdm
import base64
ไลบรารีทั้งหมดถูกใช้และอธิบายไว้ในสคริปต์ก่อนหน้านี้ยกเว้นไฟล์ mailbox ไลบรารีที่ใช้ในการแยกวิเคราะห์ไฟล์ MBOX
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสองอาร์กิวเมนต์หนึ่งจะเป็นพา ธ ไปยังไฟล์ MBOX และอีกอันจะเป็นโฟลเดอร์ผลลัพธ์ที่ต้องการ
if __name__ == '__main__':
parser = ArgumentParser('Parsing MBOX files')
parser.add_argument("MBOX", help="Path to mbox file")
parser.add_argument(
"OUTPUT_DIR",help = "Path to output directory to write report ""and exported content")
args = parser.parse_args()
main(args.MBOX, args.OUTPUT_DIR)
ตอนนี้จะกำหนด main() ฟังก์ชันและการโทร mbox คลาสของไลบรารีกล่องจดหมายด้วยความช่วยเหลือซึ่งเราสามารถแยกวิเคราะห์ไฟล์ MBOX โดยระบุพา ธ -
def main(mbox_file, output_dir):
print("Reading mbox file")
mbox = mailbox.mbox(mbox_file, factory=custom_reader)
print("{} messages to parse".format(len(mbox)))
ตอนนี้กำหนดวิธีการอ่านสำหรับ mailbox ห้องสมุดดังนี้ -
def custom_reader(data_stream):
data = data_stream.read()
try:
content = data.decode("ascii")
except (UnicodeDecodeError, UnicodeEncodeError) as e:
content = data.decode("cp1252", errors="replace")
return mailbox.mboxMessage(content)
ตอนนี้สร้างตัวแปรสำหรับการประมวลผลเพิ่มเติมดังนี้ -
parsed_data = []
attachments_dir = os.path.join(output_dir, "attachments")
if not os.path.exists(attachments_dir):
os.makedirs(attachments_dir)
columns = [
"Date", "From", "To", "Subject", "X-Gmail-Labels", "Return-Path", "Received",
"Content-Type", "Message-ID","X-GM-THRID", "num_attachments_exported", "export_path"]
ถัดไปใช้ tqdm เพื่อสร้างแถบความคืบหน้าและติดตามกระบวนการทำซ้ำดังนี้ -
for message in tqdm(mbox):
msg_data = dict()
header_data = dict(message._headers)
for hdr in columns:
msg_data[hdr] = header_data.get(hdr, "N/A")
ตอนนี้ตรวจสอบข้อความสภาพอากาศว่ามีน้ำหนักบรรทุกหรือไม่ หากมีแล้วเราจะกำหนดwrite_payload() วิธีการดังนี้ -
if len(message.get_payload()):
export_path = write_payload(message, attachments_dir)
msg_data['num_attachments_exported'] = len(export_path)
msg_data['export_path'] = ", ".join(export_path)
ตอนนี้จำเป็นต้องต่อท้ายข้อมูล แล้วเราจะโทรcreate_report() วิธีการดังนี้ -
parsed_data.append(msg_data)
create_report(
parsed_data, os.path.join(output_dir, "mbox_report.csv"), columns)
def write_payload(msg, out_dir):
pyld = msg.get_payload()
export_path = []
if msg.is_multipart():
for entry in pyld:
export_path += write_payload(entry, out_dir)
else:
content_type = msg.get_content_type()
if "application/" in content_type.lower():
content = base64.b64decode(msg.get_payload())
export_path.append(export_content(msg, out_dir, content))
elif "image/" in content_type.lower():
content = base64.b64decode(msg.get_payload())
export_path.append(export_content(msg, out_dir, content))
elif "video/" in content_type.lower():
content = base64.b64decode(msg.get_payload())
export_path.append(export_content(msg, out_dir, content))
elif "audio/" in content_type.lower():
content = base64.b64decode(msg.get_payload())
export_path.append(export_content(msg, out_dir, content))
elif "text/csv" in content_type.lower():
content = base64.b64decode(msg.get_payload())
export_path.append(export_content(msg, out_dir, content))
elif "info/" in content_type.lower():
export_path.append(export_content(msg, out_dir,
msg.get_payload()))
elif "text/calendar" in content_type.lower():
export_path.append(export_content(msg, out_dir,
msg.get_payload()))
elif "text/rtf" in content_type.lower():
export_path.append(export_content(msg, out_dir,
msg.get_payload()))
else:
if "name=" in msg.get('Content-Disposition', "N/A"):
content = base64.b64decode(msg.get_payload())
export_path.append(export_content(msg, out_dir, content))
elif "name=" in msg.get('Content-Type', "N/A"):
content = base64.b64decode(msg.get_payload())
export_path.append(export_content(msg, out_dir, content))
return export_path
สังเกตว่าข้อความ if-else ข้างต้นเข้าใจง่าย ตอนนี้เราต้องกำหนดวิธีการที่จะแยกชื่อไฟล์จากไฟล์msg วัตถุดังต่อไปนี้ -
def export_content(msg, out_dir, content_data):
file_name = get_filename(msg)
file_ext = "FILE"
if "." in file_name: file_ext = file_name.rsplit(".", 1)[-1]
file_name = "{}_{:.4f}.{}".format(file_name.rsplit(".", 1)[0], time.time(), file_ext)
file_name = os.path.join(out_dir, file_name)
ตอนนี้ด้วยความช่วยเหลือของโค้ดบรรทัดต่อไปนี้คุณสามารถส่งออกไฟล์ได้จริง -
if isinstance(content_data, str):
open(file_name, 'w').write(content_data)
else:
open(file_name, 'wb').write(content_data)
return file_name
ตอนนี้ให้เรากำหนดฟังก์ชันในการแยกชื่อไฟล์จากไฟล์ message เพื่อแสดงชื่อของไฟล์เหล่านี้อย่างถูกต้องดังนี้ -
def get_filename(msg):
if 'name=' in msg.get("Content-Disposition", "N/A"):
fname_data = msg["Content-Disposition"].replace("\r\n", " ")
fname = [x for x in fname_data.split("; ") if 'name=' in x]
file_name = fname[0].split("=", 1)[-1]
elif 'name=' in msg.get("Content-Type", "N/A"):
fname_data = msg["Content-Type"].replace("\r\n", " ")
fname = [x for x in fname_data.split("; ") if 'name=' in x]
file_name = fname[0].split("=", 1)[-1]
else:
file_name = "NO_FILENAME"
fchars = [x for x in file_name if x.isalnum() or x.isspace() or x == "."]
return "".join(fchars)
ตอนนี้เราสามารถเขียนไฟล์ CSV โดยกำหนดไฟล์ create_report() ฟังก์ชันดังต่อไปนี้ -
def create_report(output_data, output_file, columns):
with open(output_file, 'w', newline="") as outfile:
csvfile = csv.DictWriter(outfile, columns)
csvfile.writeheader()
csvfile.writerows(output_data)
เมื่อคุณเรียกใช้สคริปต์ที่ให้ไว้ข้างต้นเราจะได้รับรายงาน CSV และไดเรกทอรีที่เต็มไปด้วยไฟล์แนบ
บทนี้จะอธิบายแนวคิดต่างๆที่เกี่ยวข้องกับการพิสูจน์หลักฐานของ Microsoft Windows และสิ่งประดิษฐ์ที่สำคัญที่ผู้ตรวจสอบสามารถได้รับจากกระบวนการตรวจสอบ
บทนำ
สิ่งประดิษฐ์คือวัตถุหรือพื้นที่ภายในระบบคอมพิวเตอร์ที่มีข้อมูลสำคัญที่เกี่ยวข้องกับกิจกรรมที่ดำเนินการโดยผู้ใช้คอมพิวเตอร์ ประเภทและตำแหน่งของข้อมูลนี้ขึ้นอยู่กับระบบปฏิบัติการ ในระหว่างการวิเคราะห์ทางนิติวิทยาศาสตร์สิ่งประดิษฐ์เหล่านี้มีบทบาทสำคัญมากในการอนุมัติหรือไม่อนุมัติการสังเกตของผู้ตรวจสอบ
ความสำคัญของ Windows Artifacts สำหรับนิติเวช
สิ่งประดิษฐ์ของ Windows มีความสำคัญเนื่องจากสาเหตุต่อไปนี้ -
ประมาณ 90% ของการเข้าชมในโลกมาจากคอมพิวเตอร์ที่ใช้ Windows เป็นระบบปฏิบัติการ นั่นคือเหตุผลที่ผู้ตรวจสอบทางนิติวิทยาศาสตร์ดิจิทัลสิ่งประดิษฐ์ของ Windows เป็นสิ่งที่จำเป็นมาก
ระบบปฏิบัติการ Windows จัดเก็บหลักฐานประเภทต่างๆที่เกี่ยวข้องกับกิจกรรมของผู้ใช้ในระบบคอมพิวเตอร์ นี่เป็นอีกเหตุผลหนึ่งที่แสดงให้เห็นถึงความสำคัญของสิ่งประดิษฐ์ของ Windows สำหรับการพิสูจน์หลักฐานทางดิจิทัล
หลายครั้งที่ผู้ตรวจสอบวนเวียนอยู่กับการสอบสวนในพื้นที่เก่าและดั้งเดิมเช่นข้อมูลที่คัดลอกมาของผู้ใช้ สิ่งประดิษฐ์ของ Windows สามารถนำไปสู่การตรวจสอบไปสู่พื้นที่ที่ไม่ใช่แบบดั้งเดิมเช่นข้อมูลที่ระบบสร้างขึ้นหรือสิ่งประดิษฐ์
Windows มีสิ่งประดิษฐ์จำนวนมากซึ่งเป็นประโยชน์สำหรับผู้ตรวจสอบตลอดจน บริษัท และบุคคลที่ทำการสืบสวนอย่างไม่เป็นทางการ
การเพิ่มขึ้นของอาชญากรรมไซเบอร์ในช่วงไม่กี่ปีที่ผ่านมาเป็นอีกสาเหตุหนึ่งที่สิ่งประดิษฐ์ของ Windows มีความสำคัญ
Windows Artifacts และสคริปต์ Python
ในส่วนนี้เราจะพูดถึงสิ่งประดิษฐ์ของ Windows และสคริปต์ Python เพื่อดึงข้อมูลจากสิ่งเหล่านี้
ถังขยะรีไซเคิล
เป็นหนึ่งในสิ่งประดิษฐ์ของ Windows ที่สำคัญสำหรับการตรวจสอบทางนิติวิทยาศาสตร์ ถังรีไซเคิลของ Windows มีไฟล์ที่ผู้ใช้ลบ แต่ระบบยังไม่ได้ลบออก แม้ว่าผู้ใช้จะลบไฟล์ออกจากระบบอย่างสมบูรณ์ แต่ก็ทำหน้าที่เป็นแหล่งข้อมูลสำคัญในการตรวจสอบ เนื่องจากผู้ตรวจสอบสามารถดึงข้อมูลที่มีค่าเช่นเส้นทางไฟล์ต้นฉบับตลอดจนเวลาที่ส่งไปยังถังรีไซเคิลจากไฟล์ที่ถูกลบ
โปรดทราบว่าการจัดเก็บหลักฐานถังรีไซเคิลขึ้นอยู่กับรุ่นของ Windows ในสคริปต์ Python ต่อไปนี้เราจะจัดการกับ Windows 7 ที่สร้างไฟล์สองไฟล์:$R ไฟล์ที่มีเนื้อหาจริงของไฟล์รีไซเคิลและ $I ไฟล์ที่มีชื่อไฟล์ต้นฉบับเส้นทางขนาดไฟล์เมื่อไฟล์ถูกลบ
สำหรับสคริปต์ Python เราจำเป็นต้องติดตั้งโมดูลของบุคคลที่สามคือ pytsk3, pyewf และ unicodecsv. เราสามารถใช้pipเพื่อติดตั้ง เราสามารถทำตามขั้นตอนต่อไปนี้เพื่อดึงข้อมูลจากถังรีไซเคิล -
ขั้นแรกเราต้องใช้วิธีเรียกซ้ำเพื่อสแกนผ่านไฟล์ $Recycle.bin และเลือกไฟล์ทั้งหมดที่ขึ้นต้นด้วย $I.
ต่อไปเราจะอ่านเนื้อหาของไฟล์และแยกวิเคราะห์โครงสร้างข้อมูลเมตาที่มีอยู่
ตอนนี้เราจะค้นหาไฟล์ $ R ที่เกี่ยวข้อง
ในที่สุดเราจะเขียนผลลัพธ์ลงในไฟล์ CSV เพื่อตรวจสอบ
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ขั้นแรกเราต้องนำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser
import datetime
import os
import struct
from utility.pytskutil import TSKUtil
import unicodecsv as csv
ต่อไปเราต้องจัดเตรียมอาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง โปรดทราบว่าที่นี่จะยอมรับสามอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังไฟล์หลักฐานที่สองคือประเภทของไฟล์หลักฐานและที่สามคือพา ธ เอาต์พุตที่ต้องการไปยังรายงาน CSV ดังที่แสดงด้านล่าง
if __name__ == '__main__':
parser = argparse.ArgumentParser('Recycle Bin evidences')
parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE', help = "Evidence file format",
choices = ('ewf', 'raw'))
parser.add_argument('CSV_REPORT', help = "Path to CSV report")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.CSV_REPORT)
ตอนนี้กำหนด main()ฟังก์ชันที่จะจัดการการประมวลผลทั้งหมด มันจะค้นหา$I ไฟล์ดังนี้ -
def main(evidence, image_type, report_file):
tsk_util = TSKUtil(evidence, image_type)
dollar_i_files = tsk_util.recurse_files("$I", path = '/$Recycle.bin',logic = "startswith") if dollar_i_files is not None: processed_files = process_dollar_i(tsk_util, dollar_i_files) write_csv(report_file,['file_path', 'file_size', 'deleted_time','dollar_i_file', 'dollar_r_file', 'is_directory'],processed_files) else: print("No $I files found")
ตอนนี้ถ้าเราพบ $I จากนั้นไฟล์จะต้องถูกส่งไปที่ process_dollar_i() ซึ่งจะยอมรับ tsk_util เช่นเดียวกับรายการของ $I ไฟล์ดังที่แสดงด้านล่าง -
def process_dollar_i(tsk_util, dollar_i_files):
processed_files = []
for dollar_i in dollar_i_files:
file_attribs = read_dollar_i(dollar_i[2])
if file_attribs is None:
continue
file_attribs['dollar_i_file'] = os.path.join('/$Recycle.bin', dollar_i[1][1:])
ตอนนี้ค้นหาไฟล์ $ R ดังนี้ -
recycle_file_path = os.path.join('/$Recycle.bin',dollar_i[1].rsplit("/", 1)[0][1:]) dollar_r_files = tsk_util.recurse_files( "$R" + dollar_i[0][2:],path = recycle_file_path, logic = "startswith")
if dollar_r_files is None:
dollar_r_dir = os.path.join(recycle_file_path,"$R" + dollar_i[0][2:])
dollar_r_dirs = tsk_util.query_directory(dollar_r_dir)
if dollar_r_dirs is None:
file_attribs['dollar_r_file'] = "Not Found"
file_attribs['is_directory'] = 'Unknown'
else:
file_attribs['dollar_r_file'] = dollar_r_dir
file_attribs['is_directory'] = True
else:
dollar_r = [os.path.join(recycle_file_path, r[1][1:])for r in dollar_r_files]
file_attribs['dollar_r_file'] = ";".join(dollar_r)
file_attribs['is_directory'] = False
processed_files.append(file_attribs)
return processed_files
ตอนนี้กำหนด read_dollar_i() วิธีการอ่านไฟล์ $Iไฟล์หรืออีกนัยหนึ่งคือแยกวิเคราะห์ข้อมูลเมตา เราจะใช้read_random()วิธีการอ่านแปดไบต์แรกของลายเซ็น สิ่งนี้จะคืนค่าไม่มีหากลายเซ็นไม่ตรงกัน หลังจากนั้นเราจะต้องอ่านและแกะค่าจาก$I ไฟล์หากเป็นไฟล์ที่ถูกต้อง
def read_dollar_i(file_obj):
if file_obj.read_random(0, 8) != '\x01\x00\x00\x00\x00\x00\x00\x00':
return None
raw_file_size = struct.unpack('<q', file_obj.read_random(8, 8))
raw_deleted_time = struct.unpack('<q', file_obj.read_random(16, 8))
raw_file_path = file_obj.read_random(24, 520)
ตอนนี้หลังจากแตกไฟล์เหล่านี้เราจำเป็นต้องตีความจำนวนเต็มให้เป็นค่าที่มนุษย์อ่านได้โดยใช้ sizeof_fmt() ฟังก์ชันดังแสดงด้านล่าง -
file_size = sizeof_fmt(raw_file_size[0])
deleted_time = parse_windows_filetime(raw_deleted_time[0])
file_path = raw_file_path.decode("utf16").strip("\x00")
return {'file_size': file_size, 'file_path': file_path,'deleted_time': deleted_time}
ตอนนี้เราต้องกำหนด sizeof_fmt() ฟังก์ชันดังต่อไปนี้ -
def sizeof_fmt(num, suffix = 'B'):
for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix)
ตอนนี้กำหนดฟังก์ชันสำหรับจำนวนเต็มที่ตีความเป็นวันที่และเวลาที่จัดรูปแบบดังนี้ -
def parse_windows_filetime(date_value):
microseconds = float(date_value) / 10
ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(
microseconds = microseconds)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
ตอนนี้เราจะกำหนด write_csv() วิธีการเขียนผลลัพธ์ที่ประมวลผลเป็นไฟล์ CSV ดังนี้ -
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
เมื่อคุณเรียกใช้สคริปต์ข้างต้นเราจะได้รับข้อมูลจากไฟล์ $ I และ $ R
บันทึกย่อช่วยเตือน
Windows Sticky Notes แทนที่นิสัยการเขียนด้วยปากกาและกระดาษในโลกแห่งความเป็นจริง บันทึกย่อเหล่านี้ใช้เพื่อลอยบนเดสก์ท็อปพร้อมตัวเลือกต่างๆสำหรับสีแบบอักษรและอื่น ๆ ใน Windows 7 ไฟล์ Sticky Notes จะถูกเก็บเป็นไฟล์ OLE ดังนั้นในสคริปต์ Python ต่อไปนี้เราจะตรวจสอบไฟล์ OLE นี้เพื่อแยกข้อมูลเมตาจาก Sticky Notes
สำหรับสคริปต์ Python นี้เราจำเป็นต้องติดตั้งโมดูลของบุคคลที่สามคือ olefile, pytsk3, pyewfและ unicodecsv เราสามารถใช้คำสั่งpip เพื่อติดตั้ง
เราสามารถทำตามขั้นตอนที่กล่าวถึงด้านล่างเพื่อดึงข้อมูลจากไฟล์ Sticky note คือ StickyNote.sn -
ขั้นแรกให้เปิดไฟล์หลักฐานและค้นหาไฟล์ StickyNote.snt ทั้งหมด
จากนั้นแยกวิเคราะห์ข้อมูลเมตาและเนื้อหาจากสตรีม OLE และเขียนเนื้อหา RTF ลงในไฟล์
สุดท้ายสร้างรายงาน CSV ของข้อมูลเมตานี้
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นให้นำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser
import unicodecsv as csv
import os
import StringIO
from utility.pytskutil import TSKUtil
import olefile
จากนั้นกำหนดตัวแปรส่วนกลางที่จะใช้กับสคริปต์นี้ -
REPORT_COLS = ['note_id', 'created', 'modified', 'note_text', 'note_file']
ต่อไปเราต้องจัดเตรียมอาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง โปรดทราบว่าที่นี่จะยอมรับสามอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังไฟล์หลักฐานที่สองคือประเภทของไฟล์หลักฐานและที่สามคือพา ธ เอาต์พุตที่ต้องการดังนี้ -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Evidence from Sticky Notes')
parser.add_argument('EVIDENCE_FILE', help="Path to evidence file")
parser.add_argument('IMAGE_TYPE', help="Evidence file format",choices=('ewf', 'raw'))
parser.add_argument('REPORT_FOLDER', help="Path to report folder")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT_FOLDER)
ตอนนี้เราจะกำหนด main() ซึ่งจะคล้ายกับสคริปต์ก่อนหน้าตามที่แสดงด้านล่าง -
def main(evidence, image_type, report_folder):
tsk_util = TSKUtil(evidence, image_type)
note_files = tsk_util.recurse_files('StickyNotes.snt', '/Users','equals')
ตอนนี้ให้เราทำซ้ำผ่านไฟล์ผลลัพธ์ แล้วเราจะโทรparse_snt_file() เพื่อประมวลผลไฟล์จากนั้นเราจะเขียนไฟล์ RTF ด้วยไฟล์ write_note_rtf() วิธีการดังนี้ -
report_details = []
for note_file in note_files:
user_dir = note_file[1].split("/")[1]
file_like_obj = create_file_like_obj(note_file[2])
note_data = parse_snt_file(file_like_obj)
if note_data is None:
continue
write_note_rtf(note_data, os.path.join(report_folder, user_dir))
report_details += prep_note_report(note_data, REPORT_COLS,"/Users" + note_file[1])
write_csv(os.path.join(report_folder, 'sticky_notes.csv'), REPORT_COLS,report_details)
ต่อไปเราต้องกำหนดฟังก์ชันต่างๆที่ใช้ในสคริปต์นี้
ก่อนอื่นเราจะกำหนด create_file_like_obj() ฟังก์ชั่นสำหรับอ่านขนาดของไฟล์โดยใช้ pytskไฟล์วัตถุ จากนั้นเราจะกำหนดparse_snt_file() ฟังก์ชันที่จะรับอ็อบเจ็กต์ที่มีลักษณะคล้ายไฟล์เป็นอินพุตและใช้เพื่ออ่านและตีความไฟล์โน้ต
def parse_snt_file(snt_file):
if not olefile.isOleFile(snt_file):
print("This is not an OLE file")
return None
ole = olefile.OleFileIO(snt_file)
note = {}
for stream in ole.listdir():
if stream[0].count("-") == 3:
if stream[0] not in note:
note[stream[0]] = {"created": ole.getctime(stream[0]),"modified": ole.getmtime(stream[0])}
content = None
if stream[1] == '0':
content = ole.openstream(stream).read()
elif stream[1] == '3':
content = ole.openstream(stream).read().decode("utf-16")
if content:
note[stream[0]][stream[1]] = content
return note
ตอนนี้สร้างไฟล์ RTF โดยกำหนดไฟล์ write_note_rtf() ฟังก์ชันดังต่อไปนี้
def write_note_rtf(note_data, report_folder):
if not os.path.exists(report_folder):
os.makedirs(report_folder)
for note_id, stream_data in note_data.items():
fname = os.path.join(report_folder, note_id + ".rtf")
with open(fname, 'w') as open_file:
open_file.write(stream_data['0'])
ตอนนี้เราจะแปลพจนานุกรมที่ซ้อนกันเป็นรายการพจนานุกรมแบบรวมที่เหมาะสมกว่าสำหรับสเปรดชีต CSV จะทำได้โดยการกำหนดprep_note_report()ฟังก์ชัน สุดท้ายนี้เราจะกำหนดwrite_csv() ฟังก์ชัน
def prep_note_report(note_data, report_cols, note_file):
report_details = []
for note_id, stream_data in note_data.items():
report_details.append({
"note_id": note_id,
"created": stream_data['created'],
"modified": stream_data['modified'],
"note_text": stream_data['3'].strip("\x00"),
"note_file": note_file
})
return report_details
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
หลังจากเรียกใช้สคริปต์ด้านบนเราจะได้รับข้อมูลเมตาจากไฟล์ Sticky Notes
ไฟล์รีจิสทรี
ไฟล์รีจิสทรีของ Windows มีรายละเอียดที่สำคัญมากมายซึ่งเปรียบเสมือนขุมทรัพย์ของข้อมูลสำหรับนักวิเคราะห์ทางนิติวิทยาศาสตร์ เป็นฐานข้อมูลแบบลำดับชั้นที่มีรายละเอียดที่เกี่ยวข้องกับการกำหนดค่าระบบปฏิบัติการกิจกรรมของผู้ใช้การติดตั้งซอฟต์แวร์เป็นต้นในสคริปต์ Python ต่อไปนี้เราจะเข้าถึงข้อมูลพื้นฐานทั่วไปจากSYSTEM และ SOFTWARE ลมพิษ
สำหรับสคริปต์ Python นี้เราจำเป็นต้องติดตั้งโมดูลของบุคคลที่สามคือ pytsk3, pyewf และ registry. เราสามารถใช้pip เพื่อติดตั้ง
เราสามารถทำตามขั้นตอนด้านล่างเพื่อดึงข้อมูลจากรีจิสทรีของ Windows -
ขั้นแรกค้นหากลุ่มรีจิสทรีเพื่อดำเนินการตามชื่อและตามเส้นทาง
จากนั้นเราจะเปิดไฟล์เหล่านี้โดยใช้โมดูล StringIO และ Registry
ในที่สุดเราต้องประมวลผลแต่ละกลุ่มและพิมพ์ค่าที่แยกวิเคราะห์ไปยังคอนโซลเพื่อตีความ
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นให้นำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser
import datetime
import StringIO
import struct
from utility.pytskutil import TSKUtil
from Registry import Registry
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสองข้อโต้แย้ง - ประการแรกคือเส้นทางไปยังไฟล์หลักฐานที่สองคือประเภทของไฟล์หลักฐานดังที่แสดงด้านล่าง -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Evidence from Windows Registry')
parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE', help = "Evidence file format",
choices = ('ewf', 'raw'))
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE)
ตอนนี้เราจะกำหนด main() ฟังก์ชันสำหรับการค้นหา SYSTEM และ SOFTWARE ลมพิษภายใน /Windows/System32/config โฟลเดอร์ดังนี้ -
def main(evidence, image_type):
tsk_util = TSKUtil(evidence, image_type)
tsk_system_hive = tsk_util.recurse_files('system', '/Windows/system32/config', 'equals')
tsk_software_hive = tsk_util.recurse_files('software', '/Windows/system32/config', 'equals')
system_hive = open_file_as_reg(tsk_system_hive[0][2])
software_hive = open_file_as_reg(tsk_software_hive[0][2])
process_system_hive(system_hive)
process_software_hive(software_hive)
ตอนนี้กำหนดฟังก์ชันสำหรับเปิดไฟล์รีจิสทรี เพื่อจุดประสงค์นี้เราต้องรวบรวมขนาดของไฟล์จากpytsk metadata ดังนี้ -
def open_file_as_reg(reg_file):
file_size = reg_file.info.meta.size
file_content = reg_file.read_random(0, file_size)
file_like_obj = StringIO.StringIO(file_content)
return Registry.Registry(file_like_obj)
ตอนนี้ด้วยความช่วยเหลือของวิธีการต่อไปนี้เราสามารถดำเนินการได้ SYSTEM> รัง -
def process_system_hive(hive):
root = hive.root()
current_control_set = root.find_key("Select").value("Current").value()
control_set = root.find_key("ControlSet{:03d}".format(current_control_set))
raw_shutdown_time = struct.unpack(
'<Q', control_set.find_key("Control").find_key("Windows").value("ShutdownTime").value())
shutdown_time = parse_windows_filetime(raw_shutdown_time[0])
print("Last Shutdown Time: {}".format(shutdown_time))
time_zone = control_set.find_key("Control").find_key("TimeZoneInformation")
.value("TimeZoneKeyName").value()
print("Machine Time Zone: {}".format(time_zone))
computer_name = control_set.find_key("Control").find_key("ComputerName").find_key("ComputerName")
.value("ComputerName").value()
print("Machine Name: {}".format(computer_name))
last_access = control_set.find_key("Control").find_key("FileSystem")
.value("NtfsDisableLastAccessUpdate").value()
last_access = "Disabled" if last_access == 1 else "enabled"
print("Last Access Updates: {}".format(last_access))
ตอนนี้เราจำเป็นต้องกำหนดฟังก์ชันสำหรับจำนวนเต็มที่ตีความเป็นวันที่และเวลาที่จัดรูปแบบดังนี้ -
def parse_windows_filetime(date_value):
microseconds = float(date_value) / 10
ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds = microseconds)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
def parse_unix_epoch(date_value):
ts = datetime.datetime.fromtimestamp(date_value)
return ts.strftime('%Y-%m-%d %H:%M:%S.%f')
ตอนนี้ด้วยความช่วยเหลือของวิธีการต่อไปนี้เราสามารถดำเนินการได้ SOFTWARE รัง -
def process_software_hive(hive):
root = hive.root()
nt_curr_ver = root.find_key("Microsoft").find_key("Windows NT")
.find_key("CurrentVersion")
print("Product name: {}".format(nt_curr_ver.value("ProductName").value()))
print("CSD Version: {}".format(nt_curr_ver.value("CSDVersion").value()))
print("Current Build: {}".format(nt_curr_ver.value("CurrentBuild").value()))
print("Registered Owner: {}".format(nt_curr_ver.value("RegisteredOwner").value()))
print("Registered Org:
{}".format(nt_curr_ver.value("RegisteredOrganization").value()))
raw_install_date = nt_curr_ver.value("InstallDate").value()
install_date = parse_unix_epoch(raw_install_date)
print("Installation Date: {}".format(install_date))
หลังจากเรียกใช้สคริปต์ข้างต้นเราจะได้รับข้อมูลเมตาที่เก็บไว้ในไฟล์ Windows Registry
บทนี้พูดถึงสิ่งประดิษฐ์ที่สำคัญกว่าใน Windows และวิธีการแยกโดยใช้ Python
กิจกรรมของผู้ใช้
Windows มี NTUSER.DATไฟล์สำหรับจัดเก็บกิจกรรมต่างๆของผู้ใช้ โปรไฟล์ผู้ใช้ทุกคนมีกลุ่มเหมือนNTUSER.DATซึ่งเก็บข้อมูลและการกำหนดค่าที่เกี่ยวข้องกับผู้ใช้นั้นโดยเฉพาะ ดังนั้นจึงมีประโยชน์อย่างมากสำหรับการตรวจสอบโดยนักวิเคราะห์ทางนิติวิทยาศาสตร์
สคริปต์ Python ต่อไปนี้จะแยกวิเคราะห์คีย์บางส่วนของ NTUSER.DATสำหรับการสำรวจการกระทำของผู้ใช้ในระบบ ก่อนที่จะดำเนินการต่อไปสำหรับสคริปต์ Python เราจำเป็นต้องติดตั้งโมดูลของบุคคลที่สามคือRegistry, pytsk3, pyewf และ Jinja2. เราสามารถใช้ pip เพื่อติดตั้งได้
เราสามารถทำตามขั้นตอนต่อไปนี้เพื่อดึงข้อมูลจาก NTUSER.DAT ไฟล์ -
ขั้นแรกให้ค้นหาทั้งหมด NTUSER.DAT ไฟล์ในระบบ
จากนั้นแยกวิเคราะห์ไฟล์ WordWheelQuery, TypePath and RunMRU ที่สำคัญสำหรับแต่ละ NTUSER.DAT ไฟล์.
ในที่สุดเราจะเขียนสิ่งประดิษฐ์เหล่านี้ซึ่งประมวลผลแล้วลงในรายงาน HTML โดยใช้ Jinja2 fmodule
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นเราต้องนำเข้าโมดูล Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser
import os
import StringIO
import struct
from utility.pytskutil import TSKUtil
from Registry import Registry
import jinja2
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสามอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังไฟล์หลักฐานอันดับที่สองคือประเภทของไฟล์หลักฐานและที่สามคือพา ธ เอาต์พุตที่ต้องการไปยังรายงาน HTML ดังแสดงด้านล่าง
if __name__ == '__main__':
parser = argparse.ArgumentParser('Information from user activities')
parser.add_argument('EVIDENCE_FILE',help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE',help = "Evidence file format",choices = ('ewf', 'raw'))
parser.add_argument('REPORT',help = "Path to report file")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT)
ตอนนี้ให้เรากำหนด main() ฟังก์ชันสำหรับค้นหาทั้งหมด NTUSER.DAT ไฟล์ดังที่แสดง -
def main(evidence, image_type, report):
tsk_util = TSKUtil(evidence, image_type)
tsk_ntuser_hives = tsk_util.recurse_files('ntuser.dat','/Users', 'equals')
nt_rec = {
'wordwheel': {'data': [], 'title': 'WordWheel Query'},
'typed_path': {'data': [], 'title': 'Typed Paths'},
'run_mru': {'data': [], 'title': 'Run MRU'}
}
ตอนนี้เราจะพยายามหาคีย์ใน NTUSER.DAT และเมื่อคุณพบแล้วให้กำหนดฟังก์ชันการประมวลผลของผู้ใช้ดังที่แสดงด้านล่าง -
for ntuser in tsk_ntuser_hives:
uname = ntuser[1].split("/")
open_ntuser = open_file_as_reg(ntuser[2])
try:
explorer_key = open_ntuser.root().find_key("Software").find_key("Microsoft")
.find_key("Windows").find_key("CurrentVersion").find_key("Explorer")
except Registry.RegistryKeyNotFoundException:
continue
nt_rec['wordwheel']['data'] += parse_wordwheel(explorer_key, uname)
nt_rec['typed_path']['data'] += parse_typed_paths(explorer_key, uname)
nt_rec['run_mru']['data'] += parse_run_mru(explorer_key, uname)
nt_rec['wordwheel']['headers'] = \ nt_rec['wordwheel']['data'][0].keys()
nt_rec['typed_path']['headers'] = \ nt_rec['typed_path']['data'][0].keys()
nt_rec['run_mru']['headers'] = \ nt_rec['run_mru']['data'][0].keys()
ตอนนี้ส่งวัตถุพจนานุกรมและเส้นทางไปที่ write_html() วิธีการดังนี้ -
write_html(report, nt_rec)
ตอนนี้กำหนดวิธีการที่ใช้ pytsk จัดการไฟล์และอ่านลงในคลาส Registry ผ่านไฟล์ StringIO ชั้นเรียน.
def open_file_as_reg(reg_file):
file_size = reg_file.info.meta.size
file_content = reg_file.read_random(0, file_size)
file_like_obj = StringIO.StringIO(file_content)
return Registry.Registry(file_like_obj)
ตอนนี้เราจะกำหนดฟังก์ชันที่จะแยกวิเคราะห์และจัดการ WordWheelQuery คีย์จาก NTUSER.DAT ไฟล์ดังนี้ -
def parse_wordwheel(explorer_key, username):
try:
wwq = explorer_key.find_key("WordWheelQuery")
except Registry.RegistryKeyNotFoundException:
return []
mru_list = wwq.value("MRUListEx").value()
mru_order = []
for i in xrange(0, len(mru_list), 2):
order_val = struct.unpack('h', mru_list[i:i + 2])[0]
if order_val in mru_order and order_val in (0, -1):
break
else:
mru_order.append(order_val)
search_list = []
for count, val in enumerate(mru_order):
ts = "N/A"
if count == 0:
ts = wwq.timestamp()
search_list.append({
'timestamp': ts,
'username': username,
'order': count,
'value_name': str(val),
'search': wwq.value(str(val)).value().decode("UTF-16").strip("\x00")
})
return search_list
ตอนนี้เราจะกำหนดฟังก์ชันที่จะแยกวิเคราะห์และจัดการ TypedPaths คีย์จาก NTUSER.DAT ไฟล์ดังนี้ -
def parse_typed_paths(explorer_key, username):
try:
typed_paths = explorer_key.find_key("TypedPaths")
except Registry.RegistryKeyNotFoundException:
return []
typed_path_details = []
for val in typed_paths.values():
typed_path_details.append({
"username": username,
"value_name": val.name(),
"path": val.value()
})
return typed_path_details
ตอนนี้เราจะกำหนดฟังก์ชันที่จะแยกวิเคราะห์และจัดการ RunMRU คีย์จาก NTUSER.DAT ไฟล์ดังนี้ -
def parse_run_mru(explorer_key, username):
try:
run_mru = explorer_key.find_key("RunMRU")
except Registry.RegistryKeyNotFoundException:
return []
if len(run_mru.values()) == 0:
return []
mru_list = run_mru.value("MRUList").value()
mru_order = []
for i in mru_list:
mru_order.append(i)
mru_details = []
for count, val in enumerate(mru_order):
ts = "N/A"
if count == 0:
ts = run_mru.timestamp()
mru_details.append({
"username": username,
"timestamp": ts,
"order": count,
"value_name": val,
"run_statement": run_mru.value(val).value()
})
return mru_details
ตอนนี้ฟังก์ชันต่อไปนี้จะจัดการการสร้างรายงาน HTML -
def write_html(outfile, data_dict):
cwd = os.path.dirname(os.path.abspath(__file__))
env = jinja2.Environment(loader=jinja2.FileSystemLoader(cwd))
template = env.get_template("user_activity.html")
rendering = template.render(nt_data=data_dict)
with open(outfile, 'w') as open_outfile:
open_outfile.write(rendering)
ในที่สุดเราสามารถเขียนเอกสาร HTML สำหรับรายงานได้ หลังจากเรียกใช้สคริปต์ข้างต้นเราจะได้รับข้อมูลจากไฟล์ NTUSER.DAT ในรูปแบบเอกสาร HTML
LINK ไฟล์
ไฟล์ทางลัดถูกสร้างขึ้นเมื่อผู้ใช้หรือระบบปฏิบัติการสร้างไฟล์ทางลัดสำหรับไฟล์ที่ใช้บ่อยดับเบิลคลิกหรือเข้าถึงจากไดรฟ์ระบบเช่นที่เก็บข้อมูลที่แนบมา ไฟล์ทางลัดประเภทนี้เรียกว่าไฟล์ลิงค์ โดยการเข้าถึงไฟล์ลิงก์เหล่านี้ผู้ตรวจสอบสามารถค้นหากิจกรรมของหน้าต่างเช่นเวลาและตำแหน่งที่ไฟล์เหล่านี้ถูกเข้าถึง
ให้เราพูดคุยเกี่ยวกับสคริปต์ Python ที่เราสามารถใช้เพื่อรับข้อมูลจากไฟล์ Windows LINK เหล่านี้
สำหรับสคริปต์ Python ให้ติดตั้งโมดูลของบุคคลที่สามคือ pylnk, pytsk3, pyewf. เราสามารถทำตามขั้นตอนต่อไปนี้เพื่อดึงข้อมูลจากlnk ไฟล์
ขั้นแรกให้ค้นหา lnk ไฟล์ภายในระบบ
จากนั้นแยกข้อมูลจากไฟล์นั้นโดยทำซ้ำผ่านไฟล์เหล่านั้น
ในที่สุดเราจำเป็นต้องส่งข้อมูลนี้ไปยังรายงาน CSV
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นให้นำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser
import csv
import StringIO
from utility.pytskutil import TSKUtil
import pylnk
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสามอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังไฟล์หลักฐานอันดับที่สองคือประเภทของไฟล์หลักฐานและที่สามคือพา ธ เอาต์พุตที่ต้องการไปยังรายงาน CSV ดังที่แสดงด้านล่าง -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Parsing LNK files')
parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
parser.add_argument('IMAGE_TYPE', help = "Evidence file format",choices = ('ewf', 'raw'))
parser.add_argument('CSV_REPORT', help = "Path to CSV report")
args = parser.parse_args()
main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.CSV_REPORT)
ตอนนี้ตีความไฟล์หลักฐานโดยสร้างวัตถุของ TSKUtil และวนซ้ำผ่านระบบไฟล์เพื่อค้นหาไฟล์ที่ลงท้ายด้วย lnk. สามารถทำได้โดยกำหนดmain() ฟังก์ชันดังต่อไปนี้ -
def main(evidence, image_type, report):
tsk_util = TSKUtil(evidence, image_type)
lnk_files = tsk_util.recurse_files("lnk", path="/", logic="endswith")
if lnk_files is None:
print("No lnk files found")
exit(0)
columns = [
'command_line_arguments', 'description', 'drive_serial_number',
'drive_type', 'file_access_time', 'file_attribute_flags',
'file_creation_time', 'file_modification_time', 'file_size',
'environmental_variables_location', 'volume_label',
'machine_identifier', 'local_path', 'network_path',
'relative_path', 'working_directory'
]
ตอนนี้ด้วยความช่วยเหลือของรหัสต่อไปนี้เราจะทำซ้ำ lnk ไฟล์โดยสร้างฟังก์ชั่นดังนี้ -
parsed_lnks = []
for entry in lnk_files:
lnk = open_file_as_lnk(entry[2])
lnk_data = {'lnk_path': entry[1], 'lnk_name': entry[0]}
for col in columns:
lnk_data[col] = getattr(lnk, col, "N/A")
lnk.close()
parsed_lnks.append(lnk_data)
write_csv(report, columns + ['lnk_path', 'lnk_name'], parsed_lnks)
ตอนนี้เราต้องกำหนดสองฟังก์ชั่นหนึ่งจะเปิดไฟล์ pytsk ไฟล์ออบเจ็กต์และอื่น ๆ จะใช้สำหรับการเขียนรายงาน CSV ดังที่แสดงด้านล่าง -
def open_file_as_lnk(lnk_file):
file_size = lnk_file.info.meta.size
file_content = lnk_file.read_random(0, file_size)
file_like_obj = StringIO.StringIO(file_content)
lnk = pylnk.file()
lnk.open_file_object(file_like_obj)
return lnk
def write_csv(outfile, fieldnames, data):
with open(outfile, 'wb') as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
หลังจากเรียกใช้สคริปต์ข้างต้นเราจะได้รับข้อมูลจากการค้นพบ lnk ไฟล์ในรายงาน CSV -
ดึงไฟล์ล่วงหน้า
เมื่อใดก็ตามที่แอปพลิเคชันทำงานเป็นครั้งแรกจากตำแหน่งเฉพาะ Windows จะสร้างขึ้น prefetch files. สิ่งเหล่านี้ใช้เพื่อเร่งกระบวนการเริ่มต้นแอปพลิเคชัน นามสกุลของไฟล์เหล่านี้คือ.PF และสิ่งเหล่านี้จะถูกเก็บไว้ในไฟล์ ”\Root\Windows\Prefetch” โฟลเดอร์
ผู้เชี่ยวชาญด้านนิติวิทยาศาสตร์ดิจิทัลสามารถเปิดเผยหลักฐานการทำงานของโปรแกรมจากตำแหน่งที่ระบุพร้อมกับรายละเอียดของผู้ใช้ ไฟล์ Prefetch เป็นสิ่งประดิษฐ์ที่มีประโยชน์สำหรับผู้ตรวจสอบเนื่องจากรายการจะยังคงอยู่แม้ว่าโปรแกรมจะถูกลบหรือไม่ได้ติดตั้งก็ตาม
ให้เราพูดคุยเกี่ยวกับสคริปต์ Python ที่จะดึงข้อมูลจากไฟล์ดึงข้อมูลล่วงหน้าของ Windows ตามที่ระบุด้านล่าง -
สำหรับสคริปต์ Python ให้ติดตั้งโมดูลของบุคคลที่สามคือ pylnk, pytsk3 และ unicodecsv. โปรดจำไว้ว่าเราได้ทำงานกับไลบรารีเหล่านี้แล้วในสคริปต์ Python ที่เราได้กล่าวถึงในบทก่อนหน้านี้
เราต้องทำตามขั้นตอนด้านล่างเพื่อดึงข้อมูลออกมา prefetch ไฟล์ -
ขั้นแรกให้สแกนหา .pf ไฟล์นามสกุลหรือไฟล์ prefetch
ตอนนี้ทำการตรวจสอบลายเซ็นเพื่อกำจัดผลบวกปลอม
จากนั้นแยกวิเคราะห์รูปแบบไฟล์การดึงข้อมูลล่วงหน้าของ Windows สิ่งนี้แตกต่างกับเวอร์ชัน Windows ตัวอย่างเช่นสำหรับ Windows XP คือ 17 สำหรับ Windows Vista และ Windows 7 เป็น 23, 26 สำหรับ Windows 8.1 และ 30 สำหรับ Windows 10
สุดท้ายนี้เราจะเขียนผลลัพธ์ที่แยกวิเคราะห์ในไฟล์ CSV
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นให้นำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
import argparse
from datetime import datetime, timedelta
import os
import pytsk3
import pyewf
import struct
import sys
import unicodecsv as csv
from utility.pytskutil import TSKUtil
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสองข้อโต้แย้งอันดับแรกคือพา ธ ไปยังไฟล์หลักฐานและอันดับที่สองจะเป็นประเภทของไฟล์หลักฐาน นอกจากนี้ยังยอมรับอาร์กิวเมนต์ที่เป็นทางเลือกสำหรับระบุเส้นทางในการสแกนหาไฟล์ prefetch -
if __name__ == "__main__":
parser = argparse.ArgumentParser('Parsing Prefetch files')
parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
parser.add_argument("OUTPUT_CSV", help = "Path to write output csv")
parser.add_argument("-d", help = "Prefetch directory to scan",default = "/WINDOWS/PREFETCH")
args = parser.parse_args()
if os.path.exists(args.EVIDENCE_FILE) and \
os.path.isfile(args.EVIDENCE_FILE):
main(args.EVIDENCE_FILE, args.TYPE, args.OUTPUT_CSV, args.d)
else:
print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
sys.exit(1)
ตอนนี้ตีความไฟล์หลักฐานโดยสร้างวัตถุของ TSKUtil และวนซ้ำผ่านระบบไฟล์เพื่อค้นหาไฟล์ที่ลงท้ายด้วย .pf. สามารถทำได้โดยกำหนดmain() ฟังก์ชันดังต่อไปนี้ -
def main(evidence, image_type, output_csv, path):
tsk_util = TSKUtil(evidence, image_type)
prefetch_dir = tsk_util.query_directory(path)
prefetch_files = None
if prefetch_dir is not None:
prefetch_files = tsk_util.recurse_files(".pf", path=path, logic="endswith")
if prefetch_files is None:
print("[-] No .pf files found")
sys.exit(2)
print("[+] Identified {} potential prefetch files".format(len(prefetch_files)))
prefetch_data = []
for hit in prefetch_files:
prefetch_file = hit[2]
pf_version = check_signature(prefetch_file)
ตอนนี้กำหนดวิธีการที่จะทำการตรวจสอบลายเซ็นดังที่แสดงด้านล่าง -
def check_signature(prefetch_file):
version, signature = struct.unpack("^<2i", prefetch_file.read_random(0, 8))
if signature == 1094927187:
return version
else:
return None
if pf_version is None:
continue
pf_name = hit[0]
if pf_version == 17:
parsed_data = parse_pf_17(prefetch_file, pf_name)
parsed_data.append(os.path.join(path, hit[1].lstrip("//")))
prefetch_data.append(parsed_data)
ตอนนี้เริ่มประมวลผลไฟล์ดึงข้อมูลล่วงหน้าของ Windows ที่นี่เรากำลังนำตัวอย่างของการดึงไฟล์ล่วงหน้าของ Windows XP -
def parse_pf_17(prefetch_file, pf_name):
create = convert_unix(prefetch_file.info.meta.crtime)
modify = convert_unix(prefetch_file.info.meta.mtime)
def convert_unix(ts):
if int(ts) == 0:
return ""
return datetime.utcfromtimestamp(ts)
def convert_filetime(ts):
if int(ts) == 0:
return ""
return datetime(1601, 1, 1) + timedelta(microseconds=ts / 10)
ตอนนี้แยกข้อมูลที่ฝังอยู่ภายในไฟล์ที่กำหนดไว้ล่วงหน้าโดยใช้โครงสร้างดังนี้ -
pf_size, name, vol_info, vol_entries, vol_size, filetime, \
count = struct.unpack("<i60s32x3iq16xi",prefetch_file.read_random(12, 136))
name = name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]
vol_name_offset, vol_name_length, vol_create, \
vol_serial = struct.unpack("<2iqi",prefetch_file.read_random(vol_info, 20))
vol_serial = hex(vol_serial).lstrip("0x")
vol_serial = vol_serial[:4] + "-" + vol_serial[4:]
vol_name = struct.unpack(
"<{}s".format(2 * vol_name_length),
prefetch_file.read_random(vol_info + vol_name_offset,vol_name_length * 2))[0]
vol_name = vol_name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]
return [
pf_name, name, pf_size, create,
modify, convert_filetime(filetime), count, vol_name,
convert_filetime(vol_create), vol_serial ]
เนื่องจากเราได้จัดเตรียมเวอร์ชันการดึงข้อมูลล่วงหน้าสำหรับ Windows XP แต่จะเกิดอะไรขึ้นหากพบเวอร์ชันการดึงข้อมูลล่วงหน้าสำหรับ Windows อื่น ๆ จากนั้นจะต้องแสดงข้อความแสดงข้อผิดพลาดดังนี้ -
elif pf_version == 23:
print("[-] Windows Vista / 7 PF file {} -- unsupported".format(pf_name))
continue
elif pf_version == 26:
print("[-] Windows 8 PF file {} -- unsupported".format(pf_name))
continue
elif pf_version == 30:
print("[-] Windows 10 PF file {} -- unsupported".format(pf_name))
continue
else:
print("[-] Signature mismatch - Name: {}\nPath: {}".format(hit[0], hit[1]))
continue
write_output(prefetch_data, output_csv)
ตอนนี้กำหนดวิธีการเขียนผลลัพธ์ลงในรายงาน CSV ดังนี้ -
def write_output(data, output_csv):
print("[+] Writing csv report")
with open(output_csv, "wb") as outfile:
writer = csv.writer(outfile)
writer.writerow([
"File Name", "Prefetch Name", "File Size (bytes)",
"File Create Date (UTC)", "File Modify Date (UTC)",
"Prefetch Last Execution Date (UTC)",
"Prefetch Execution Count", "Volume", "Volume Create Date",
"Volume Serial", "File Path" ])
writer.writerows(data)
หลังจากเรียกใช้สคริปต์ข้างต้นเราจะได้รับข้อมูลจากการดึงไฟล์ล่วงหน้าของเวอร์ชัน Windows XP ลงในสเปรดชีต
บทนี้จะอธิบายเกี่ยวกับสิ่งประดิษฐ์เพิ่มเติมที่นักวิจัยสามารถหาได้ในระหว่างการวิเคราะห์ทางนิติวิทยาศาสตร์บน Windows
บันทึกเหตุการณ์
ไฟล์บันทึกเหตุการณ์ของ Windows ในฐานะชื่อ - กระเป๋าเป็นไฟล์พิเศษที่เก็บเหตุการณ์สำคัญเช่นเมื่อผู้ใช้เข้าสู่ระบบคอมพิวเตอร์เมื่อโปรแกรมพบข้อผิดพลาดเกี่ยวกับการเปลี่ยนแปลงระบบการเข้าถึง RDP เหตุการณ์เฉพาะของแอปพลิเคชันเป็นต้นผู้ตรวจสอบไซเบอร์มักสนใจเหตุการณ์ ข้อมูลบันทึกเนื่องจากมีข้อมูลประวัติที่เป็นประโยชน์มากมายเกี่ยวกับการเข้าถึงระบบ ในสคริปต์ Python ต่อไปนี้เราจะประมวลผลทั้งรูปแบบบันทึกเหตุการณ์ Windows แบบเดิมและแบบปัจจุบัน
สำหรับสคริปต์ Python เราจำเป็นต้องติดตั้งโมดูลของบุคคลที่สามคือ pytsk3, pyewf, unicodecsv, pyevt and pyevtx. เราสามารถทำตามขั้นตอนด้านล่างเพื่อดึงข้อมูลจากบันทึกเหตุการณ์ -
ขั้นแรกค้นหาบันทึกเหตุการณ์ทั้งหมดที่ตรงกับอาร์กิวเมนต์อินพุต
จากนั้นทำการตรวจสอบลายเซ็นไฟล์
ตอนนี้ประมวลผลบันทึกเหตุการณ์แต่ละรายการที่พบด้วยไลบรารีที่เหมาะสม
สุดท้ายเขียนผลลัพธ์ลงในสเปรดชีต
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นให้นำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
import argparse
import unicodecsv as csv
import os
import pytsk3
import pyewf
import pyevt
import pyevtx
import sys
from utility.pytskutil import TSKUtil
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง โปรดทราบว่าที่นี่จะยอมรับสามอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังไฟล์หลักฐานอันดับที่สองคือประเภทของไฟล์หลักฐานและที่สามคือชื่อของบันทึกเหตุการณ์ที่จะดำเนินการ
if __name__ == "__main__":
parser = argparse.ArgumentParser('Information from Event Logs')
parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
parser.add_argument(
"LOG_NAME",help = "Event Log Name (SecEvent.Evt, SysEvent.Evt, ""etc.)")
parser.add_argument(
"-d", help = "Event log directory to scan",default = "/WINDOWS/SYSTEM32/WINEVT")
parser.add_argument(
"-f", help = "Enable fuzzy search for either evt or"" evtx extension", action = "store_true")
args = parser.parse_args()
if os.path.exists(args.EVIDENCE_FILE) and \ os.path.isfile(args.EVIDENCE_FILE):
main(args.EVIDENCE_FILE, args.TYPE, args.LOG_NAME, args.d, args.f)
else:
print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
sys.exit(1)
ตอนนี้โต้ตอบกับบันทึกเหตุการณ์เพื่อสอบถามการมีอยู่ของเส้นทางที่ผู้ใช้ระบุโดยการสร้างไฟล์ TSKUtilวัตถุ. สามารถทำได้ด้วยความช่วยเหลือของmain() วิธีการดังนี้ -
def main(evidence, image_type, log, win_event, fuzzy):
tsk_util = TSKUtil(evidence, image_type)
event_dir = tsk_util.query_directory(win_event)
if event_dir is not None:
if fuzzy is True:
event_log = tsk_util.recurse_files(log, path=win_event)
else:
event_log = tsk_util.recurse_files(log, path=win_event, logic="equal")
if event_log is not None:
event_data = []
for hit in event_log:
event_file = hit[2]
temp_evt = write_file(event_file)
ตอนนี้เราต้องทำการตรวจสอบลายเซ็นตามด้วยการกำหนดวิธีการที่จะเขียนเนื้อหาทั้งหมดไปยังไดเร็กทอรีปัจจุบัน -
def write_file(event_file):
with open(event_file.info.name.name, "w") as outfile:
outfile.write(event_file.read_random(0, event_file.info.meta.size))
return event_file.info.name.name
if pyevt.check_file_signature(temp_evt):
evt_log = pyevt.open(temp_evt)
print("[+] Identified {} records in {}".format(
evt_log.number_of_records, temp_evt))
for i, record in enumerate(evt_log.records):
strings = ""
for s in record.strings:
if s is not None:
strings += s + "\n"
event_data.append([
i, hit[0], record.computer_name,
record.user_security_identifier,
record.creation_time, record.written_time,
record.event_category, record.source_name,
record.event_identifier, record.event_type,
strings, "",
os.path.join(win_event, hit[1].lstrip("//"))
])
elif pyevtx.check_file_signature(temp_evt):
evtx_log = pyevtx.open(temp_evt)
print("[+] Identified {} records in {}".format(
evtx_log.number_of_records, temp_evt))
for i, record in enumerate(evtx_log.records):
strings = ""
for s in record.strings:
if s is not None:
strings += s + "\n"
event_data.append([
i, hit[0], record.computer_name,
record.user_security_identifier, "",
record.written_time, record.event_level,
record.source_name, record.event_identifier,
"", strings, record.xml_string,
os.path.join(win_event, hit[1].lstrip("//"))
])
else:
print("[-] {} not a valid event log. Removing temp" file...".format(temp_evt))
os.remove(temp_evt)
continue
write_output(event_data)
else:
print("[-] {} Event log not found in {} directory".format(log, win_event))
sys.exit(3)
else:
print("[-] Win XP Event Log Directory {} not found".format(win_event))
sys.exit(2
สุดท้ายกำหนดวิธีการเขียนผลลัพธ์ไปยังสเปรดชีตดังนี้ -
def write_output(data):
output_name = "parsed_event_logs.csv"
print("[+] Writing {} to current working directory: {}".format(
output_name, os.getcwd()))
with open(output_name, "wb") as outfile:
writer = csv.writer(outfile)
writer.writerow([
"Index", "File name", "Computer Name", "SID",
"Event Create Date", "Event Written Date",
"Event Category/Level", "Event Source", "Event ID",
"Event Type", "Data", "XML Data", "File Path"
])
writer.writerows(data)
เมื่อคุณเรียกใช้สคริปต์ข้างต้นสำเร็จเราจะได้รับข้อมูลการบันทึกเหตุการณ์ในสเปรดชีต
ประวัติอินเทอร์เน็ต
ประวัติอินเทอร์เน็ตมีประโยชน์มากสำหรับนักวิเคราะห์ทางนิติวิทยาศาสตร์ เนื่องจากอาชญากรรมทางไซเบอร์ส่วนใหญ่เกิดขึ้นบนอินเทอร์เน็ตเท่านั้น ให้เราดูวิธีดึงประวัติอินเทอร์เน็ตจาก Internet Explorer ในขณะที่เราพูดคุยเกี่ยวกับการพิสูจน์หลักฐานของ Windows และ Internet Explorer มาพร้อมกับ Windows โดยค่าเริ่มต้น
บน Internet Explorer ประวัติอินเทอร์เน็ตจะถูกบันทึกไว้ใน index.datไฟล์. ให้เราดูสคริปต์ Python ซึ่งจะดึงข้อมูลจากindex.dat ไฟล์.
เราสามารถทำตามขั้นตอนด้านล่างเพื่อดึงข้อมูลจาก index.dat ไฟล์ -
ขั้นแรกให้ค้นหา index.dat ไฟล์ภายในระบบ
จากนั้นแยกข้อมูลจากไฟล์นั้นโดยทำซ้ำผ่านไฟล์เหล่านั้น
ตอนนี้เขียนข้อมูลทั้งหมดลงในรายงาน CSV
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นให้นำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
import argparse
from datetime import datetime, timedelta
import os
import pytsk3
import pyewf
import pymsiecf
import sys
import unicodecsv as csv
from utility.pytskutil import TSKUtil
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง โปรดทราบว่าที่นี่จะยอมรับสองอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังไฟล์หลักฐานและที่สองจะเป็นประเภทของไฟล์หลักฐาน -
if __name__ == "__main__":
parser = argparse.ArgumentParser('getting information from internet history')
parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
parser.add_argument("-d", help = "Index.dat directory to scan",default = "/USERS")
args = parser.parse_args()
if os.path.exists(args.EVIDENCE_FILE) and os.path.isfile(args.EVIDENCE_FILE):
main(args.EVIDENCE_FILE, args.TYPE, args.d)
else:
print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
sys.exit(1)
ตอนนี้ตีความไฟล์หลักฐานโดยสร้างวัตถุของ TSKUtilและวนซ้ำผ่านระบบไฟล์เพื่อค้นหาไฟล์ index.dat สามารถทำได้โดยกำหนดไฟล์main() ฟังก์ชันดังต่อไปนี้ -
def main(evidence, image_type, path):
tsk_util = TSKUtil(evidence, image_type)
index_dir = tsk_util.query_directory(path)
if index_dir is not None:
index_files = tsk_util.recurse_files("index.dat", path = path,logic = "equal")
if index_files is not None:
print("[+] Identified {} potential index.dat files".format(len(index_files)))
index_data = []
for hit in index_files:
index_file = hit[2]
temp_index = write_file(index_file)
ตอนนี้กำหนดฟังก์ชันด้วยความช่วยเหลือซึ่งเราสามารถคัดลอกข้อมูลของไฟล์ index.dat ไปยังไดเร็กทอรีการทำงานปัจจุบันและในภายหลังสามารถประมวลผลโดยโมดูลของบุคคลที่สาม -
def write_file(index_file):
with open(index_file.info.name.name, "w") as outfile:
outfile.write(index_file.read_random(0, index_file.info.meta.size))
return index_file.info.name.name
ตอนนี้ใช้รหัสต่อไปนี้เพื่อทำการตรวจสอบลายเซ็นด้วยความช่วยเหลือของฟังก์ชันในตัวคือ check_file_signature() -
if pymsiecf.check_file_signature(temp_index):
index_dat = pymsiecf.open(temp_index)
print("[+] Identified {} records in {}".format(
index_dat.number_of_items, temp_index))
for i, record in enumerate(index_dat.items):
try:
data = record.data
if data is not None:
data = data.rstrip("\x00")
except AttributeError:
if isinstance(record, pymsiecf.redirected):
index_data.append([
i, temp_index, "", "", "", "", "",record.location, "", "", record.offset,os.path.join(path, hit[1].lstrip("//"))])
elif isinstance(record, pymsiecf.leak):
index_data.append([
i, temp_index, record.filename, "","", "", "", "", "", "", record.offset,os.path.join(path, hit[1].lstrip("//"))])
continue
index_data.append([
i, temp_index, record.filename,
record.type, record.primary_time,
record.secondary_time,
record.last_checked_time, record.location,
record.number_of_hits, data, record.offset,
os.path.join(path, hit[1].lstrip("//"))
])
else:
print("[-] {} not a valid index.dat file. Removing "
"temp file..".format(temp_index))
os.remove("index.dat")
continue
os.remove("index.dat")
write_output(index_data)
else:
print("[-] Index.dat files not found in {} directory".format(path))
sys.exit(3)
else:
print("[-] Directory {} not found".format(win_event))
sys.exit(2)
ตอนนี้กำหนดวิธีการที่จะพิมพ์ผลลัพธ์ในไฟล์ CSV ดังที่แสดงด้านล่าง -
def write_output(data):
output_name = "Internet_Indexdat_Summary_Report.csv"
print("[+] Writing {} with {} parsed index.dat files to current "
"working directory: {}".format(output_name, len(data),os.getcwd()))
with open(output_name, "wb") as outfile:
writer = csv.writer(outfile)
writer.writerow(["Index", "File Name", "Record Name",
"Record Type", "Primary Date", "Secondary Date",
"Last Checked Date", "Location", "No. of Hits",
"Record Data", "Record Offset", "File Path"])
writer.writerows(data)
หลังจากเรียกใช้สคริปต์ด้านบนเราจะได้รับข้อมูลจากไฟล์ index.dat ในไฟล์ CSV
สำเนาเงาระดับเสียง
Shadow Copy เป็นเทคโนโลยีที่รวมอยู่ใน Windows สำหรับการถ่ายสำเนาสำรองหรือภาพรวมของไฟล์คอมพิวเตอร์ด้วยตนเองหรือโดยอัตโนมัติ เรียกอีกอย่างว่า Volume Snapshot Service หรือ Volume Shadow Service (VSS)
ด้วยความช่วยเหลือของไฟล์ VSS เหล่านี้ผู้เชี่ยวชาญด้านนิติวิทยาศาสตร์สามารถมีข้อมูลในอดีตเกี่ยวกับการเปลี่ยนแปลงของระบบเมื่อเวลาผ่านไปและไฟล์ใดที่มีอยู่ในคอมพิวเตอร์ เทคโนโลยี Shadow copy กำหนดให้ระบบไฟล์เป็น NTFS สำหรับการสร้างและจัดเก็บ Shadow copy
ในส่วนนี้เราจะเห็นสคริปต์ Python ซึ่งช่วยในการเข้าถึงสำเนาเงาที่มีอยู่ในภาพทางนิติวิทยาศาสตร์
สำหรับสคริปต์ Python เราจำเป็นต้องติดตั้งโมดูลของบุคคลที่สามคือ pytsk3, pyewf, unicodecsv, pyvshadow และ vss. เราสามารถทำตามขั้นตอนด้านล่างเพื่อดึงข้อมูลจากไฟล์ VSS
ขั้นแรกให้เข้าถึงปริมาณของอิมเมจดิบและระบุพาร์ติชัน NTFS ทั้งหมด
จากนั้นแยกข้อมูลจากสำเนาเงานั้นโดยทำซ้ำผ่านข้อมูลเหล่านั้น
ในที่สุดเราต้องสร้างรายชื่อไฟล์ข้อมูลภายในสแนปชอต
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ก่อนอื่นให้นำเข้าไลบรารี Python ต่อไปนี้ -
from __future__ import print_function
import argparse
from datetime import datetime, timedelta
import os
import pytsk3
import pyewf
import pyvshadow
import sys
import unicodecsv as csv
from utility import vss
from utility.pytskutil import TSKUtil
from utility import pytskutil
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสองอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังไฟล์หลักฐานและที่สองคือไฟล์เอาต์พุต
if __name__ == "__main__":
parser = argparse.ArgumentParser('Parsing Shadow Copies')
parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
parser.add_argument("OUTPUT_CSV", help = "Output CSV with VSS file listing")
args = parser.parse_args()
ตอนนี้ตรวจสอบการมีอยู่ของพา ธ ไฟล์อินพุตและแยกไดเร็กทอรีออกจากไฟล์เอาต์พุต
directory = os.path.dirname(args.OUTPUT_CSV)
if not os.path.exists(directory) and directory != "":
os.makedirs(directory)
if os.path.exists(args.EVIDENCE_FILE) and \ os.path.isfile(args.EVIDENCE_FILE):
main(args.EVIDENCE_FILE, args.OUTPUT_CSV)
else:
print("[-] Supplied input file {} does not exist or is not a "
"file".format(args.EVIDENCE_FILE))
sys.exit(1)
ตอนนี้โต้ตอบกับโวลุ่มของไฟล์หลักฐานโดยสร้างไฟล์ TSKUtilวัตถุ. สามารถทำได้ด้วยความช่วยเหลือของmain() วิธีการดังนี้ -
def main(evidence, output):
tsk_util = TSKUtil(evidence, "raw")
img_vol = tsk_util.return_vol()
if img_vol is not None:
for part in img_vol:
if tsk_util.detect_ntfs(img_vol, part):
print("Exploring NTFS Partition for VSS")
explore_vss(evidence, part.start * img_vol.info.block_size,output)
else:
print("[-] Must be a physical preservation to be compatible ""with this script")
sys.exit(2)
ตอนนี้กำหนดวิธีการสำรวจไฟล์เงาของไดรฟ์ข้อมูลที่แยกวิเคราะห์ดังนี้ -
def explore_vss(evidence, part_offset, output):
vss_volume = pyvshadow.volume()
vss_handle = vss.VShadowVolume(evidence, part_offset)
vss_count = vss.GetVssStoreCount(evidence, part_offset)
if vss_count > 0:
vss_volume.open_file_object(vss_handle)
vss_data = []
for x in range(vss_count):
print("Gathering data for VSC {} of {}".format(x, vss_count))
vss_store = vss_volume.get_store(x)
image = vss.VShadowImgInfo(vss_store)
vss_data.append(pytskutil.openVSSFS(image, x))
write_csv(vss_data, output)
สุดท้ายกำหนดวิธีการเขียนผลลัพธ์ในสเปรดชีตดังนี้ -
def write_csv(data, output):
if data == []:
print("[-] No output results to write")
sys.exit(3)
print("[+] Writing output to {}".format(output))
if os.path.exists(output):
append = True
with open(output, "ab") as csvfile:
csv_writer = csv.writer(csvfile)
headers = ["VSS", "File", "File Ext", "File Type", "Create Date",
"Modify Date", "Change Date", "Size", "File Path"]
if not append:
csv_writer.writerow(headers)
for result_list in data:
csv_writer.writerows(result_list)
เมื่อคุณรันสคริปต์ Python นี้สำเร็จเราจะรับข้อมูลที่อยู่ใน VSS ลงในสเปรดชีต
จนถึงตอนนี้เราได้เห็นวิธีการรับสิ่งประดิษฐ์ใน Windows โดยใช้ Python ในบทนี้ให้เราเรียนรู้เกี่ยวกับการตรวจสอบสิ่งประดิษฐ์จากบันทึกโดยใช้ Python
บทนำ
สิ่งประดิษฐ์ที่ใช้บันทึกเป็นขุมทรัพย์ของข้อมูลที่มีประโยชน์มากสำหรับผู้เชี่ยวชาญด้านนิติวิทยาศาสตร์ดิจิทัล แม้ว่าเราจะมีซอฟต์แวร์ตรวจสอบต่างๆสำหรับรวบรวมข้อมูล แต่ปัญหาหลักในการแยกวิเคราะห์ข้อมูลที่เป็นประโยชน์จากข้อมูลเหล่านี้คือเราต้องการข้อมูลจำนวนมาก
สิ่งประดิษฐ์ตามบันทึกต่างๆและการตรวจสอบใน Python
ในส่วนนี้ให้เราพูดคุยถึงสิ่งประดิษฐ์ตามบันทึกต่างๆและการตรวจสอบใน Python -
การประทับเวลา
การประทับเวลาบ่งบอกข้อมูลและเวลาของกิจกรรมในบันทึก เป็นองค์ประกอบที่สำคัญอย่างหนึ่งของไฟล์บันทึกใด ๆ โปรดทราบว่าค่าข้อมูลและเวลาเหล่านี้อาจอยู่ในรูปแบบต่างๆ
สคริปต์ Python ที่แสดงด้านล่างจะใช้วันที่ - เวลาดิบเป็นอินพุตและจัดเตรียมการประทับเวลาที่จัดรูปแบบเป็นเอาต์พุต
สำหรับสคริปต์นี้เราต้องทำตามขั้นตอนต่อไปนี้ -
ขั้นแรกตั้งค่าอาร์กิวเมนต์ที่จะรับค่าข้อมูลดิบพร้อมกับแหล่งที่มาของข้อมูลและประเภทข้อมูล
ตอนนี้จัดเตรียมคลาสสำหรับการจัดเตรียมอินเทอร์เฟซทั่วไปสำหรับข้อมูลในรูปแบบวันที่ต่างๆ
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ขั้นแรกให้นำเข้าโมดูล Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from datetime import datetime as dt
from datetime import timedelta
ตามปกติแล้วเราต้องจัดเตรียมอาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสามอาร์กิวเมนต์อันดับแรกคือค่าวันที่ที่จะประมวลผลอันดับที่สองจะเป็นแหล่งที่มาของค่าวันที่นั้นและที่สามจะเป็นประเภท -
if __name__ == '__main__':
parser = ArgumentParser('Timestamp Log-based artifact')
parser.add_argument("date_value", help="Raw date value to parse")
parser.add_argument(
"source", help = "Source format of date",choices = ParseDate.get_supported_formats())
parser.add_argument(
"type", help = "Data type of input value",choices = ('number', 'hex'), default = 'int')
args = parser.parse_args()
date_parser = ParseDate(args.date_value, args.source, args.type)
date_parser.run()
print(date_parser.timestamp)
ตอนนี้เราต้องกำหนดคลาสซึ่งจะยอมรับอาร์กิวเมนต์สำหรับค่าวันที่มาวันที่และประเภทค่า -
class ParseDate(object):
def __init__(self, date_value, source, data_type):
self.date_value = date_value
self.source = source
self.data_type = data_type
self.timestamp = None
ตอนนี้เราจะกำหนดเมธอดที่จะทำหน้าที่เหมือนคอนโทรลเลอร์เหมือนกับเมธอด main () -
def run(self):
if self.source == 'unix-epoch':
self.parse_unix_epoch()
elif self.source == 'unix-epoch-ms':
self.parse_unix_epoch(True)
elif self.source == 'windows-filetime':
self.parse_windows_filetime()
@classmethod
def get_supported_formats(cls):
return ['unix-epoch', 'unix-epoch-ms', 'windows-filetime']
ตอนนี้เราต้องกำหนดสองวิธีซึ่งจะประมวลผลเวลา Unix epoch และ FILETIME ตามลำดับ -
def parse_unix_epoch(self, milliseconds=False):
if self.data_type == 'hex':
conv_value = int(self.date_value)
if milliseconds:
conv_value = conv_value / 1000.0
elif self.data_type == 'number':
conv_value = float(self.date_value)
if milliseconds:
conv_value = conv_value / 1000.0
else:
print("Unsupported data type '{}' provided".format(self.data_type))
sys.exit('1')
ts = dt.fromtimestamp(conv_value)
self.timestamp = ts.strftime('%Y-%m-%d %H:%M:%S.%f')
def parse_windows_filetime(self):
if self.data_type == 'hex':
microseconds = int(self.date_value, 16) / 10.0
elif self.data_type == 'number':
microseconds = float(self.date_value) / 10
else:
print("Unsupported data type '{}' provided".format(self.data_type))
sys.exit('1')
ts = dt(1601, 1, 1) + timedelta(microseconds=microseconds)
self.timestamp = ts.strftime('%Y-%m-%d %H:%M:%S.%f')
หลังจากเรียกใช้สคริปต์ข้างต้นโดยการระบุเวลาเราจะได้รับค่าที่แปลงแล้วในรูปแบบที่อ่านง่าย
บันทึกเว็บเซิร์ฟเวอร์
จากมุมมองของผู้เชี่ยวชาญด้านนิติวิทยาศาสตร์ดิจิทัลบันทึกของเว็บเซิร์ฟเวอร์เป็นสิ่งประดิษฐ์ที่สำคัญอีกอย่างหนึ่งเนื่องจากสามารถรับสถิติผู้ใช้ที่เป็นประโยชน์พร้อมกับข้อมูลเกี่ยวกับผู้ใช้และตำแหน่งทางภูมิศาสตร์ ต่อไปนี้เป็นสคริปต์ Python ที่จะสร้างสเปรดชีตหลังจากประมวลผลบันทึกของเว็บเซิร์ฟเวอร์เพื่อให้วิเคราะห์ข้อมูลได้ง่าย
ก่อนอื่นเราต้องนำเข้าโมดูล Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser, FileType
import re
import shlex
import logging
import sys
import csv
logger = logging.getLogger(__file__)
ตอนนี้เราต้องกำหนดรูปแบบที่จะแยกวิเคราะห์จากบันทึก -
iis_log_format = [
("date", re.compile(r"\d{4}-\d{2}-\d{2}")),
("time", re.compile(r"\d\d:\d\d:\d\d")),
("s-ip", re.compile(
r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}")),
("cs-method", re.compile(
r"(GET)|(POST)|(PUT)|(DELETE)|(OPTIONS)|(HEAD)|(CONNECT)")),
("cs-uri-stem", re.compile(r"([A-Za-z0-1/\.-]*)")),
("cs-uri-query", re.compile(r"([A-Za-z0-1/\.-]*)")),
("s-port", re.compile(r"\d*")),
("cs-username", re.compile(r"([A-Za-z0-1/\.-]*)")),
("c-ip", re.compile(
r"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}")),
("cs(User-Agent)", re.compile(r".*")),
("sc-status", re.compile(r"\d*")),
("sc-substatus", re.compile(r"\d*")),
("sc-win32-status", re.compile(r"\d*")),
("time-taken", re.compile(r"\d*"))]
ตอนนี้ให้อาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง ที่นี่จะยอมรับสองอาร์กิวเมนต์อันดับแรกคือบันทึก IIS ที่จะประมวลผลอันดับที่สองคือพา ธ ไฟล์ CSV ที่ต้องการ
if __name__ == '__main__':
parser = ArgumentParser('Parsing Server Based Logs')
parser.add_argument('iis_log', help = "Path to IIS Log",type = FileType('r'))
parser.add_argument('csv_report', help = "Path to CSV report")
parser.add_argument('-l', help = "Path to processing log",default=__name__ + '.log')
args = parser.parse_args()
logger.setLevel(logging.DEBUG)
msg_fmt = logging.Formatter(
"%(asctime)-15s %(funcName)-10s ""%(levelname)-8s %(message)s")
strhndl = logging.StreamHandler(sys.stdout)
strhndl.setFormatter(fmt = msg_fmt)
fhndl = logging.FileHandler(args.log, mode = 'a')
fhndl.setFormatter(fmt = msg_fmt)
logger.addHandler(strhndl)
logger.addHandler(fhndl)
logger.info("Starting IIS Parsing ")
logger.debug("Supplied arguments: {}".format(", ".join(sys.argv[1:])))
logger.debug("System " + sys.platform)
logger.debug("Version " + sys.version)
main(args.iis_log, args.csv_report, logger)
iologger.info("IIS Parsing Complete")
ตอนนี้เราต้องกำหนดเมธอด main () ที่จะจัดการสคริปต์สำหรับข้อมูลบันทึกจำนวนมาก -
def main(iis_log, report_file, logger):
parsed_logs = []
for raw_line in iis_log:
line = raw_line.strip()
log_entry = {}
if line.startswith("#") or len(line) == 0:
continue
if '\"' in line:
line_iter = shlex.shlex(line_iter)
else:
line_iter = line.split(" ")
for count, split_entry in enumerate(line_iter):
col_name, col_pattern = iis_log_format[count]
if col_pattern.match(split_entry):
log_entry[col_name] = split_entry
else:
logger.error("Unknown column pattern discovered. "
"Line preserved in full below")
logger.error("Unparsed Line: {}".format(line))
parsed_logs.append(log_entry)
logger.info("Parsed {} lines".format(len(parsed_logs)))
cols = [x[0] for x in iis_log_format]
logger.info("Creating report file: {}".format(report_file))
write_csv(report_file, cols, parsed_logs)
logger.info("Report created")
สุดท้ายเราต้องกำหนดวิธีการที่จะเขียนผลลัพธ์ลงในสเปรดชีต -
def write_csv(outfile, fieldnames, data):
with open(outfile, 'w', newline="") as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
หลังจากเรียกใช้สคริปต์ข้างต้นเราจะได้รับบันทึกจากเว็บเซิร์ฟเวอร์ในสเปรดชีต
การสแกนไฟล์สำคัญโดยใช้ YARA
YARA (อีกหนึ่งอัลกอริทึมซ้ำ) เป็นยูทิลิตี้จับคู่รูปแบบที่ออกแบบมาสำหรับการระบุมัลแวร์และการตอบสนองต่อเหตุการณ์ เราจะใช้ YARA สำหรับการสแกนไฟล์ ในสคริปต์ Python ต่อไปนี้เราจะใช้ YARA
เราสามารถติดตั้ง YARA ด้วยความช่วยเหลือของคำสั่งต่อไปนี้ -
pip install YARA
เราสามารถทำตามขั้นตอนด้านล่างสำหรับการใช้กฎ YARA เพื่อสแกนไฟล์ -
ขั้นแรกตั้งค่าและรวบรวมกฎ YARA
จากนั้นสแกนไฟล์เดียวแล้ววนซ้ำผ่านไดเรกทอรีเพื่อประมวลผลไฟล์แต่ละไฟล์
สุดท้ายนี้เราจะส่งออกผลลัพธ์เป็น CSV
รหัส Python
ให้เราดูวิธีใช้รหัส Python เพื่อจุดประสงค์นี้ -
ขั้นแรกเราต้องนำเข้าโมดูล Python ต่อไปนี้ -
from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
import os
import csv
import yara
จากนั้นจัดเตรียมอาร์กิวเมนต์สำหรับตัวจัดการบรรทัดคำสั่ง โปรดทราบว่าที่นี่จะยอมรับสองอาร์กิวเมนต์ - อันดับแรกคือพา ธ ไปยังกฎ YARA อันดับที่สองคือไฟล์ที่จะสแกน
if __name__ == '__main__':
parser = ArgumentParser('Scanning files by YARA')
parser.add_argument(
'yara_rules',help = "Path to Yara rule to scan with. May be file or folder path.")
parser.add_argument('path_to_scan',help = "Path to file or folder to scan")
parser.add_argument('--output',help = "Path to output a CSV report of scan results")
args = parser.parse_args()
main(args.yara_rules, args.path_to_scan, args.output)
ตอนนี้เราจะกำหนดฟังก์ชัน main () ที่จะยอมรับเส้นทางไปยังกฎของ yara และไฟล์ที่จะสแกน -
def main(yara_rules, path_to_scan, output):
if os.path.isdir(yara_rules):
yrules = yara.compile(yara_rules)
else:
yrules = yara.compile(filepath=yara_rules)
if os.path.isdir(path_to_scan):
match_info = process_directory(yrules, path_to_scan)
else:
match_info = process_file(yrules, path_to_scan)
columns = ['rule_name', 'hit_value', 'hit_offset', 'file_name',
'rule_string', 'rule_tag']
if output is None:
write_stdout(columns, match_info)
else:
write_csv(output, columns, match_info)
ตอนนี้กำหนดวิธีการที่จะวนซ้ำผ่านไดเร็กทอรีและส่งผลลัพธ์ไปยังวิธีการอื่นสำหรับการประมวลผลเพิ่มเติม -
def process_directory(yrules, folder_path):
match_info = []
for root, _, files in os.walk(folder_path):
for entry in files:
file_entry = os.path.join(root, entry)
match_info += process_file(yrules, file_entry)
return match_info
จากนั้นกำหนดสองฟังก์ชัน โปรดทราบว่าก่อนอื่นเราจะใช้match() วิธีการ yrulesออบเจ็กต์และอีกรายการจะรายงานข้อมูลที่ตรงกันไปยังคอนโซลหากผู้ใช้ไม่ระบุไฟล์เอาต์พุตใด ๆ สังเกตโค้ดที่แสดงด้านล่าง -
def process_file(yrules, file_path):
match = yrules.match(file_path)
match_info = []
for rule_set in match:
for hit in rule_set.strings:
match_info.append({
'file_name': file_path,
'rule_name': rule_set.rule,
'rule_tag': ",".join(rule_set.tags),
'hit_offset': hit[0],
'rule_string': hit[1],
'hit_value': hit[2]
})
return match_info
def write_stdout(columns, match_info):
for entry in match_info:
for col in columns:
print("{}: {}".format(col, entry[col]))
print("=" * 30)
สุดท้ายนี้เราจะกำหนดวิธีการที่จะเขียนผลลัพธ์ลงในไฟล์ CSV ดังที่แสดงด้านล่าง -
def write_csv(outfile, fieldnames, data):
with open(outfile, 'w', newline="") as open_outfile:
csvfile = csv.DictWriter(open_outfile, fieldnames)
csvfile.writeheader()
csvfile.writerows(data)
เมื่อคุณรันสคริปต์ข้างต้นสำเร็จแล้วเราสามารถจัดเตรียมอาร์กิวเมนต์ที่เหมาะสมที่บรรทัดคำสั่งและสามารถสร้างรายงาน CSV ได้