การตรวจสอบสิ่งประดิษฐ์จากบันทึก

จนถึงตอนนี้เราได้เห็นวิธีการรับสิ่งประดิษฐ์ใน 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 ได้