Investigasi Artefak Berbasis Log

Sampai sekarang, kami telah melihat cara mendapatkan artefak di Windows menggunakan Python. Di bab ini, mari kita belajar tentang investigasi artefak berbasis log menggunakan Python.

pengantar

Artefak berbasis kayu gelondongan adalah harta karun informasi yang bisa sangat berguna bagi ahli forensik digital. Meskipun kami memiliki berbagai perangkat lunak pemantauan untuk mengumpulkan informasi, masalah utama untuk mengurai informasi yang berguna darinya adalah kami membutuhkan banyak data.

Berbagai Artefak Berbasis Log dan Investigasi dengan Python

Di bagian ini, mari kita bahas berbagai artefak berbasis log dan penyelidikannya dengan Python -

Stempel waktu

Stempel waktu menyampaikan data dan waktu aktivitas di log. Ini adalah salah satu elemen penting dari file log apa pun. Perhatikan bahwa data dan nilai waktu ini bisa datang dalam berbagai format.

Skrip Python yang ditunjukkan di bawah ini akan menggunakan tanggal-waktu mentah sebagai masukan dan memberikan stempel waktu yang diformat sebagai keluarannya.

Untuk skrip ini, kita perlu mengikuti langkah-langkah berikut -

  • Pertama, siapkan argumen yang akan mengambil nilai data mentah bersama dengan sumber data dan tipe datanya.

  • Sekarang, sediakan kelas untuk menyediakan antarmuka umum untuk data di berbagai format tanggal.

Kode Python

Mari kita lihat bagaimana menggunakan kode Python untuk tujuan ini -

Pertama, impor modul Python berikut -

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

Sekarang seperti biasa kita perlu memberikan argumen untuk penangan baris perintah. Di sini ia akan menerima tiga argumen, pertama adalah nilai tanggal yang akan diproses, kedua akan menjadi sumber nilai tanggal itu dan ketiga adalah tipenya -

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)

Sekarang, kita perlu mendefinisikan kelas yang akan menerima argumen untuk nilai tanggal, sumber tanggal, dan jenis nilai -

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

Sekarang kita akan mendefinisikan metode yang akan bertindak seperti pengontrol seperti metode 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']

Sekarang, kita perlu mendefinisikan dua metode yang masing-masing akan memproses waktu epoch Unix dan 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')

Setelah menjalankan skrip di atas, dengan memberikan stempel waktu kita bisa mendapatkan nilai yang dikonversi dalam format yang mudah dibaca.

Log Server Web

Dari sudut pandang ahli forensik digital, log server web adalah artefak penting lainnya karena mereka bisa mendapatkan statistik pengguna yang berguna bersama dengan informasi tentang pengguna dan lokasi geografis. Berikut ini adalah skrip Python yang akan membuat spreadsheet, setelah memproses log server web, untuk memudahkan analisis informasi.

Pertama-tama kita perlu mengimpor modul Python berikut -

from __future__ import print_function
from argparse import ArgumentParser, FileType

import re
import shlex
import logging
import sys
import csv

logger = logging.getLogger(__file__)

Sekarang, kita perlu menentukan pola yang akan diurai dari log -

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

Sekarang, berikan argumen untuk penangan baris perintah. Di sini akan menerima dua argumen, pertama akan menjadi log IIS yang akan diproses, yang kedua adalah jalur file CSV yang diinginkan.

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

Sekarang kita perlu mendefinisikan metode main () yang akan menangani skrip untuk informasi log massal -

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

Terakhir, kita perlu mendefinisikan metode yang akan menulis output ke spreadsheet -

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)

Setelah menjalankan skrip di atas kita akan mendapatkan log berbasis server web dalam spreadsheet.

Memindai File Penting menggunakan YARA

YARA (Yet Another Recursive Algorithm) adalah utilitas pencocokan pola yang dirancang untuk identifikasi malware dan respons insiden. Kami akan menggunakan YARA untuk memindai file. Dalam skrip Python berikut, kami akan menggunakan YARA.

Kami dapat menginstal YARA dengan bantuan perintah berikut -

pip install YARA

Kami dapat mengikuti langkah-langkah yang diberikan di bawah ini untuk menggunakan aturan YARA untuk memindai file -

  • Pertama, siapkan dan kompilasi aturan YARA

  • Kemudian, pindai satu file dan kemudian lakukan iterasi melalui direktori untuk memproses file individual.

  • Terakhir, kami akan mengekspor hasilnya ke CSV.

Kode Python

Mari kita lihat bagaimana menggunakan kode Python untuk tujuan ini -

Pertama, kita perlu mengimpor modul Python berikut -

from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter

import os
import csv
import yara

Selanjutnya, berikan argumen untuk penangan baris perintah. Perhatikan bahwa di sini ia akan menerima dua argumen - pertama adalah jalur ke aturan YARA, kedua adalah file yang akan dipindai.

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)

Sekarang kita akan menentukan fungsi main () yang akan menerima jalur ke aturan yara dan file yang akan dipindai -

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)

Sekarang, tentukan metode yang akan melakukan iterasi melalui direktori dan meneruskan hasilnya ke metode lain untuk diproses lebih lanjut -

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

Selanjutnya, tentukan dua fungsi. Perhatikan bahwa pertama kita akan menggunakanmatch() metode untuk yrulesobject dan lainnya akan melaporkan informasi yang cocok ke konsol jika pengguna tidak menentukan file output apa pun. Perhatikan kode yang ditunjukkan di bawah ini -

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)

Terakhir, kami akan menentukan metode yang akan menulis output ke file CSV, seperti yang ditunjukkan di bawah ini -

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)

Setelah Anda berhasil menjalankan skrip di atas, kami dapat memberikan argumen yang sesuai di baris perintah dan dapat membuat laporan CSV.