Điều tra bằng cách sử dụng email

Các chương trước đã thảo luận về tầm quan trọng và quy trình của pháp y mạng và các khái niệm liên quan. Trong chương này, chúng ta hãy tìm hiểu về vai trò của email trong pháp y kỹ thuật số và việc điều tra chúng bằng Python.

Vai trò của Email trong Điều tra

Email đóng một vai trò rất quan trọng trong giao tiếp kinh doanh và đã nổi lên như một trong những ứng dụng quan trọng nhất trên internet. Chúng là một chế độ thuận tiện để gửi tin nhắn cũng như tài liệu, không chỉ từ máy tính mà còn từ các thiết bị điện tử khác như điện thoại di động và máy tính bảng.

Mặt tiêu cực của email là bọn tội phạm có thể làm rò rỉ thông tin quan trọng về công ty của họ. Do đó, vai trò của email trong pháp y kỹ thuật số đã được gia tăng trong những năm gần đây. Trong pháp y kỹ thuật số, email được coi là bằng chứng quan trọng và Phân tích tiêu đề email đã trở nên quan trọng để thu thập bằng chứng trong quá trình pháp y.

Điều tra viên có các mục tiêu sau khi thực hiện pháp y qua email:

  • Để xác định tội phạm chính
  • Thu thập bằng chứng cần thiết
  • Trình bày những phát hiện
  • Để xây dựng trường hợp

Những thách thức trong pháp y qua email

Pháp y email đóng một vai trò rất quan trọng trong điều tra vì hầu hết các giao tiếp trong thời đại hiện nay đều dựa vào email. Tuy nhiên, một nhà điều tra pháp y qua email có thể phải đối mặt với những thách thức sau đây trong quá trình điều tra -

Email giả mạo

Thách thức lớn nhất trong pháp y email là việc sử dụng các email giả mạo được tạo ra bằng cách thao túng và viết kịch bản tiêu đề, v.v. Trong thể loại này, tội phạm cũng sử dụng email tạm thời, một dịch vụ cho phép người dùng đã đăng ký nhận email tại một địa chỉ tạm thời hết hạn. sau một khoảng thời gian nhất định.

Giả mạo

Một thách thức khác trong pháp y email là giả mạo trong đó bọn tội phạm sử dụng để trình bày email là của người khác. Trong trường hợp này, máy sẽ nhận được cả địa chỉ IP giả cũng như địa chỉ IP gốc.

Gửi lại email ẩn danh

Tại đây, máy chủ Email loại bỏ thông tin nhận dạng từ email trước khi chuyển tiếp nó. Điều này dẫn đến một thách thức lớn khác cho việc điều tra email.

Các kỹ thuật được sử dụng trong điều tra pháp y qua email

Pháp y email là nghiên cứu về nguồn và nội dung của email để làm bằng chứng xác định người gửi và người nhận thực tế của một thư cùng với một số thông tin khác như ngày / giờ truyền và ý định của người gửi. Nó liên quan đến việc điều tra siêu dữ liệu, quét cổng cũng như tìm kiếm từ khóa.

Một số kỹ thuật phổ biến có thể được sử dụng để điều tra pháp y qua email là

  • Phân tích tiêu đề
  • Điều tra máy chủ
  • Điều tra thiết bị mạng
  • Dấu vân tay của Người gửi thư
  • Số nhận dạng được nhúng phần mềm

Trong các phần sau, chúng ta sẽ tìm hiểu cách lấy thông tin bằng Python cho mục đích điều tra email.

Trích xuất thông tin từ tệp EML

Các tệp EML về cơ bản là các email ở định dạng tệp được sử dụng rộng rãi để lưu trữ các email. Chúng là các tệp văn bản có cấu trúc tương thích với nhiều ứng dụng email như Microsoft Outlook, Outlook Express và Windows Live Mail.

Tệp EML lưu trữ tiêu đề email, nội dung nội dung, dữ liệu đính kèm dưới dạng văn bản thuần túy. Nó sử dụng base64 để mã hóa dữ liệu nhị phân và mã hóa Quotes-Printable (QP) để lưu trữ thông tin nội dung. Tập lệnh Python có thể được sử dụng để trích xuất thông tin từ tệp EML được đưa ra dưới đây:

Đầu tiên, nhập các thư viện Python sau như được hiển thị bên dưới:

from __future__ import print_function
from argparse import ArgumentParser, FileType
from email import message_from_file

