Điều tra đồ tạo tác dựa trên nhật ký

Cho đến bây giờ, chúng ta đã thấy cách lấy các tạo tác trong Windows bằng Python. Trong chương này, chúng ta hãy tìm hiểu về cách điều tra các tạo tác dựa trên nhật ký bằng Python.

Giới thiệu

Các hiện vật dựa trên nhật ký là kho tàng thông tin có thể rất hữu ích cho một chuyên gia pháp y kỹ thuật số. Mặc dù chúng tôi có nhiều phần mềm giám sát để thu thập thông tin, vấn đề chính để phân tích thông tin hữu ích từ chúng là chúng tôi cần nhiều dữ liệu.

Nhiều tạo tác dựa trên nhật ký và điều tra bằng Python

Trong phần này, chúng ta hãy thảo luận về các tạo tác dựa trên nhật ký khác nhau và điều tra của chúng bằng Python -

Dấu thời gian

Dấu thời gian truyền tải dữ liệu và thời gian của hoạt động trong nhật ký. Nó là một trong những yếu tố quan trọng của bất kỳ tệp nhật ký nào. Lưu ý rằng các giá trị dữ liệu và thời gian này có thể có nhiều định dạng khác nhau.

Tập lệnh Python được hiển thị bên dưới sẽ lấy ngày-giờ thô làm đầu vào và cung cấp dấu thời gian được định dạng làm đầu ra của nó.

Đối với tập lệnh này, chúng ta cần làm theo các bước sau:

  • Đầu tiên, hãy thiết lập các đối số sẽ nhận giá trị dữ liệu thô cùng với nguồn dữ liệu và kiểu dữ liệu.

  • Bây giờ, hãy cung cấp một lớp để cung cấp giao diện chung cho dữ liệu trên các định dạng ngày tháng khác nhau.

Mã Python

Hãy để chúng tôi xem cách sử dụng mã Python cho mục đích này -

Đầu tiên, nhập các mô-đun Python sau:

from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from datetime import datetime as dt
from datetime import timedelta

Bây giờ, như thường lệ, chúng ta cần cung cấp đối số cho trình xử lý dòng lệnh. Ở đây nó sẽ chấp nhận ba đối số, đầu tiên sẽ là giá trị ngày được xử lý, thứ hai sẽ là nguồn của giá trị ngày đó và thứ ba sẽ là loại của nó -

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)

Bây giờ, chúng ta cần xác định một lớp sẽ chấp nhận các đối số cho giá trị ngày, nguồn ngày và kiểu giá trị -

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

Bây giờ chúng ta sẽ định nghĩa một phương thức sẽ hoạt động giống như một bộ điều khiển giống như phương thức 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']

Bây giờ, chúng ta cần xác định hai phương thức sẽ xử lý thời gian kỷ nguyên Unix và FILETIME tương ứng -

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')

Sau khi chạy tập lệnh trên, bằng cách cung cấp dấu thời gian, chúng tôi có thể nhận được giá trị được chuyển đổi ở định dạng dễ đọc.

Nhật ký Máy chủ Web

Theo quan điểm của chuyên gia pháp y kỹ thuật số, nhật ký máy chủ web là một tạo tác quan trọng khác vì chúng có thể nhận được số liệu thống kê hữu ích của người dùng cùng với thông tin về người dùng và vị trí địa lý. Sau đây là tập lệnh Python sẽ tạo một bảng tính, sau khi xử lý nhật ký máy chủ web, để dễ dàng phân tích thông tin.

Trước hết, chúng ta cần nhập các mô-đun Python sau:

from __future__ import print_function
from argparse import ArgumentParser, FileType

import re
import shlex
import logging
import sys
import csv

logger = logging.getLogger(__file__)

Bây giờ, chúng ta cần xác định các mẫu sẽ được phân tích cú pháp từ các bản ghi -

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*"))]

Bây giờ, cung cấp một đối số cho trình xử lý dòng lệnh. Ở đây nó sẽ chấp nhận hai đối số, đầu tiên sẽ là nhật ký IIS sẽ được xử lý, thứ hai là đường dẫn tệp CSV mong muốn.

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")

Bây giờ chúng ta cần xác định phương thức main () sẽ xử lý tập lệnh cho thông tin nhật ký hàng loạt -

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")

Cuối cùng, chúng ta cần xác định một phương thức sẽ ghi đầu ra vào bảng tính -

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)

Sau khi chạy tập lệnh trên, chúng ta sẽ nhận được nhật ký dựa trên máy chủ web trong một bảng tính.

Quét các tệp quan trọng bằng YARA

YARA (Yet Another Recursive Algorithm) là một tiện ích đối sánh mẫu được thiết kế để xác định phần mềm độc hại và phản ứng sự cố. Chúng tôi sẽ sử dụng YARA để quét các tệp. Trong tập lệnh Python sau, chúng tôi sẽ sử dụng YARA.

Chúng ta có thể cài đặt YARA với sự trợ giúp của lệnh sau:

pip install YARA

Chúng tôi có thể làm theo các bước được đưa ra bên dưới để sử dụng các quy tắc YARA để quét tệp -

  • Đầu tiên, thiết lập và biên dịch các quy tắc YARA

  • Sau đó, quét một tệp duy nhất và sau đó lặp qua các thư mục để xử lý các tệp riêng lẻ.

  • Cuối cùng, chúng tôi sẽ xuất kết quả sang CSV.

Mã Python

Hãy để chúng tôi xem cách sử dụng mã Python cho mục đích này -

Đầu tiên, chúng ta cần nhập các mô-đun Python sau:

from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter

import os
import csv
import yara

Tiếp theo, cung cấp đối số cho trình xử lý dòng lệnh. Lưu ý rằng ở đây nó sẽ chấp nhận hai đối số - đầu tiên là đường dẫn đến các quy tắc YARA, thứ hai là tệp được quét.

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)

Bây giờ chúng ta sẽ xác định hàm main () sẽ chấp nhận đường dẫn đến các quy tắc yara và tệp được quét -

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)

Bây giờ, hãy xác định một phương thức sẽ lặp qua thư mục và chuyển kết quả đến một phương thức khác để xử lý thêm -

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

Tiếp theo, xác định hai chức năng. Lưu ý rằng trước tiên chúng ta sẽ sử dụngmatch() phương pháp để yrulesđối tượng và đối tượng khác sẽ báo cáo thông tin trùng khớp đó với bảng điều khiển nếu người dùng không chỉ định bất kỳ tệp đầu ra nào. Quan sát đoạn mã được hiển thị bên dưới -

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)

Cuối cùng, chúng tôi sẽ xác định một phương thức sẽ ghi đầu ra vào tệp CSV, như được hiển thị bên dưới:

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)

Sau khi bạn chạy tập lệnh trên thành công, chúng tôi có thể cung cấp các đối số thích hợp tại dòng lệnh và có thể tạo báo cáo CSV.