Учебники

Python Digital Network Forensics-II

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

Сохранение веб-страницы с красивым супом

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

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

  • Изменения в веб-ресурсах — веб-ресурсы постоянно меняются каждый день, что является проблемой для сохранения веб-страниц.

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

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

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

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

Изменения в веб-ресурсах — веб-ресурсы постоянно меняются каждый день, что является проблемой для сохранения веб-страниц.

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

Целостность — веб-страницы должны быть защищены от несанкционированного изменения, удаления или удаления, чтобы защитить его целостность.

Работа с мультимедийными данными. При сохранении веб-страниц нам также необходимо иметь дело с мультимедийными данными, что может вызвать проблемы при этом.

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

В этой главе мы собираемся использовать библиотеку 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-кроме следующим образом:

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 () для записи первой веб-страницы в выходной каталог

Функция 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-exc следующим образом:

try:
   index = urlopen(url, context = context).read().decode("utf-8")
except urllib.error.HTTPError as e:
   print("[-] Error accessing webpage - exiting..")
   sys.exit(1)

Теперь определите последний список хешей с загруженных страниц. Вы можете сделать это, найдя последний экземпляр тега HTML href в хэш-списке 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 в текстовом формате.