import os
import quopri
import base64

Trong các thư viện trên, quopriđược sử dụng để giải mã các giá trị được mã hóa QP từ các tệp EML. Mọi dữ liệu được mã hóa base64 đều có thể được giải mã với sự trợ giúp củabase64 thư viện.

Tiếp theo, chúng ta hãy cung cấp đối số cho trình xử lý dòng lệnh. Lưu ý rằng ở đây nó sẽ chỉ chấp nhận một đối số là đường dẫn đến tệp EML như hình dưới đây:

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)

Bây giờ, chúng ta cần xác định main() trong đó chúng ta sẽ sử dụng phương thức có tên message_from_file()từ thư viện email để đọc tệp giống đối tượng. Ở đây, chúng tôi sẽ truy cập tiêu đề, nội dung nội dung, tệp đính kèm và thông tin trọng tải khác bằng cách sử dụng biến kết quả có tênemlfile như được hiển thị trong mã dưới đây -

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

Bây giờ, chúng ta cần xác định process_payload() trong đó chúng tôi sẽ trích xuất nội dung nội dung thư bằng cách sử dụng get_payload()phương pháp. Chúng tôi sẽ giải mã dữ liệu được mã hóa QP bằng cách sử dụngquopri.decodestring()chức năng. Chúng tôi cũng sẽ kiểm tra loại MIME nội dung để nó có thể xử lý việc lưu trữ email đúng cách. Hãy quan sát đoạn mã dưới đây -

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)

Sau khi thực hiện tập lệnh trên, chúng ta sẽ nhận được thông tin tiêu đề cùng với các trọng tải khác nhau trên bảng điều khiển.

Phân tích tệp MSG bằng Python

Thư điện tử có nhiều định dạng khác nhau. MSG là một trong những loại định dạng được Microsoft Outlook và Exchange sử dụng. Các tệp có phần mở rộng MSG có thể chứa văn bản ASCII thuần túy cho tiêu đề và nội dung thư chính cũng như các siêu liên kết và tệp đính kèm.

Trong phần này, chúng ta sẽ tìm hiểu cách trích xuất thông tin từ tệp MSG bằng Outlook API. Lưu ý rằng tập lệnh Python sau sẽ chỉ hoạt động trên Windows. Đối với điều này, chúng tôi cần cài đặt thư viện Python của bên thứ ba có tênpywin32 như sau -

pip install pywin32

Bây giờ, hãy nhập các thư viện sau bằng các lệnh được hiển thị:

from __future__ import print_function
from argparse import ArgumentParser

import os
import win32com.client
import pywintypes

Bây giờ, chúng ta hãy 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ố, một là đường dẫn đến tệp MSG và đối số khác sẽ là thư mục đầu ra mong muốn như sau:

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)

Bây giờ, chúng ta cần xác định main() chức năng mà chúng ta sẽ gọi win32com thư viện để thiết lập Outlook API hơn nữa cho phép truy cập vào MAPI không gian tên.

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)

Bây giờ, hãy xác định các hàm khác nhau mà chúng ta đang sử dụng trong tập lệnh này. Đoạn mã dưới đây cho thấy việc xác địnhdisplay_msg_attribs() cho phép chúng tôi hiển thị các thuộc tính khác nhau của thư như chủ đề, tới, BCC, CC, Kích thước, Tên người gửi, đã gửi, v.v.

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

Bây giờ, xác định display_msg_recipeints() chức năng lặp qua các tin nhắn và hiển thị chi tiết người nhận.

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

Tiếp theo, chúng tôi xác định extract_msg_body() chức năng trích xuất nội dung nội dung, HTML cũng như Văn bản thuần túy, từ thư.

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

Tiếp theo, chúng ta sẽ xác định extract_attachments() hàm xuất dữ liệu đính kèm vào thư mục đầu ra mong muốn.

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

Khi tất cả các chức năng được xác định, chúng tôi sẽ in tất cả các thuộc tính vào bảng điều khiển với dòng mã sau:

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

Sau khi chạy tập lệnh trên, chúng ta sẽ nhận được các thuộc tính của tin nhắn và các tệp đính kèm của nó trong cửa sổ bảng điều khiển cùng với một số tệp trong thư mục đầu ra.

Cấu trúc tệp MBOX từ Google Takeout bằng Python

Tệp MBOX là tệp văn bản có định dạng đặc biệt chia nhỏ các thư được lưu trữ bên trong. Chúng thường được tìm thấy cùng với hệ thống UNIX, Thunderbolt và Google Takeouts.

