Python Digital Network Forensics-II

บทก่อนหน้านี้เกี่ยวกับแนวคิดบางประการของนิติเครือข่ายโดยใช้ Python ในบทนี้ให้เราเข้าใจนิติเครือข่ายโดยใช้ Python ในระดับที่ลึกขึ้น

การเก็บรักษาหน้าเว็บด้วยซุปที่สวยงาม

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

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

  • Change in Web Resources - ทรัพยากรบนเว็บมีการเปลี่ยนแปลงทุกวันซึ่งเป็นความท้าทายสำหรับการรักษาหน้าเว็บ

  • Large Quantity of Resources - อีกปัญหาหนึ่งที่เกี่ยวข้องกับการเก็บรักษาหน้าเว็บคือทรัพยากรจำนวนมากที่จะต้องเก็บรักษาไว้

  • Integrity - หน้าเว็บต้องได้รับการปกป้องจากการแก้ไขการลบหรือการลบโดยไม่ได้รับอนุญาตเพื่อปกป้องความสมบูรณ์

  • Dealing with multimedia data - ในขณะที่รักษาหน้าเว็บเราจำเป็นต้องจัดการกับข้อมูลมัลติมีเดียด้วยและสิ่งเหล่านี้อาจทำให้เกิดปัญหาในขณะที่ทำเช่นนั้น

  • Providing access - นอกจากการรักษาแล้วปัญหาของการให้การเข้าถึงทรัพยากรบนเว็บและการจัดการกับปัญหาการเป็นเจ้าของก็ต้องได้รับการแก้ไขเช่นกัน

ในบทนี้เราจะใช้ Python library ชื่อ 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 สำหรับการรักษาหน้าเว็บ

สคริปต์ 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 ในรูปแบบข้อความ