Криминалистическая экспертиза цифровых сетей Python-II

В предыдущей главе были рассмотрены некоторые концепции сетевой криминалистики с использованием Python. В этой главе давайте разберемся в сетевой криминалистике с использованием Python на более глубоком уровне.

Сохранение веб-страницы с помощью Beautiful Soup

Всемирная паутина (WWW) - это уникальный источник информации. Однако его наследие находится под высоким риском из-за угрожающей скорости потери контента. Ряд учреждений, занимающихся культурным наследием, академических учреждений, некоммерческих организаций и частных предприятий изучили связанные с этим вопросы и внесли свой вклад в разработку технических решений для веб-архивирования.

Сохранение веб-страниц или веб-архивирование - это процесс сбора данных из World Wide Web, гарантирующий, что данные сохраняются в архиве и делают их доступными для будущих исследователей, историков и общественности. Прежде чем перейти к сохранению веб-страницы, давайте обсудим некоторые важные вопросы, связанные с сохранением веб-страницы, как указано ниже -

  • Change in Web Resources - Веб-ресурсы постоянно меняются, что является проблемой для сохранения веб-страниц.

  • Large Quantity of Resources - Еще одна проблема, связанная с сохранением веб-страниц, - это большое количество ресурсов, которые необходимо сохранить.

  • Integrity - Веб-страницы должны быть защищены от несанкционированного изменения, удаления или удаления для защиты своей целостности.

  • Dealing with multimedia data - При сохранении веб-страниц нам также необходимо иметь дело с мультимедийными данными, и при этом могут возникнуть проблемы.

  • Providing access - Помимо сохранения, необходимо решить вопрос обеспечения доступа к веб-ресурсам и решения вопросов собственности.

В этой главе мы собираемся использовать библиотеку Python с именем 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 (). Давайте использовать блок try-except следующим образом -

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 Больше подробностей.

Создание хеш-списка с разделителями новой строки из VirusShare с использованием Python

Список хэшей из VirusShare может использоваться различными инструментами судебной экспертизы, такими как X-way и 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 следующим образом:

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 в текстовом формате.