Trong phần này, bạn sẽ thấy một tập lệnh Python, nơi chúng ta sẽ cấu trúc các tệp MBOX lấy từ Google Takeouts. Nhưng trước đó chúng ta phải biết rằng làm thế nào chúng ta có thể tạo các tệp MBOX này bằng cách sử dụng tài khoản Google hoặc tài khoản Gmail của chúng tôi.

Nhận Hộp thư Tài khoản Google ở ​​Định dạng MBX

Có được hộp thư tài khoản Google đồng nghĩa với việc sao lưu tài khoản Gmail của chúng ta. Sao lưu có thể được thực hiện vì nhiều lý do cá nhân hoặc nghề nghiệp. Lưu ý rằng Google cung cấp tính năng sao lưu dữ liệu Gmail. Để chuyển hộp thư tài khoản Google của chúng tôi sang định dạng MBOX, bạn cần thực hiện theo các bước được cung cấp bên dưới -

  • Mở My account bảng điều khiển.

  • Chuyển đến phần Thông tin cá nhân và quyền riêng tư và chọn Kiểm soát liên kết nội dung của bạn.

  • Bạn có thể tạo một kho lưu trữ mới hoặc có thể quản lý một kho lưu trữ hiện có. Nếu chúng tôi nhấp vào,CREATE ARCHIVE liên kết, sau đó chúng tôi sẽ nhận được một số hộp kiểm cho mỗi sản phẩm Google mà chúng tôi muốn đưa vào.

  • Sau khi chọn sản phẩm, chúng tôi sẽ có quyền tự do lựa chọn loại tệp và kích thước tối đa cho kho lưu trữ của chúng tôi cùng với phương thức phân phối để chọn từ danh sách.

  • Cuối cùng, chúng tôi sẽ nhận được bản sao lưu này ở định dạng MBOX.

Mã Python

Bây giờ, tệp MBOX được thảo luận ở trên có thể được cấu trúc bằng Python như hình dưới đây:

Đầu tiên, cần nhập các thư viện Python như sau:

from __future__ import print_function
from argparse import ArgumentParser

import mailbox
import os
import time
import csv
from tqdm import tqdm

import base64

Tất cả các thư viện đã được sử dụng và giải thích trong các tập lệnh trước đó, ngoại trừ mailbox thư viện được sử dụng để phân tích cú pháp tệp MBOX.

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ố - một là đường dẫn đến tệp MBOX và đối số kia sẽ là thư mục đầu ra mong muốn.

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)

Bây giờ, sẽ xác định main() chức năng và cuộc gọi mbox lớp thư viện hộp thư với sự trợ giúp của chúng tôi có thể phân tích cú pháp tệp MBOX bằng cách cung cấp đường dẫn của nó -

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

Bây giờ, hãy xác định một phương pháp đọc cho mailbox thư viện như sau -

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)

Bây giờ, hãy tạo một số biến để xử lý thêm như sau:

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

Tiếp theo, sử dụng tqdm để tạo thanh tiến trình và theo dõi quá trình lặp lại như sau:

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

Bây giờ, hãy kiểm tra thông báo thời tiết có tải trọng hay không. Nếu nó đang có thì chúng tôi sẽ xác địnhwrite_payload() phương pháp như sau -

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)

Bây giờ, dữ liệu cần được thêm vào. Sau đó, chúng tôi sẽ gọicreate_report() phương pháp như sau -

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

Quan sát rằng các câu lệnh if-else ở trên rất dễ hiểu. Bây giờ, chúng ta cần xác định một phương thức sẽ trích xuất tên tệp từmsg đối tượng như sau -

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)

Bây giờ, với sự trợ giúp của các dòng mã sau, bạn thực sự có thể xuất tệp -

if isinstance(content_data, str):
   open(file_name, 'w').write(content_data)
else:
   open(file_name, 'wb').write(content_data)
return file_name

Bây giờ, chúng ta hãy xác định một hàm để trích xuất tên tệp từ message để trình bày chính xác tên của các tệp này như sau:

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)

Bây giờ, chúng ta có thể viết tệp CSV bằng cách xác định create_report() chức năng như sau -

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)

Sau khi bạn chạy tập lệnh được cung cấp ở trên, chúng tôi sẽ nhận được báo cáo CSV và thư mục chứa đầy tệp đính kèm.