Учебники

Python Digital Forensics — Краткое руководство

Python Digital Forensics — Введение

Эта глава даст вам представление о том, что такое цифровая криминалистика, и ее исторический обзор. Вы также поймете, где вы можете применять цифровую экспертизу в реальной жизни и ее ограничения.

Что такое цифровая криминалистика?

Цифровая криминалистика может быть определена как отрасль криминалистики, которая анализирует, исследует, идентифицирует и восстанавливает цифровые доказательства, хранящиеся на электронных устройствах. Это обычно используется для уголовного права и частных расследований.

Например, вы можете положиться на извлечение улик из цифровой криминалистической экспертизы в случае кражи данных на электронном устройстве.

Краткий исторический обзор цифровой криминалистики

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

1970-е-1980-е годы: первое компьютерное преступление

До этого десятилетия компьютерное преступление не было признано. Однако, если это должно было произойти, тогда действующие законы имели дело с ними. Позже, в 1978 году, первое преступление к компьютерам было признано в Законе о компьютерных преступлениях во Флориде, который включал законодательство, запрещающее несанкционированное изменение или удаление данных в компьютерной системе. Но с течением времени, благодаря развитию технологий, спектр компьютерных преступлений также увеличился. Для того, чтобы иметь дело с преступлениями, связанных с авторским правом, неприкосновенностью частной жизни и детской порнографией, были приняты различные другие законы.

1980-е-1990-е годы: десятилетие развития

Это десятилетие было десятилетием развития цифровой криминалистики, и все из-за первого в истории расследования (1986), в котором Клифф Столл отслеживал хакера по имени Маркус Хесс. В течение этого периода были разработаны два вида дисциплин цифровой криминалистики — сначала с помощью специальных инструментов и методов, разработанных практикующими специалистами, которые восприняли это как хобби, а во втором — научное сообщество. В 1992 году термин «компьютерная криминалистика» использовался в научной литературе.

2000-е-2010-е годы: десятилетие стандартизации

После того, как цифровая криминалистика достигла определенного уровня, возникла необходимость в разработке определенных стандартов, которым можно следовать при проведении расследований. Соответственно, различные научные учреждения и органы опубликовали руководящие принципы для цифровой криминалистики. В 2002 году Научная рабочая группа по цифровым доказательствам (SWGDE) опубликовала документ под названием «Лучшие практики компьютерной криминалистики». Другим пером в кепке был международный договор под руководством Европы, а именно «Конвенция о киберпреступности», подписанная 43 странами и ратифицированная 16 странами. Даже после таких стандартов все еще существует необходимость решить некоторые проблемы, которые были выявлены исследователями.

Процесс цифровой криминалистики

С тех пор, как в 1978 году было совершено первое преступление, связанное с использованием компьютеров, масштабы цифровой преступной деятельности значительно возросли. Из-за этого приращения существует необходимость в структурированном способе борьбы с ними. В 1984 году был введен формализованный процесс, и после этого было разработано большое количество новых и усовершенствованных процессов компьютерного криминалистического расследования.

Процесс компьютерного криминалистического расследования включает три основных этапа, описанных ниже:

Этап 1: приобретение или визуализация экспонатов

Первый этап цифровой криминалистики включает сохранение состояния цифровой системы, чтобы его можно было проанализировать позже. Это очень похоже на фотографирование, образцы крови и т. Д. С места преступления. Например, это включает захват изображения выделенных и нераспределенных областей жесткого диска или ОЗУ.

Этап 2: Анализ

Входом этой фазы являются данные, полученные на этапе сбора данных. Здесь эти данные были изучены для выявления доказательств. Эта фаза дает три вида доказательств следующим образом:

  • Обвинительные доказательства — эти доказательства подтверждают данную историю.

  • Оправдательные доказательства — эти доказательства противоречат данной истории.

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

Обвинительные доказательства — эти доказательства подтверждают данную историю.

Оправдательные доказательства — эти доказательства противоречат данной истории.

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

Этап 3: презентация или отчетность

Как следует из названия, этот этап представляет заключение и соответствующие доказательства из расследования.

Применение цифровой криминалистики

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

Уголовное право

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

Частное расследование

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

Отрасли цифровой криминалистики

Цифровая преступность не ограничивается только компьютерами, однако хакеры и преступники используют небольшие цифровые устройства, такие как планшеты, смартфоны и т. Д., Также в очень больших масштабах. Некоторые устройства имеют энергозависимую память, в то время как другие имеют энергонезависимую память. Следовательно, в зависимости от типа устройств, цифровая криминалистика имеет следующие ветви —

Компьютерная криминалистика

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

Мобильная криминалистика

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

Сетевая криминалистика

Это касается мониторинга и анализа трафика компьютерной сети, как локальной, так и глобальной сети (глобальная сеть) в целях сбора информации, сбора доказательств или обнаружения вторжений.

База данных Криминалистика

Эта ветвь цифровой криминалистики занимается криминалистическим изучением баз данных и их метаданных.

Навыки, необходимые для проведения цифровых криминалистических исследований

Цифровые криминалисты помогают отслеживать хакеров, восстанавливать украденные данные, отслеживать компьютерные атаки и возвращаться к их источнику, а также помогают в других типах расследований, связанных с компьютерами. Некоторые из ключевых навыков, необходимых для того, чтобы стать цифровым судебно-медицинским экспертом, описаны ниже.

Выдающиеся способности мышления

Цифровой криминалист должен быть выдающимся мыслителем и должен уметь применять различные инструменты и методологии для конкретного задания для получения результатов. Он / она должен уметь находить разные закономерности и устанавливать между ними взаимосвязи.

Технические навыки

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

Страстный о кибер-безопасности

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

Навыки общения

Хорошие коммуникативные навыки необходимы для координации с различными командами и извлечения недостающих данных или информации.

Умелое создание отчетов

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

Ограничения

Цифровая криминалистическая экспертиза предлагает определенные ограничения, как обсуждено здесь —

Необходимо представить убедительные доказательства

Один из основных недостатков цифрового криминалистического расследования заключается в том, что эксперт должен соблюдать стандарты, которые необходимы для доказательств в суде, поскольку данные могут быть легко подделаны. С другой стороны, компьютерный судебный следователь должен иметь полное представление о правовых требованиях, обработке доказательств и процедурах документирования, чтобы представить убедительные доказательства в суде.

Инструменты исследования

Эффективность цифрового расследования целиком и полностью зависит от экспертизы цифрового судебного эксперта и выбора правильного инструмента расследования. Если используемый инструмент не соответствует указанным стандартам, то в суде, доказательства могут быть отклонены судьей.

Недостаток технических знаний среди аудитории

Другое ограничение заключается в том, что некоторые люди не совсем знакомы с компьютерной криминалистикой; поэтому многие люди не понимают эту область. Следователи должны быть доведены до сведения своих выводов в судах таким образом, чтобы помочь каждому понять результаты.

Стоимость

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

Python Digital Forensics — Начало работы

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

Почему Python для цифровой криминалистики?

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

Некоторые из уникальных особенностей языка программирования Python, которые делают его подходящим для проектов цифровой криминалистики, приведены ниже —

  • Простота синтаксиса. Синтаксис Python прост по сравнению с другими языками, что упрощает его изучение и использование для цифровой криминалистики.

  • Комплексные встроенные модулиКомплексные встроенные модули Python являются отличным помощником для проведения полного цифрового судебного расследования.

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

Простота синтаксиса. Синтаксис Python прост по сравнению с другими языками, что упрощает его изучение и использование для цифровой криминалистики.

Комплексные встроенные модулиКомплексные встроенные модули Python являются отличным помощником для проведения полного цифрового судебного расследования.

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

Особенности Python

Python, являющийся высокоуровневым, интерпретируемым, интерактивным и объектно-ориентированным языком сценариев, предоставляет следующие возможности:

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

  • Выразительный и легкий для чтения — язык Python является выразительным по своей природе; следовательно, его код более понятен и читаем.

  • Кроссплатформенная совместимость — Python является кроссплатформенным совместимым языком, что означает, что он может эффективно работать на различных платформах, таких как UNIX, Windows и Macintosh.

  • Программирование в интерактивном режиме — мы можем проводить интерактивное тестирование и отладку кода, потому что Python поддерживает интерактивный режим для программирования.

  • Предоставляет различные модули и функции — Python имеет большую стандартную библиотеку, которая позволяет нам использовать богатый набор модулей и функций для нашего скрипта.

  • Поддерживает динамическую проверку типов — Python поддерживает динамическую проверку типов и предоставляет динамические типы данных очень высокого уровня.

  • Программирование GUI — Python поддерживает программирование GUI для разработки графических пользовательских интерфейсов.

  • Интеграция с другими языками программирования — Python может быть легко интегрирован с другими языками программирования, такими как C, C ++, JAVA и т. Д.

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

Выразительный и легкий для чтения — язык Python является выразительным по своей природе; следовательно, его код более понятен и читаем.

Кроссплатформенная совместимость — Python является кроссплатформенным совместимым языком, что означает, что он может эффективно работать на различных платформах, таких как UNIX, Windows и Macintosh.

Программирование в интерактивном режиме — мы можем проводить интерактивное тестирование и отладку кода, потому что Python поддерживает интерактивный режим для программирования.

Предоставляет различные модули и функции — Python имеет большую стандартную библиотеку, которая позволяет нам использовать богатый набор модулей и функций для нашего скрипта.

Поддерживает динамическую проверку типов — Python поддерживает динамическую проверку типов и предоставляет динамические типы данных очень высокого уровня.

Программирование GUI — Python поддерживает программирование GUI для разработки графических пользовательских интерфейсов.

Интеграция с другими языками программирования — Python может быть легко интегрирован с другими языками программирования, такими как C, C ++, JAVA и т. Д.

Установка Python

Дистрибутив Python доступен для различных платформ, таких как Windows, UNIX, Linux и Mac. Нам нужно только загрузить двоичный код в соответствии с нашей платформой. В случае, если двоичный код для какой-либо платформы недоступен, мы должны иметь компилятор C, чтобы исходный код мог быть скомпилирован вручную.

Этот раздел познакомит вас с установкой Python на различные платформы.

Установка Python в Unix и Linux

Вы можете выполнить следующие шаги, чтобы установить Python на компьютере с Unix / Linux.

Шаг 1 — Откройте веб-браузер. Введите и введите www.python.org/downloads/

Шаг 2 — Загрузите сжатый исходный код, доступный для Unix / Linux.

Шаг 3 — Извлеките загруженные заархивированные файлы.

Шаг 4 — Если вы хотите настроить некоторые параметры, вы можете отредактировать файл Modules / Setup .

Шаг 5 — Используйте следующие команды для завершения установки —

run ./configure script
make
make install

После того, как вы успешно выполнили шаги, указанные выше, Python будет установлен в его стандартном расположении / usr / local / bin, а его библиотеки — в / usr / local / lib / pythonXX, где XX — версия Python.

Установка Python в Windows

Мы можем выполнить следующие простые шаги для установки Python на компьютер с Windows.

Шаг 1 — Откройте веб-браузер. Введите и введите www.python.org/downloads/

Шаг 2. Загрузите файл установщика Windows python-XYZ.msi , где XYZ — это версия, которую нам нужно установить.

Шаг 3 — Теперь запустите этот MSI-файл после сохранения установочного файла на локальном компьютере.

Шаг 4 — Запустите загруженный файл, который вызовет мастер установки Python.

Установка Python на Macintosh

Для установки Python 3 в Mac OS X мы должны использовать установщик пакетов с именем Homebrew .

Вы можете использовать следующую команду для установки Homebrew, если у вас ее нет в вашей системе —

$ ruby -e "$(curl -fsSL
https://raw.githubusercontent.com/Homebrew/install/master/install)"

Если вам нужно обновить менеджер пакетов, то это можно сделать с помощью следующей команды —

$ brew update

Теперь используйте следующую команду для установки Python3 в вашей системе:

$ brew install python3

Установка пути

Нам нужно установить путь для установки Python, и это отличается от платформ, таких как UNIX, WINDOWS или MAC.

Настройка пути в Unix / Linux

Вы можете использовать следующие опции для установки пути в Unix / Linux —

  • If using csh shell — Type setenv PATH «$PATH:/usr/local/bin/python» and then press Enter.

  • If using bash shell (Linux) − Type export ATH=»$PATH:/usr/local/bin/python» and then press Enter.

  • If using sh or ksh shell — Type PATH=»$PATH:/usr/local/bin/python» and then press Enter.

If using csh shell — Type setenv PATH «$PATH:/usr/local/bin/python» and then press Enter.

If using bash shell (Linux) − Type export ATH=»$PATH:/usr/local/bin/python» and then press Enter.

If using sh or ksh shell — Type PATH=»$PATH:/usr/local/bin/python» and then press Enter.

Настройка пути в Windows

Введите путь% path%; C: \ Python в командной строке и нажмите клавишу ВВОД.

Запуск Python

Вы можете выбрать любой из следующих трех методов для запуска интерпретатора Python:

Метод 1: Использование интерактивного переводчика

Система, которая предоставляет интерпретатор командной строки или оболочку, может легко использоваться для запуска Python. Например, Unix, DOS и т. Д. Вы можете выполнить шаги, приведенные ниже, чтобы начать кодирование в интерактивном интерпретаторе —

Шаг 1 — Введите python в командной строке.

Шаг 2 — Начните кодирование прямо в интерактивном интерпретаторе, используя команды, показанные ниже —

$python # Unix/Linux
or
python% # Unix/Linux
or
C:> python # Windows/DOS

Способ 2: использование скрипта из командной строки

Мы также можем выполнить скрипт Python из командной строки, вызвав интерпретатор в нашем приложении. Вы можете использовать команды, показанные ниже —

$python script.py # Unix/Linux
or
python% script.py # Unix/Linux
or
C: >python script.py # Windows/DOS

Метод 3: Интегрированная среда разработки

Если в системе есть приложение с графическим интерфейсом, которое поддерживает Python, то Python можно запустить из этой среды с графическим интерфейсом. Некоторые из IDE для различных платформ приведены ниже —

  • Unix IDE — UNIX имеет IDLE IDE для Python.

  • Windows IDE — Windows имеет PythonWin, первый интерфейс Windows для Python вместе с графическим интерфейсом.

  • IDE для Macintosh — Macintosh имеет IDLE IDE, доступную на основном веб-сайте, которую можно загрузить в виде файлов MacBinary или BinHex’d.

Unix IDE — UNIX имеет IDLE IDE для Python.

Windows IDE — Windows имеет PythonWin, первый интерфейс Windows для Python вместе с графическим интерфейсом.

IDE для Macintosh — Macintosh имеет IDLE IDE, доступную на основном веб-сайте, которую можно загрузить в виде файлов MacBinary или BinHex’d.

Отчет об артефактах

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

Необходимость создания отчета

Процесс цифровой криминалистики включает отчетность в качестве третьего этапа. Это одна из самых важных частей цифрового судебного процесса. Создание отчета необходимо по следующим причинам:

  • Это документ, в котором цифровой судебно-медицинский эксперт описывает процесс расследования и его выводы.

  • Хороший цифровой криминалистический отчет может быть использован другим экспертом для достижения того же результата с помощью тех же репозиториев.

  • Это технический и научный документ, который содержит факты, найденные в пределах 1 и 0 цифровых доказательств.

Это документ, в котором цифровой судебно-медицинский эксперт описывает процесс расследования и его выводы.

Хороший цифровой криминалистический отчет может быть использован другим экспертом для достижения того же результата с помощью тех же репозиториев.

Это технический и научный документ, который содержит факты, найденные в пределах 1 и 0 цифровых доказательств.

Общие рекомендации по созданию отчетов

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

  • Резюме . Отчет должен содержать краткое изложение информации, чтобы читатель мог выяснить цель отчета.

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

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

  • Рекомендации для адвоката. В отчете должны содержаться рекомендации для адвоката о продолжении или прекращении расследования на основе результатов, содержащихся в отчете.

Резюме . Отчет должен содержать краткое изложение информации, чтобы читатель мог выяснить цель отчета.

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

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

Рекомендации для адвоката. В отчете должны содержаться рекомендации для адвоката о продолжении или прекращении расследования на основе результатов, содержащихся в отчете.

Создание разных типов отчетов

В приведенном выше разделе мы узнали о важности отчетов в цифровой криминалистике вместе с рекомендациями по их созданию. Некоторые форматы в Python для создания отчетов различного типа обсуждаются ниже —

Отчеты CSV

Одним из наиболее распространенных форматов вывода отчетов является отчет в виде таблицы в формате CSV. Вы можете создать CSV для создания отчета об обработанных данных, используя код Python, как показано ниже —

Во-первых, импортируйте полезные библиотеки для написания электронной таблицы —

from __future__ import print_function
import csv
import os
import sys

Теперь вызовите следующий метод —

Write_csv(TEST_DATA_LIST, ["Name", "Age", "City", "Job description"], os.getcwd())

Мы используем следующую глобальную переменную для представления типов данных:

TEST_DATA_LIST = [["Ram", 32, Bhopal, Manager], 
   ["Raman", 42, Indore, Engg.],
   ["Mohan", 25, Chandigarh, HR], 
   ["Parkash", 45, Delhi, IT]]

Далее, давайте определим метод для продолжения дальнейших операций. Мы открываем файл в режиме «w» и устанавливаем аргумент ключевого слова newline в пустую строку.

def Write_csv(data, header, output_directory, name = None):
   if name is None:
      name = "report1.csv"
   print("[+] Writing {} to {}".format(name, output_directory))
   
   with open(os.path.join(output_directory, name), "w", newline = "") as \ csvfile:
      writer = csv.writer(csvfile)
      writer.writerow(header)
      writer.writerow(data)

Если вы запустите приведенный выше скрипт, вы получите следующие данные, хранящиеся в файле report1.csv.

название Возраст город обозначение
Баран 32 Бхопал Managerh
Раман 42 Индор Engg
Mohan 25 Чандигарх HR
Parkash 45 Дели ЭТО

Отчеты Excel

Другим распространенным форматом вывода отчетов является отчет в виде электронной таблицы Excel (.xlsx). Мы можем создать таблицу, а также построить график с помощью Excel. Мы можем создать отчет обработанных данных в формате Excel, используя код Python, как показано ниже.

Во-первых, импортируйте модуль XlsxWriter для создания электронной таблицы —

import xlsxwriter

Теперь создайте объект книги. Для этого нам нужно использовать конструктор Workbook ().

workbook = xlsxwriter.Workbook('report2.xlsx')

Теперь создайте новый лист с помощью модуля add_worksheet ().

worksheet = workbook.add_worksheet()

Затем запишите следующие данные в лист —

report2 = (['Ram', 32, Bhopal’],['Mohan',25, Chandigarh’] ,['Parkash',45, Delhi’])

row = 0
col = 0

Вы можете перебрать эти данные и записать их следующим образом:

for item, cost in (a):
   worksheet.write(row, col, item)
   worksheet.write(row, col+1, cost)
   row + = 1

Теперь давайте закроем этот файл Excel с помощью метода close ().

workbook.close()

Приведенный выше скрипт создаст файл Excel с именем report2.xlsx, содержащий следующие данные:

Баран 32 Бхопал
Mohan 25 Чандигарх
Parkash 45 Дели

Расследование Приобретение СМИ

Для следователя важно иметь подробные следственные заметки, чтобы точно вспомнить результаты или собрать все части расследования. Скриншот очень полезен для отслеживания шагов, предпринятых для конкретного расследования. С помощью следующего кода Python мы можем сделать снимок экрана и сохранить его на жестком диске для дальнейшего использования.

Сначала установите модуль Python с именем pyscreenshot с помощью следующей команды —

Pip install pyscreenshot

Теперь импортируйте необходимые модули, как показано на рисунке —

import pyscreenshot as ImageGrab

Используйте следующую строку кода, чтобы получить скриншот —

image = ImageGrab.grab()

Используйте следующую строку кода, чтобы сохранить скриншот в указанное место —

image.save('d:/image123.png')

Теперь, если вы хотите открыть скриншот в виде графика, вы можете использовать следующий код Python —

import numpy as np
import matplotlib.pyplot as plt
import pyscreenshot as ImageGrab
imageg = ImageGrab.grab()
plt.imshow(image, cmap='gray', interpolation='bilinear')
plt.show()

Python Digital Mobile Device Forensics

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

Вступление

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

Хотя использование смартфонов в цифровой криминалистике растет день ото дня, тем не менее, оно считается нестандартным из-за его неоднородности. С другой стороны, компьютерное оборудование, такое как жесткий диск, считается стандартным и развивается как стабильная дисциплина. В индустрии цифровой криминалистики много споров о методах, используемых для нестандартных устройств, имеющих временные доказательства, такие как смартфоны.

Извлекаемые из мобильных устройств артефакты

Современные мобильные устройства обладают большим количеством цифровой информации по сравнению со старыми телефонами, имеющими только журнал вызовов или SMS-сообщения. Таким образом, мобильные устройства могут предоставить следователям много информации о своем пользователе. Некоторые артефакты, которые могут быть извлечены с мобильных устройств, перечислены ниже:

  • Сообщения — это полезные артефакты, которые могут раскрыть душевное состояние владельца и даже дать некоторую ранее неизвестную информацию следователю.

  • История местоположений — данные истории местоположений являются полезным артефактом, который может использоваться следователями для проверки конкретного местоположения человека.

  • Установленные приложения. Получив доступ к установленным приложениям, исследователь получает представление о привычках и взглядах мобильного пользователя.

Сообщения — это полезные артефакты, которые могут раскрыть душевное состояние владельца и даже дать некоторую ранее неизвестную информацию следователю.

История местоположений — данные истории местоположений являются полезным артефактом, который может использоваться следователями для проверки конкретного местоположения человека.

Установленные приложения. Получив доступ к установленным приложениям, исследователь получает представление о привычках и взглядах мобильного пользователя.

Доказательства Источники и обработка в Python

Смартфоны имеют базы данных SQLite и файлы PLIST в качестве основных источников доказательств. В этом разделе мы собираемся обработать источники доказательств в Python.

Анализ файлов PLIST

PLIST (список свойств) — это гибкий и удобный формат для хранения данных приложения, особенно на устройствах iPhone. Он использует расширение .plist . Такие файлы используются для хранения информации о пакетах и ​​приложениях. Он может быть в двух форматах: XML и двоичный . Следующий код Python откроет и прочитает файл PLIST. Обратите внимание, что прежде чем приступить к этому, мы должны создать наш собственный файл Info.plist .

Сначала установите стороннюю библиотеку с именем biplist с помощью следующей команды —

Pip install biplist

Теперь импортируйте несколько полезных библиотек для обработки файлов plist —

import biplist
import os
import sys

Теперь используйте следующую команду в методе main для чтения файла plist в переменную:

def main(plist):
   try:
      data = biplist.readPlist(plist)
   except (biplist.InvalidPlistException,biplist.NotBinaryPlistException) as e:
print("[-] Invalid PLIST file - unable to be opened by biplist")
sys.exit(1)

Теперь мы можем либо прочитать данные на консоли, либо напрямую распечатать их из этой переменной.

Базы данных SQLite

SQLite служит основным хранилищем данных на мобильных устройствах. SQLite — внутрипроцессная библиотека, которая реализует самодостаточный, транзакционный механизм базы данных SQL с нулевой конфигурацией сервера. Это база данных с нулевой конфигурацией, вам не нужно настраивать ее в своей системе, в отличие от других баз данных.

Если вы новичок или незнакомы с базами данных SQLite, вы можете перейти по ссылке www.tutorialspoint.com/sqlite/index.htm. Кроме того, вы можете перейти по ссылке www.tutorialspoint.com/sqlite/sqlite_python.htm, если хотите углубиться в детали SQLite с помощью Python.

Во время мобильной криминалистики мы можем взаимодействовать с файлом sms.db мобильного устройства и извлекать ценную информацию из таблицы сообщений . Python имеет встроенную библиотеку с именем sqlite3 для подключения к базе данных SQLite. Вы можете импортировать то же самое с помощью следующей команды —

import sqlite3

Теперь с помощью следующей команды мы можем подключиться к базе данных, например, sms.db для мобильных устройств:

Conn = sqlite3.connect(‘sms.db’)
C = conn.cursor()

Здесь C — объект курсора, с помощью которого мы можем взаимодействовать с базой данных.

Теперь предположим, что если мы хотим выполнить определенную команду, скажем, чтобы получить подробности из таблицы abc , это можно сделать с помощью следующей команды:

c.execute(“Select * from abc”)
c.close()

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

Мы можем использовать следующую команду для получения данных имен столбцов таблицы сообщений в sms.db

c.execute(“pragma table_info(message)”)
table_data = c.fetchall()
columns = [x[1] for x in table_data

Обратите внимание, что здесь мы используем команду SQLite PRAGMA, которая является специальной командой для управления различными переменными среды и флагами состояния в среде SQLite. В приведенной выше команде метод fetchall () возвращает набор результатов. Имя каждого столбца хранится в первом индексе каждого кортежа.

Теперь с помощью следующей команды мы можем запросить у таблицы все ее данные и сохранить ее в переменной с именем data_msg

c.execute(“Select * from message”)
data_msg = c.fetchall()

Приведенная выше команда сохранит данные в переменной, и в дальнейшем мы также можем записать вышеуказанные данные в CSV-файл, используя метод csv.writer () .

резервные копии iTunes

Мобильная экспертиза iPhone может выполняться на резервных копиях iTunes. Судебно-медицинские эксперты полагаются на анализ логических резервных копий iPhone, полученных через iTunes. Протокол AFC (Apple File Connection) используется iTunes для резервного копирования. Кроме того, процесс резервного копирования не изменяет ничего на iPhone, кроме записей ключей условного депонирования.

Теперь возникает вопрос, почему для эксперта по цифровой экспертизе важно понимать методы резервного копирования iTunes? Это важно в случае, если мы получим доступ к компьютеру подозреваемого вместо iPhone напрямую, потому что, когда компьютер используется для синхронизации с iPhone, большая часть информации на iPhone, скорее всего, будет сохранена на компьютере.

Процесс резервного копирования и его расположение

Всякий раз, когда продукт Apple резервируется на компьютер, он синхронизируется с iTunes, и в нем будет определенная папка с уникальным идентификатором устройства. В последнем формате резервной копии файлы хранятся в подпапках, содержащих первые два шестнадцатеричных символа имени файла. Из этих файлов резервных копий есть некоторые файлы, такие как info.plist, которые полезны вместе с базой данных с именем Manifest.db. В следующей таблице показаны места резервного копирования, которые зависят от операционных систем резервных копий iTunes.

Операционные системы Местоположение резервной копии
Win7 C: \ Users \ [имя пользователя] \ AppData \ Roaming \ AppleComputer \ MobileSync \ Backup \
MAC OS X ~ / Библиотека / Поддержка приложений / MobileSync / Резервное копирование /

Для обработки резервной копии iTunes с помощью Python нам необходимо сначала определить все резервные копии в расположении резервной копии в соответствии с нашей операционной системой. Затем мы будем перебирать каждую резервную копию и читать базу данных Manifest.db.

Теперь с помощью следующего кода Python мы можем сделать то же самое —

Сначала импортируйте необходимые библиотеки следующим образом:

from __future__ import print_function
import argparse
import logging
import os

from shutil import copyfile
import sqlite3
import sys
logger = logging.getLogger(__name__)

Теперь предоставьте два позиционных аргумента, а именно INPUT_DIR и OUTPUT_DIR, который представляет резервную копию iTunes и желаемую выходную папку —

if __name__ == "__main__":
   parser.add_argument("INPUT_DIR",help = "Location of folder containing iOS backups, ""e.g. ~\Library\Application Support\MobileSync\Backup folder")
   parser.add_argument("OUTPUT_DIR", help = "Output Directory")
   parser.add_argument("-l", help = "Log file path",default = __file__[:-2] + "log")
   parser.add_argument("-v", help = "Increase verbosity",action = "store_true") args = parser.parse_args()

Теперь настройте журнал следующим образом:

if args.v:
   logger.setLevel(logging.DEBUG)
else:
   logger.setLevel(logging.INFO)

Теперь настройте формат сообщения для этого журнала следующим образом:

msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-13s""%(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 iBackup Visualizer")
logger.debug("Supplied arguments: {}".format(" ".join(sys.argv[1:])))
logger.debug("System: " + sys.platform)
logger.debug("Python Version: " + sys.version)

Следующая строка кода создаст необходимые папки для нужного выходного каталога с помощью функции os.makedirs ()

if not os.path.exists(args.OUTPUT_DIR):
   os.makedirs(args.OUTPUT_DIR)

Теперь передайте предоставленные входные и выходные каталоги функции main () следующим образом:

if os.path.exists(args.INPUT_DIR) and os.path.isdir(args.INPUT_DIR):
   main(args.INPUT_DIR, args.OUTPUT_DIR)
else:
   logger.error("Supplied input directory does not exist or is not ""a directory")
   sys.exit(1)

Теперь напишите функцию main (), которая будет дополнительно вызывать функцию backup_summary () для определения всех резервных копий, присутствующих во входной папке —

def main(in_dir, out_dir):
   backups = backup_summary(in_dir)
def backup_summary(in_dir):
   logger.info("Identifying all iOS backups in {}".format(in_dir))
   root = os.listdir(in_dir)
   backups = {}
   
   for x in root:
      temp_dir = os.path.join(in_dir, x)
      if os.path.isdir(temp_dir) and len(x) == 40:
         num_files = 0
         size = 0
         
         for root, subdir, files in os.walk(temp_dir):
            num_files += len(files)
            size += sum(os.path.getsize(os.path.join(root, name))
               for name in files)
         backups[x] = [temp_dir, num_files, size]
   return backups

Теперь распечатайте сводку каждой резервной копии на консоли следующим образом:

print("Backup Summary")
print("=" * 20)

if len(backups) > 0:
   for i, b in enumerate(backups):
      print("Backup No.: {} \n""Backup Dev. Name: {} \n""# Files: {} \n""Backup Size (Bytes): {}\n".format(i, b, backups[b][1], backups[b][2]))

Теперь поместите содержимое файла Manifest.db в переменную с именем db_items.

try:
   db_items = process_manifest(backups[b][0])
   except IOError:
      logger.warn("Non-iOS 10 backup encountered or " "invalid backup. Continuing to next backup.")
continue

Теперь давайте определим функцию, которая будет принимать путь к каталогу резервной копии —

def process_manifest(backup):
   manifest = os.path.join(backup, "Manifest.db")
   
   if not os.path.exists(manifest):
      logger.error("Manifest DB not found in {}".format(manifest))
      raise IOError

Теперь, используя SQLite3, мы подключимся к базе данных с помощью курсора с именем c —

c = conn.cursor()
items = {}

for row in c.execute("SELECT * from Files;"):
   items[row[0]] = [row[2], row[1], row[3]]
return items

create_files(in_dir, out_dir, b, db_items)
   print("=" * 20)
else:
   logger.warning("No valid backups found. The input directory should be
      " "the parent-directory immediately above the SHA-1 hash " "iOS device backups")
      sys.exit(2)

Теперь определите метод create_files () следующим образом:

def create_files(in_dir, out_dir, b, db_items):
   msg = "Copying Files for backup {} to {}".format(b, os.path.join(out_dir, b))
   logger.info(msg)

Теперь перебираем каждый ключ в словаре db_items

for x, key in enumerate(db_items):
   if db_items[key][0] is None or db_items[key][0] == "":
      continue
   else:
      dirpath = os.path.join(out_dir, b,
os.path.dirname(db_items[key][0]))
   filepath = os.path.join(out_dir, b, db_items[key][0])
   
   if not os.path.exists(dirpath):
      os.makedirs(dirpath)
      original_dir = b + "/" + key[0:2] + "/" + key
   path = os.path.join(in_dir, original_dir)
   
   if os.path.exists(filepath):
      filepath = filepath + "_{}".format(x)

Теперь используйте метод shutil.copyfile () для копирования файла резервной копии следующим образом:

try:
   copyfile(path, filepath)
   except IOError:
      logger.debug("File not found in backup: {}".format(path))
         files_not_found += 1
   if files_not_found > 0:
      logger.warning("{} files listed in the Manifest.db not" "found in
backup".format(files_not_found))
   copyfile(os.path.join(in_dir, b, "Info.plist"), os.path.join(out_dir, b,
"Info.plist"))
   copyfile(os.path.join(in_dir, b, "Manifest.db"), os.path.join(out_dir, b,
"Manifest.db"))
   copyfile(os.path.join(in_dir, b, "Manifest.plist"), os.path.join(out_dir, b,
"Manifest.plist"))
   copyfile(os.path.join(in_dir, b, "Status.plist"),os.path.join(out_dir, b,
"Status.plist"))

С помощью приведенного выше скрипта Python мы можем получить обновленную структуру файлов резервных копий в нашей выходной папке. Мы можем использовать библиотеку pycrypto python для расшифровки резервных копий.

Wi-Fi

Мобильные устройства можно использовать для подключения к внешнему миру путем подключения через сети Wi-Fi, которые доступны везде. Иногда устройство автоматически подключается к этим открытым сетям.

В случае iPhone список открытых подключений Wi-Fi, к которым подключено устройство, хранится в файле PLIST с именем com.apple.wifi.plist . Этот файл будет содержать SSID Wi-Fi, BSSID и время соединения.

Нам нужно извлечь детали Wi-Fi из стандартного отчета Cellebrite XML с использованием Python. Для этого нам нужно использовать API от Wireless Geographic Logging Engine (WIGLE), популярной платформы, которую можно использовать для поиска местоположения устройства с помощью имен сетей Wi-Fi.

Мы можем использовать библиотеку именованных запросов Python для доступа к API из WIGLE. Это может быть установлено следующим образом —

pip install requests

API от WIGLE

Нам нужно зарегистрироваться на сайте WIGLE https://wigle.net/account, чтобы получить бесплатный API от WIGLE. Сценарий Python для получения информации о пользовательском устройстве и его подключении через API WIGEL обсуждается ниже —

Сначала импортируйте следующие библиотеки для обработки разных вещей —

from __future__ import print_function

import argparse
import csv
import os
import sys
import xml.etree.ElementTree as ET
import requests

Теперь предоставьте два позиционных аргумента, а именно INPUT_FILE и OUTPUT_CSV, которые будут представлять входной файл с MAC-адресом Wi-Fi и желаемый выходной CSV-файл соответственно —

if __name__ == "__main__":
   parser.add_argument("INPUT_FILE", help = "INPUT FILE with MAC Addresses")
   parser.add_argument("OUTPUT_CSV", help = "Output CSV File")
   parser.add_argument("-t", help = "Input type: Cellebrite XML report or TXT
file",choices = ('xml', 'txt'), default = "xml")
   parser.add_argument('--api', help = "Path to API key
   file",default = os.path.expanduser("~/.wigle_api"),
   type = argparse.FileType('r'))
   args = parser.parse_args()

Теперь следующие строки кода проверят, существует ли входной файл и является ли он файлом. Если нет, он выходит из сценария —

if not os.path.exists(args.INPUT_FILE) or \ not os.path.isfile(args.INPUT_FILE):
   print("[-] {} does not exist or is not a
file".format(args.INPUT_FILE))
   sys.exit(1)
directory = os.path.dirname(args.OUTPUT_CSV)
if directory != '' and not os.path.exists(directory):
   os.makedirs(directory)
api_key = args.api.readline().strip().split(":")

Теперь передайте аргумент main следующим образом:

main(args.INPUT_FILE, args.OUTPUT_CSV, args.t, api_key)
def main(in_file, out_csv, type, api_key):
   if type == 'xml':
      wifi = parse_xml(in_file)
   else:
      wifi = parse_txt(in_file)
query_wigle(wifi, out_csv, api_key)

Теперь мы проанализируем файл XML следующим образом:

def parse_xml(xml_file):
   wifi = {}
   xmlns = "{http://pa.cellebrite.com/report/2.0}"
   print("[+] Opening {} report".format(xml_file))
   
   xml_tree = ET.parse(xml_file)
   print("[+] Parsing report for all connected WiFi addresses")
   
   root = xml_tree.getroot()

Теперь итерируем дочерний элемент корня следующим образом:

for child in root.iter():
   if child.tag == xmlns + "model":
      if child.get("type") == "Location":
         for field in child.findall(xmlns + "field"):
            if field.get("name") == "TimeStamp":
               ts_value = field.find(xmlns + "value")
               try:
               ts = ts_value.text
               except AttributeError:
continue

Теперь мы проверим, присутствует ли строка ssid в тексте значения или нет —

if "SSID" in value.text:
   bssid, ssid = value.text.split("\t")
   bssid = bssid[7:]
   ssid = ssid[6:]

Теперь нам нужно добавить BSSID, SSID и метку времени в словарь wifi следующим образом:

if bssid in wifi.keys():

wifi[bssid]["Timestamps"].append(ts)
   wifi[bssid]["SSID"].append(ssid)
else:
   wifi[bssid] = {"Timestamps": [ts], "SSID":
[ssid],"Wigle": {}}
return wifi

Анализатор текста, который намного проще, чем анализатор XML, показан ниже —

def parse_txt(txt_file):
   wifi = {}
   print("[+] Extracting MAC addresses from {}".format(txt_file))
   
   with open(txt_file) as mac_file:
      for line in mac_file:
         wifi[line.strip()] = {"Timestamps": ["N/A"], "SSID":
["N/A"],"Wigle": {}}
return wifi

Теперь давайте воспользуемся модулем запросов для выполнения вызовов API WIGLE и перейдем к методу query_wigle ()

def query_wigle(wifi_dictionary, out_csv, api_key):
   print("[+] Querying Wigle.net through Python API for {} "
"APs".format(len(wifi_dictionary)))
   for mac in wifi_dictionary:

   wigle_results = query_mac_addr(mac, api_key)
def query_mac_addr(mac_addr, api_key):

   query_url = "https://api.wigle.net/api/v2/network/search?" \
"onlymine = false&freenet = false&paynet = false" \ "&netid = {}".format(mac_addr)
   req = requests.get(query_url, auth = (api_key[0], api_key[1]))
   return req.json()

На самом деле существует ограничение в день для вызовов WIGLE API, если этот предел превышает, то он должен показать ошибку следующим образом:

try:
   if wigle_results["resultCount"] == 0:
      wifi_dictionary[mac]["Wigle"]["results"] = []
         continue
   else:
      wifi_dictionary[mac]["Wigle"] = wigle_results
except KeyError:
   if wigle_results["error"] == "too many queries today":
      print("[-] Wigle daily query limit exceeded")
      wifi_dictionary[mac]["Wigle"]["results"] = []
      continue
   else:
      print("[-] Other error encountered for " "address {}: {}".format(mac,
wigle_results['error']))
   wifi_dictionary[mac]["Wigle"]["results"] = []
   continue
prep_output(out_csv, wifi_dictionary)

Теперь мы будем использовать метод prep_output (), чтобы сгладить словарь в легко записываемые фрагменты —

def prep_output(output, data):
   csv_data = {}
   google_map = https://www.google.com/maps/search/

Теперь получите доступ ко всем данным, которые мы собрали, следующим образом:

for x, mac in enumerate(data):
   for y, ts in enumerate(data[mac]["Timestamps"]):
      for z, result in enumerate(data[mac]["Wigle"]["results"]):
         shortres = data[mac]["Wigle"]["results"][z]
         g_map_url = "{}{},{}".format(google_map, shortres["trilat"],shortres["trilong"])

Теперь мы можем записать вывод в файл CSV, как мы делали в предыдущих сценариях в этой главе, используя функцию write_csv () .

Изучение встроенных метаданных

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

Вступление

Встроенные метаданные — это информация о данных, хранящихся в том же файле, в котором находится объект, описанный этими данными. Другими словами, это информация о цифровом ресурсе, хранящаяся в самом цифровом файле. Он всегда связан с файлом и никогда не может быть отделен.

В случае цифровой криминалистики мы не можем извлечь всю информацию о конкретном файле. С другой стороны, встроенные метаданные могут предоставить нам информацию, необходимую для расследования. Например, метаданные текстового файла могут содержать информацию об авторе, его длине, дате написания и даже краткую сводку об этом документе. Цифровое изображение может включать метаданные, такие как длина изображения, выдержка и т. Д.

Артефакты, содержащие атрибуты метаданных и их извлечение

В этом разделе мы узнаем о различных артефактах, содержащих атрибуты метаданных, и об их процессе извлечения с использованием Python.

Аудио и видео

Это два очень распространенных артефакта, которые имеют встроенные метаданные. Эти метаданные могут быть извлечены для целей исследования.

Вы можете использовать следующий скрипт Python для извлечения общих атрибутов или метаданных из аудио или MP3-файла и видео или MP4-файла.

Обратите внимание, что для этого скрипта нам нужно установить стороннюю библиотеку Python с именем mutagen, которая позволяет извлекать метаданные из аудио и видео файлов. Его можно установить с помощью следующей команды —

pip install mutagen

Вот некоторые из полезных библиотек, которые нам нужно импортировать для этого скрипта Python:

from __future__ import print_function

import argparse
import json
import mutagen

Обработчик командной строки принимает один аргумент, представляющий путь к файлам MP3 или MP4. Затем мы будем использовать метод mutagen.file (), чтобы открыть дескриптор файла следующим образом:

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Python Metadata Extractor')
   parser.add_argument("AV_FILE", help="File to extract metadata from")
   args = parser.parse_args()
   av_file = mutagen.File(args.AV_FILE)
   file_ext = args.AV_FILE.rsplit('.', 1)[-1]
   
   if file_ext.lower() == 'mp3':
      handle_id3(av_file)
   elif file_ext.lower() == 'mp4':
      handle_mp4(av_file)

Теперь нам нужно использовать два дескриптора: один для извлечения данных из MP3 и один для извлечения данных из файла MP4. Мы можем определить эти ручки следующим образом:

def handle_id3(id3_file):
   id3_frames = {'TIT2': 'Title', 'TPE1': 'Artist', 'TALB': 'Album','TXXX':
      'Custom', 'TCON': 'Content Type', 'TDRL': 'Date released','COMM': 'Comments',
         'TDRC': 'Recording Date'}
   print("{:15} | {:15} | {:38} | {}".format("Frame", "Description","Text","Value"))
   print("-" * 85)
   
   for frames in id3_file.tags.values():
      frame_name = id3_frames.get(frames.FrameID, frames.FrameID)
      desc = getattr(frames, 'desc', "N/A")
      text = getattr(frames, 'text', ["N/A"])[0]
      value = getattr(frames, 'value', "N/A")
      
      if "date" in frame_name.lower():
         text = str(text)
      print("{:15} | {:15} | {:38} | {}".format(
         frame_name, desc, text, value))
def handle_mp4(mp4_file):
   cp_sym = u"\u00A9"
   qt_tag = {
      cp_sym + 'nam': 'Title', cp_sym + 'art': 'Artist',
      cp_sym + 'alb': 'Album', cp_sym + 'gen': 'Genre',
      'cpil': 'Compilation', cp_sym + 'day': 'Creation Date',
      'cnID': 'Apple Store Content ID', 'atID': 'Album Title ID',
      'plID': 'Playlist ID', 'geID': 'Genre ID', 'pcst': 'Podcast',
      'purl': 'Podcast URL', 'egid': 'Episode Global ID',
      'cmID': 'Camera ID', 'sfID': 'Apple Store Country',
      'desc': 'Description', 'ldes': 'Long Description'}
genre_ids = json.load(open('apple_genres.json'))

Теперь нам нужно перебрать этот файл MP4 следующим образом:

print("{:22} | {}".format('Name', 'Value'))
print("-" * 40)

for name, value in mp4_file.tags.items():
   tag_name = qt_tag.get(name, name)
   
   if isinstance(value, list):
      value = "; ".join([str(x) for x in value])
   if name == 'geID':
      value = "{}: {}".format(
      value, genre_ids[str(value)].replace("|", " - "))
   print("{:22} | {}".format(tag_name, value))

Приведенный выше скрипт даст нам дополнительную информацию о MP3, а также файлах MP4.

Изображений

Изображения могут содержать различные виды метаданных в зависимости от формата файла. Однако большинство изображений содержат информацию GPS. Мы можем извлечь эту информацию GPS с помощью сторонних библиотек Python. Вы можете использовать следующий скрипт Python, чтобы сделать то же самое —

Сначала загрузите стороннюю библиотеку Python с именем Python Imaging Library (PIL) следующим образом:

pip install pillow

Это поможет нам извлечь метаданные из изображений.

Мы также можем записать данные GPS, встроенные в изображения, в файл KML, но для этого нам нужно скачать стороннюю библиотеку Python с именем simplekml следующим образом:

pip install simplekml

В этом скрипте сначала нам нужно импортировать следующие библиотеки —

from __future__ import print_function
import argparse

from PIL import Image
from PIL.ExifTags import TAGS

import simplekml
import sys

Теперь обработчик командной строки примет один позиционный аргумент, который в основном представляет путь файла фотографий.

parser = argparse.ArgumentParser('Metadata from images')
parser.add_argument('PICTURE_FILE', help = "Path to picture")
args = parser.parse_args()

Теперь нам нужно указать URL-адреса, которые будут заполнять информацию о координатах. URL-адреса — это gmaps и open_maps . Нам также нужна функция для преобразования координаты кортежа в минутах и ​​секундах (DMS), предоставленной библиотекой PIL, в десятичную. Это можно сделать следующим образом —

gmaps = "https://www.google.com/maps?q={},{}"
open_maps = "http://www.openstreetmap.org/?mlat={}&mlon={}"

def process_coords(coord):
   coord_deg = 0
   
   for count, values in enumerate(coord):
      coord_deg += (float(values[0]) / values[1]) / 60**count
   return coord_deg

Теперь мы будем использовать функцию image.open (), чтобы открыть файл как объект PIL.

img_file = Image.open(args.PICTURE_FILE)
exif_data = img_file._getexif()

if exif_data is None:
   print("No EXIF data found")
   sys.exit()
for name, value in exif_data.items():
   gps_tag = TAGS.get(name, name)
   if gps_tag is not 'GPSInfo':
      continue

Найдя тег GPSInfo , мы сохраним ссылку GPS и обработаем координаты методом process_coords () .

lat_ref = value[1] == u'N'
lat = process_coords(value[2])

if not lat_ref:
   lat = lat * -1
lon_ref = value[3] == u'E'
lon = process_coords(value[4])

if not lon_ref:
   lon = lon * -1

Теперь запустите объект kml из библиотеки simplekml следующим образом:

kml = simplekml.Kml()
kml.newpoint(name = args.PICTURE_FILE, coords = [(lon, lat)])
kml.save(args.PICTURE_FILE + ".kml")

Теперь мы можем распечатать координаты из обработанной информации следующим образом:

print("GPS Coordinates: {}, {}".format(lat, lon))
print("Google Maps URL: {}".format(gmaps.format(lat, lon)))
print("OpenStreetMap URL: {}".format(open_maps.format(lat, lon)))
print("KML File {} created".format(args.PICTURE_FILE + ".kml"))

PDF документы

Документы PDF имеют широкий спектр носителей, включая изображения, текст, формы и т. Д. Когда мы извлекаем встроенные метаданные в документы PDF, мы можем получить результирующие данные в формате, называемом платформой расширяемых метаданных (XMP). Мы можем извлечь метаданные с помощью следующего кода Python —

Сначала установите стороннюю библиотеку Python с именем PyPDF2 для чтения метаданных, хранящихся в формате XMP. Это может быть установлено следующим образом —

pip install PyPDF2

Теперь импортируйте следующие библиотеки для извлечения метаданных из файлов PDF:

from __future__ import print_function
from argparse import ArgumentParser, FileType

import datetime
from PyPDF2 import PdfFileReader
import sys

Теперь обработчик командной строки примет один позиционный аргумент, который в основном представляет путь к файлу PDF.

parser = argparse.ArgumentParser('Metadata from PDF')
parser.add_argument('PDF_FILE', help='Path to PDF file',type=FileType('rb'))
args = parser.parse_args()

Теперь мы можем использовать метод getXmpMetadata (), чтобы предоставить объект, содержащий доступные метаданные, следующим образом:

pdf_file = PdfFileReader(args.PDF_FILE)
xmpm = pdf_file.getXmpMetadata()

if xmpm is None:
   print("No XMP metadata found in document.")
   sys.exit()

Мы можем использовать метод custom_print () для извлечения и печати соответствующих значений, таких как title, creator, contributor и т. Д. Следующим образом:

custom_print("Title: {}", xmpm.dc_title)
custom_print("Creator(s): {}", xmpm.dc_creator)
custom_print("Contributors: {}", xmpm.dc_contributor)
custom_print("Subject: {}", xmpm.dc_subject)
custom_print("Description: {}", xmpm.dc_description)
custom_print("Created: {}", xmpm.xmp_createDate)
custom_print("Modified: {}", xmpm.xmp_modifyDate)
custom_print("Event Dates: {}", xmpm.dc_date)

Мы также можем определить метод custom_print () в случае, если PDF создается с использованием нескольких программ следующим образом:

def custom_print(fmt_str, value):
   if isinstance(value, list):
      print(fmt_str.format(", ".join(value)))
   elif isinstance(value, dict):
      fmt_value = [":".join((k, v)) for k, v in value.items()]
      print(fmt_str.format(", ".join(value)))
   elif isinstance(value, str) or isinstance(value, bool):
      print(fmt_str.format(value))
   elif isinstance(value, bytes):
      print(fmt_str.format(value.decode()))
   elif isinstance(value, datetime.datetime):
      print(fmt_str.format(value.isoformat()))
   elif value is None:
      print(fmt_str.format("N/A"))
   else:
      print("warn: unhandled type {} found".format(type(value)))

Мы также можем извлечь любое другое пользовательское свойство, сохраненное программным обеспечением, следующим образом:

if xmpm.custom_properties:
   print("Custom Properties:")
   
   for k, v in xmpm.custom_properties.items():
      print("\t{}: {}".format(k, v))

Приведенный выше скрипт будет читать документ PDF и печатать метаданные, хранящиеся в формате XMP, включая некоторые пользовательские свойства, сохраняемые программным обеспечением, с помощью которого был создан этот PDF.

Исполняемые файлы Windows

Иногда мы можем столкнуться с подозрительным или несанкционированным исполняемым файлом. Но для целей исследования это может быть полезно из-за встроенных метаданных. Мы можем получить такую ​​информацию, как ее местоположение, назначение и другие атрибуты, такие как производитель, дата компиляции и т. Д. С помощью следующего скрипта Python мы можем получить дату компиляции, полезные данные из заголовков и импортированных, а также экспортированные символы.

Для этого сначала установите сторонний файл библиотеки Python pefile . Это можно сделать следующим образом —

pip install pefile

После успешной установки импортируйте следующие библиотеки следующим образом:

from __future__ import print_function

import argparse
from datetime import datetime
from pefile import PE

Теперь обработчик командной строки примет один позиционный аргумент, который в основном представляет путь к файлу исполняемого файла. Вы также можете выбрать стиль вывода, будь то подробный и подробный или упрощенный способ. Для этого вам нужно указать необязательный аргумент, как показано ниже —

parser = argparse.ArgumentParser('Metadata from executable file')
parser.add_argument("EXE_FILE", help = "Path to exe file")
parser.add_argument("-v", "--verbose", help = "Increase verbosity of output",
action = 'store_true', default = False)
args = parser.parse_args()

Теперь мы загрузим входной исполняемый файл с помощью класса PE. Мы также будем выгружать исполняемые данные в объект словаря с помощью метода dump_dict () .

pe = PE(args.EXE_FILE)
ped = pe.dump_dict()

Мы можем извлечь основные метаданные файла, такие как встроенное авторство, версия и время компиляции, используя код, показанный ниже —

file_info = {}
for structure in pe.FileInfo:
   if structure.Key == b'StringFileInfo':
      for s_table in structure.StringTable:
         for key, value in s_table.entries.items():
            if value is None or len(value) == 0:
               value = "Unknown"
            file_info[key] = value
print("File Information: ")
print("==================")

for k, v in file_info.items():
   if isinstance(k, bytes):
      k = k.decode()
   if isinstance(v, bytes):
      v = v.decode()
   print("{}: {}".format(k, v))
comp_time = ped['FILE_HEADER']['TimeDateStamp']['Value']
comp_time = comp_time.split("[")[-1].strip("]")
time_stamp, timezone = comp_time.rsplit(" ", 1)
comp_time = datetime.strptime(time_stamp, "%a %b %d %H:%M:%S %Y")
print("Compiled on {} {}".format(comp_time, timezone.strip()))

Мы можем извлечь полезные данные из заголовков следующим образом:

for section in ped['PE Sections']:
   print("Section '{}' at {}: {}/{} {}".format(
      section['Name']['Value'], hex(section['VirtualAddress']['Value']),
      section['Misc_VirtualSize']['Value'],
      section['SizeOfRawData']['Value'], section['MD5'])
   )

Теперь извлеките список импорта и экспорта из исполняемых файлов, как показано ниже —

if hasattr(pe, 'DIRECTORY_ENTRY_IMPORT'):
   print("\nImports: ")
   print("=========")
   
   for dir_entry in pe.DIRECTORY_ENTRY_IMPORT:
      dll = dir_entry.dll
      
      if not args.verbose:
         print(dll.decode(), end=", ")
         continue
      name_list = []
      
      for impts in dir_entry.imports:
         if getattr(impts, "name", b"Unknown") is None:
            name = b"Unknown"
         else:
            name = getattr(impts, "name", b"Unknown")
			name_list.append([name.decode(), hex(impts.address)])
      name_fmt = ["{} ({})".format(x[0], x[1]) for x in name_list]
      print('- {}: {}'.format(dll.decode(), ", ".join(name_fmt)))
   if not args.verbose:
      print()

Теперь напечатайте экспорт , имена и адреса, используя код, как показано ниже —

if hasattr(pe, 'DIRECTORY_ENTRY_EXPORT'):
   print("\nExports: ")
   print("=========")
   
   for sym in pe.DIRECTORY_ENTRY_EXPORT.symbols:
      print('- {}: {}'.format(sym.name.decode(), hex(sym.address)))

Приведенный выше скрипт извлечет основные метаданные, информацию из заголовков из исполняемых файлов Windows.

Метаданные офисного документа

Большая часть работы на компьютере выполняется в трех приложениях MS Office — Word, PowerPoint и Excel. Эти файлы обладают огромными метаданными, которые могут предоставить интересную информацию об их авторстве и истории.

Обратите внимание, что метаданные из формата word (.docx), excel (.xlsx) и powerpoint (.pptx) 2007 года хранятся в файле XML. Мы можем обработать эти XML-файлы в Python с помощью следующего скрипта Python, показанного ниже —

Сначала импортируйте необходимые библиотеки, как показано ниже —

from __future__ import print_function
from argparse import ArgumentParser
from datetime import datetime as dt
from xml.etree import ElementTree as etree

import zipfile
parser = argparse.ArgumentParser('Office Document Metadata’)
parser.add_argument("Office_File", help="Path to office file to read")
args = parser.parse_args()

Теперь проверьте, является ли файл файлом ZIP. Иначе, поднять ошибку. Теперь откройте файл и извлеките ключевые элементы для обработки, используя следующий код —

zipfile.is_zipfile(args.Office_File)
zfile = zipfile.ZipFile(args.Office_File)
core_xml = etree.fromstring(zfile.read('docProps/core.xml'))
app_xml = etree.fromstring(zfile.read('docProps/app.xml'))

Теперь создайте словарь для начала извлечения метаданных —

core_mapping = {
   'title': 'Title',
   'subject': 'Subject',
   'creator': 'Author(s)',
   'keywords': 'Keywords',
   'description': 'Description',
   'lastModifiedBy': 'Last Modified By',
   'modified': 'Modified Date',
   'created': 'Created Date',
   'category': 'Category',
   'contentStatus': 'Status',
   'revision': 'Revision'
}

Используйте метод iterchildren () для доступа к каждому из тегов в файле XML —

for element in core_xml.getchildren():
   for key, title in core_mapping.items():
      if key in element.tag:
         if 'date' in title.lower():
            text = dt.strptime(element.text, "%Y-%m-%dT%H:%M:%SZ")
         else:
            text = element.text
         print("{}: {}".format(title, text))

Аналогичным образом, сделайте это для файла app.xml, который содержит статистическую информацию о содержании документа —

app_mapping = {
   'TotalTime': 'Edit Time (minutes)',
   'Pages': 'Page Count',
   'Words': 'Word Count',
   'Characters': 'Character Count',
   'Lines': 'Line Count',
   'Paragraphs': 'Paragraph Count',
   'Company': 'Company',
   'HyperlinkBase': 'Hyperlink Base',
   'Slides': 'Slide count',
   'Notes': 'Note Count',
   'HiddenSlides': 'Hidden Slide Count',
}
for element in app_xml.getchildren():
   for key, title in app_mapping.items():
      if key in element.tag:
         if 'date' in title.lower():
            text = dt.strptime(element.text, "%Y-%m-%dT%H:%M:%SZ")
         else:
            text = element.text
         print("{}: {}".format(title, text))

Теперь, после запуска вышеуказанного скрипта, мы можем получить различные подробности о конкретном документе. Обратите внимание, что мы можем применять этот сценарий только к документам Office 2007 или более поздней версии.

Python Digital Network Forensics-I

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

Понимание сетевой криминалистики

Сетевая криминалистика — это подразделение цифровой криминалистики, которое занимается мониторингом и анализом трафика компьютерной сети, как локальной, так и глобальной (глобальной сети), в целях сбора информации, сбора доказательств или обнаружения вторжений. Сетевая криминалистика играет важную роль в расследовании цифровых преступлений, таких как кража интеллектуальной собственности или утечка информации. Картина сетевых коммуникаций помогает исследователю решить некоторые важные вопросы следующим образом:

  • Какие сайты были доступны?

  • Какой контент был загружен в нашу сеть?

  • Какой контент был загружен из нашей сети?

  • К каким серверам осуществляется доступ?

  • Кто-то отправляет конфиденциальную информацию за пределы брандмауэров компании?

Какие сайты были доступны?

Какой контент был загружен в нашу сеть?

Какой контент был загружен из нашей сети?

К каким серверам осуществляется доступ?

Кто-то отправляет конфиденциальную информацию за пределы брандмауэров компании?

Internet Evidence Finder (IEF)

IEF является цифровым инструментом судебной экспертизы для поиска, анализа и представления цифровых доказательств, обнаруженных на различных цифровых носителях, таких как компьютеры, смартфоны, планшеты и т. Д. Он очень популярен и используется тысячами судебных экспертов.

Использование IEF

Из-за своей популярности IEF широко используется профессионалами-криминалистами. Некоторые из вариантов использования IEF:

  • Благодаря мощным возможностям поиска он используется для одновременного поиска нескольких файлов или носителей данных.

  • Он также используется для восстановления удаленных данных из нераспределенного пространства оперативной памяти с помощью новых методов вырезания.

  • Если следователи хотят перестроить веб-страницы в их первоначальном формате в день их открытия, они могут использовать IEF.

  • Он также используется для поиска на логических или физических дисковых томах.

Благодаря мощным возможностям поиска он используется для одновременного поиска нескольких файлов или носителей данных.

Он также используется для восстановления удаленных данных из нераспределенного пространства оперативной памяти с помощью новых методов вырезания.

Если следователи хотят перестроить веб-страницы в их первоначальном формате в день их открытия, они могут использовать IEF.

Он также используется для поиска на логических или физических дисковых томах.

Вывод отчетов из IEF в CSV с использованием Python

IEF хранит данные в базе данных SQLite, и следующий скрипт Python будет динамически определять таблицы результатов в базе данных IEF и выгружать их в соответствующие файлы CSV.

Этот процесс выполняется в шагах, показанных ниже

  • Сначала создайте базу данных результатов IEF, которая будет представлять собой файл базы данных SQLite, заканчивающийся расширением .db.

  • Затем запросите эту базу данных, чтобы определить все таблицы.

  • Наконец, запишите эти таблицы результатов в отдельный файл CSV.

Сначала создайте базу данных результатов IEF, которая будет представлять собой файл базы данных SQLite, заканчивающийся расширением .db.

Затем запросите эту базу данных, чтобы определить все таблицы.

Наконец, запишите эти таблицы результатов в отдельный файл CSV.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Для скрипта Python импортируйте необходимые библиотеки следующим образом:

from __future__ import print_function

import argparse
import csv
import os
import sqlite3
import sys

Теперь нам нужно указать путь к файлу базы данных IEF —

if __name__ == '__main__':
   parser = argparse.ArgumentParser('IEF to CSV')
   parser.add_argument("IEF_DATABASE", help="Input IEF database")
   parser.add_argument("OUTPUT_DIR", help="Output DIR")
   args = parser.parse_args()

Теперь мы подтвердим существование базы данных IEF следующим образом:

if not os.path.exists(args.OUTPUT_DIR):
   os.makedirs(args.OUTPUT_DIR)
if os.path.exists(args.IEF_DATABASE) and \ os.path.isfile(args.IEF_DATABASE):
   main(args.IEF_DATABASE, args.OUTPUT_DIR)
else:
   print("[-] Supplied input file {} does not exist or is not a " "file".format(args.IEF_DATABASE))
   sys.exit(1)

Теперь, как мы делали в более ранних сценариях, установите соединение с базой данных SQLite следующим образом, чтобы выполнить запросы через курсор —

def main(database, out_directory):
   print("[+] Connecting to SQLite database")
   conn = sqlite3.connect(database)
   c = conn.cursor()

Следующие строки кода извлекают имена таблиц из базы данных —

print("List of all tables to extract")
c.execute("select * from sqlite_master where type = 'table'")
tables = [x[2] for x in c.fetchall() if not x[2].startswith('_') and not x[2].endswith('_DATA')]

Теперь мы выберем все данные из таблицы и, используя метод fetchall () объекта курсора, сохраним список кортежей, содержащих данные таблицы, в виде переменной —

print("Dumping {} tables to CSV files in {}".format(len(tables), out_directory))

for table in tables:
c.execute("pragma table_info('{}')".format(table))
table_columns = [x[1] for x in c.fetchall()]

c.execute("select * from '{}'".format(table))
table_data = c.fetchall()

Теперь, используя метод CSV_Writer (), мы запишем содержимое в файл CSV —

csv_name = table + '.csv'
csv_path = os.path.join(out_directory, csv_name)
print('[+] Writing {} table to {} CSV file'.format(table,csv_name))

with open(csv_path, "w", newline = "") as csvfile:
   csv_writer = csv.writer(csvfile)
   csv_writer.writerow(table_columns)
   csv_writer.writerows(table_data)

Приведенный выше скрипт извлечет все данные из таблиц базы данных IEF и запишет содержимое в CSV-файл по нашему выбору.

Работа с кэшированными данными

Из базы данных результатов IEF мы можем получить больше информации, которая не обязательно поддерживается самим IEF. Мы можем получить кэшированные данные, два продукта для информации, от поставщика услуг электронной почты, такого как Yahoo, Google и т. Д., Используя базу данных результатов IEF.

Ниже приведен скрипт Python для доступа к данным кэшированных данных из почты Yahoo, доступ к которой осуществляется через Google Chrome, с использованием базы данных IEF. Обратите внимание, что шаги будут более или менее такими же, как и в последнем скрипте Python.

Сначала импортируйте необходимые библиотеки для Python следующим образом:

from __future__ import print_function
import argparse
import csv
import os
import sqlite3
import sys
import json

Теперь укажите путь к файлу базы данных IEF вместе с двумя позиционными аргументами, принимаемыми обработчиком командной строки, как это было сделано в последнем скрипте —

if __name__ == '__main__':
   parser = argparse.ArgumentParser('IEF to CSV')
   parser.add_argument("IEF_DATABASE", help="Input IEF database")
   parser.add_argument("OUTPUT_DIR", help="Output DIR")
   args = parser.parse_args()

Теперь подтвердите существование базы данных IEF следующим образом:

directory = os.path.dirname(args.OUTPUT_CSV)

if not os.path.exists(directory):os.makedirs(directory)
if os.path.exists(args.IEF_DATABASE) and \ os.path.isfile(args.IEF_DATABASE):
   main(args.IEF_DATABASE, args.OUTPUT_CSV)
   else: print("Supplied input file {} does not exist or is not a " "file".format(args.IEF_DATABASE))
sys.exit(1)

Теперь установите соединение с базой данных SQLite следующим образом, чтобы выполнить запросы через курсор —

def main(database, out_csv):
   print("[+] Connecting to SQLite database")
   conn = sqlite3.connect(database)
   c = conn.cursor()

Вы можете использовать следующие строки кода для извлечения экземпляров записи кэша контактов Yahoo Mail —

print("Querying IEF database for Yahoo Contact Fragments from " "the Chrome Cache Records Table")
   try:
      c.execute("select * from 'Chrome Cache Records' where URL like " "'https://data.mail.yahoo.com" "/classicab/v2/contacts/?format=json%'")
   except sqlite3.OperationalError:
      print("Received an error querying the database --    database may be" "corrupt or not have a Chrome Cache Records table")
      sys.exit(2)

Теперь список кортежей, возвращаемых из вышеуказанного запроса, будет сохранен в переменную следующим образом:

contact_cache = c.fetchall()
contact_data = process_contacts(contact_cache)
write_csv(contact_data, out_csv)

Обратите внимание, что здесь мы будем использовать два метода, а именно process_contacts () для настройки списка результатов, а также итерации по каждой записи кэша контактов и json.loads () для сохранения данных JSON, извлеченных из таблицы, в переменную для дальнейшей манипуляции —

def process_contacts(contact_cache):
   print("[+] Processing {} cache files matching Yahoo contact cache " " data".format(len(contact_cache)))
   results = []
   
   for contact in contact_cache:
      url = contact[0]
      first_visit = contact[1]
      last_visit = contact[2]
      last_sync = contact[3]
      loc = contact[8]
	   contact_json = json.loads(contact[7].decode())
      total_contacts = contact_json["total"]
      total_count = contact_json["count"]
      
      if "contacts" not in contact_json:
         continue
      for c in contact_json["contacts"]:
         name, anni, bday, emails, phones, links = ("", "", "", "", "", "")
            if "name" in c:
            name = c["name"]["givenName"] + " " + \ c["name"]["middleName"] + " " + c["name"]["familyName"]
            
            if "anniversary" in c:
            anni = c["anniversary"]["month"] + \"/" + c["anniversary"]["day"] + "/" + \c["anniversary"]["year"]
            
            if "birthday" in c:
            bday = c["birthday"]["month"] + "/" + \c["birthday"]["day"] + "/" + c["birthday"]["year"]
            
            if "emails" in c:
               emails = ', '.join([x["ep"] for x in c["emails"]])
            
            if "phones" in c:
               phones = ', '.join([x["ep"] for x in c["phones"]])
            
            if "links" in c:
              links = ', '.join([x["ep"] for x in c["links"]])

Теперь для компании, заголовка и заметок используется метод get, как показано ниже —

company = c.get("company", "")
title = c.get("jobTitle", "")
notes = c.get("notes", "")

Теперь давайте добавим список метаданных и извлеченных элементов данных в список результатов следующим образом:

results.append([url, first_visit, last_visit, last_sync, loc, name, bday,anni, emails, phones, links, company, title, notes,total_contacts, total_count])
return results   

Теперь, используя метод CSV_Writer () , мы запишем содержимое в файл CSV —

def write_csv(data, output):
   print("[+] Writing {} contacts to {}".format(len(data), output))
   with open(output, "w", newline="") as csvfile:
      csv_writer = csv.writer(csvfile)
      csv_writer.writerow([
         "URL", "First Visit (UTC)", "Last Visit (UTC)",
         "Last Sync (UTC)", "Location", "Contact Name", "Bday",
         "Anniversary", "Emails", "Phones", "Links", "Company", "Title",
         "Notes", "Total Contacts", "Count of Contacts in Cache"])
      csv_writer.writerows(data)  

С помощью приведенного выше сценария мы можем обработать кэшированные данные из почты Yahoo с помощью базы данных IEF.

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

Расследование по электронной почте

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

Роль электронной почты в расследовании

Электронные письма играют очень важную роль в деловом общении и стали одним из самых важных приложений в Интернете. Это удобный режим для отправки сообщений и документов не только с компьютеров, но и с других электронных гаджетов, таких как мобильные телефоны и планшеты.

Негативной стороной электронных писем является то, что преступники могут утекать важную информацию о своей компании. Следовательно, роль электронных писем в цифровой криминалистике в последние годы возросла. В цифровой криминалистике электронные письма считаются важными доказательствами, и анализ заголовков электронной почты стал важным для сбора доказательств в ходе судебной экспертизы.

Следователь преследует следующие цели при проведении экспертизы электронной почты:

  • Определить основного преступника
  • Собрать необходимые доказательства
  • Чтобы представить выводы
  • Построить корпус

Проблемы в электронной почте Forensics

Экспертиза электронной почты играет очень важную роль в расследовании, так как большая часть сообщений в современную эпоху основана на электронной почте. Тем не менее, судебный следователь по электронной почте может столкнуться со следующими проблемами в ходе расследования:

Поддельные электронные письма

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

Подделка

Еще одна проблема в судебной экспертизе электронной почты заключается в подделке, в которой преступники использовали электронную почту как чужую. В этом случае аппарат получит как поддельный, так и оригинальный IP-адрес.

Анонимная переписка по электронной почте

Здесь сервер электронной почты удаляет идентифицирующую информацию из сообщения электронной почты перед дальнейшей пересылкой. Это приводит к еще одной большой проблеме для расследований по электронной почте.

Методы, используемые в электронной судебной экспертизе

Экспертиза электронной почты — это исследование источника и содержания электронной почты в качестве доказательства для идентификации фактического отправителя и получателя сообщения, а также некоторой другой информации, такой как дата / время передачи и намерение отправителя. Он включает в себя исследование метаданных, сканирование портов, а также поиск по ключевым словам.

Некоторые из общих методов, которые могут использоваться для судебного расследования по электронной почте:

  • Анализ заголовка
  • Исследование сервера
  • Исследование сетевого устройства
  • Отпечатки отправителя
  • Программные встроенные идентификаторы

В следующих разделах мы узнаем, как получать информацию с помощью Python для изучения электронной почты.

Извлечение информации из файлов EML

Файлы EML в основном представляют собой электронные письма в формате файлов, которые широко используются для хранения сообщений электронной почты. Это структурированные текстовые файлы, которые совместимы с несколькими почтовыми клиентами, такими как Microsoft Outlook, Outlook Express и Windows Live Mail.

EML-файл хранит заголовки сообщений электронной почты, содержимое тела, данные вложений в виде простого текста. Он использует base64 для кодирования двоичных данных и кодирование Quoted-Printable (QP) для хранения информации о содержимом. Сценарий Python, который можно использовать для извлечения информации из файла EML, приведен ниже —

Сначала импортируйте следующие библиотеки Python, как показано ниже:

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

import os
import quopri
import base64

В приведенных выше библиотеках quopri используется для декодирования кодированных значений QP из файлов EML. Любые данные в кодировке base64 могут быть декодированы с помощью библиотеки base64 .

Далее, давайте предоставим аргумент для обработчика командной строки. Обратите внимание, что здесь он будет принимать только один аргумент, который будет путь к файлу EML, как показано ниже —

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)

Теперь нам нужно определить функцию main (), в которой мы будем использовать метод message_from_file () из библиотеки электронной почты для чтения файла как объекта. Здесь мы получим доступ к заголовкам, содержанию тела, вложениям и другой полезной информации, используя результирующую переменную с именем emlfile, как показано в приведенном ниже коде —

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

Теперь нам нужно определить метод process_payload (), в котором мы будем извлекать содержимое тела сообщения с помощью метода get_payload () . Мы будем декодировать закодированные в QP данные с помощью функции quopri.decodestring () . Мы также проверим тип содержимого MIME, чтобы он мог правильно обрабатывать хранение электронной почты. Соблюдайте код, указанный ниже —

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)

После выполнения вышеуказанного скрипта мы получим информацию заголовка вместе с различными полезными данными на консоли.

Анализ файлов MSG с использованием Python

Сообщения электронной почты приходят в разных форматах. MSG является одним из таких форматов, используемых Microsoft Outlook и Exchange. Файлы с расширением MSG могут содержать простой текст ASCII для заголовков и основного текста сообщения, а также гиперссылки и вложения.

В этом разделе мы узнаем, как извлечь информацию из файла MSG с помощью Outlook API. Обратите внимание, что следующий скрипт Python будет работать только в Windows. Для этого нам нужно установить стороннюю библиотеку Python с именем pywin32 следующим образом:

pip install pywin32

Теперь импортируйте следующие библиотеки, используя показанные команды:

from __future__ import print_function
from argparse import ArgumentParser

import os
import win32com.client
import pywintypes

Теперь давайте предоставим аргумент для обработчика командной строки. Здесь он будет принимать два аргумента, один из которых будет путем к файлу MSG, а другой будет желаемой выходной папкой следующим образом:

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)

Теперь нам нужно определить функцию main (), в которой мы будем вызывать библиотеку win32com для настройки API-интерфейса Outlook, который дополнительно разрешает доступ к пространству имен MAPI .

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)

Теперь определите различные функции, которые мы используем в этом скрипте. Приведенный ниже код показывает определение функции display_msg_attribs (), которая позволяет нам отображать различные атрибуты сообщения, такие как тема, BCC, CC, размер, имя отправителя, отправлено и т. Д.

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

Теперь определите функцию display_msg_recipeints (), которая перебирает сообщения и отображает сведения о получателе.

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

Далее мы определяем функцию extract_msg_body (), которая извлекает из сообщения содержимое тела, HTML и обычный текст.

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

Далее мы определим функцию extract_attachments (), которая экспортирует данные вложения в желаемый выходной каталог.

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

Как только все функции будут определены, мы выведем все атрибуты на консоль со следующей строкой кодов:

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

После запуска вышеуказанного скрипта мы получим атрибуты сообщения и его вложений в окне консоли, а также несколько файлов в выходном каталоге.

Структурирование файлов MBOX из Google Takeout с использованием Python

MBOX-файлы — это текстовые файлы со специальным форматированием, которые разделяют хранящиеся в них сообщения. Они часто встречаются в системах UNIX, Thunderbolt и Google Takeouts.

В этом разделе вы увидите скрипт Python, где мы будем структурировать файлы MBOX, полученные из Google Takeouts. Но перед этим мы должны знать, как мы можем генерировать эти файлы MBOX, используя нашу учетную запись Google или Gmail.

Перевод почтового ящика аккаунта Google в формат MBX

Приобретение почтового ящика аккаунта Google подразумевает создание резервной копии нашего аккаунта Gmail. Резервное копирование может быть сделано по различным личным или профессиональным причинам. Обратите внимание, что Google обеспечивает резервное копирование данных Gmail. Чтобы приобрести почтовый ящик нашей учетной записи Google в формате MBOX, вам необходимо выполнить следующие шаги:

  • Откройте Личный кабинет .

  • Перейдите в раздел «Личная информация и конфиденциальность» и выберите «Управление ссылкой на контент».

  • Вы можете создать новый архив или управлять существующим. Если щелкнуть ссылку CREATE ARCHIVE , мы получим несколько флажков для каждого продукта Google, который мы хотим включить.

  • После выбора продуктов мы получим свободу выбора типа файла и максимального размера для нашего архива, а также способа доставки из списка.

  • Наконец, мы получим эту резервную копию в формате MBOX.

Откройте Личный кабинет .

Перейдите в раздел «Личная информация и конфиденциальность» и выберите «Управление ссылкой на контент».

Вы можете создать новый архив или управлять существующим. Если щелкнуть ссылку CREATE ARCHIVE , мы получим несколько флажков для каждого продукта Google, который мы хотим включить.

После выбора продуктов мы получим свободу выбора типа файла и максимального размера для нашего архива, а также способа доставки из списка.

Наконец, мы получим эту резервную копию в формате MBOX.

Код Python

Теперь файл MBOX, рассмотренный выше, может быть структурирован с использованием Python, как показано ниже —

Во-первых, необходимо импортировать библиотеки Python следующим образом:

from __future__ import print_function
from argparse import ArgumentParser

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

import base64

Все библиотеки были использованы и объяснены в более ранних сценариях, кроме библиотеки почтовых ящиков, которая используется для анализа файлов MBOX.

Теперь предоставьте аргумент для обработчика командной строки. Здесь он будет принимать два аргумента — один будет путем к файлу MBOX, а другой будет желаемой выходной папкой.

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)

Теперь определим функцию main () и вызовем класс mbox библиотеки почтовых ящиков, с помощью которого мы можем проанализировать файл MBOX, указав его путь —

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

Теперь определите метод чтения для библиотеки почтовых ящиков следующим образом:

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)

Теперь создайте некоторые переменные для дальнейшей обработки следующим образом:

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

Затем используйте tqdm для генерации индикатора выполнения и отслеживания итерационного процесса следующим образом:

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

Теперь проверьте, есть ли в сообщении о погоде полезные данные или нет. Если это так, мы определим метод write_payload () следующим образом:

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)

Теперь данные должны быть добавлены. Затем мы вызовем метод create_report () следующим образом:

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

Заметьте, что вышеприведенные операторы if-else легко понять. Теперь нам нужно определить метод, который будет извлекать имя файла из объекта msg следующим образом:

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)

Теперь с помощью следующих строк кода вы можете экспортировать файл:

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

Теперь давайте определим функцию для извлечения имен файлов из сообщения, чтобы точно представлять имена этих файлов следующим образом:

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)

Теперь мы можем написать файл CSV, определив функцию create_report () следующим образом:

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)

Как только вы запустите скрипт, указанный выше, мы получим отчет CSV и каталог, полный вложений.

Важные артефакты в Windows-I

В этой главе будут объяснены различные концепции, связанные с экспертизой Microsoft Windows, и важные артефакты, которые исследователь может получить в процессе расследования.

Вступление

Артефакты — это объекты или области в компьютерной системе, которые имеют важную информацию, связанную с действиями, выполняемыми пользователем компьютера. Тип и расположение этой информации зависит от операционной системы. Во время криминалистического анализа эти артефакты играют очень важную роль в одобрении или неодобрении наблюдения исследователя.

Важность артефактов Windows для криминалистики

Артефакты Windows приобретают значение по следующим причинам:

  • Около 90% трафика в мире приходится на компьютеры, использующие Windows в качестве операционной системы. Вот почему для цифровых криминалистов артефакты Windows очень важны.

  • Операционная система Windows хранит различные типы доказательств, связанных с деятельностью пользователя в компьютерной системе. Это еще одна причина, которая показывает важность артефактов Windows для цифровой криминалистики.

  • Много раз следователь вращает расследование вокруг старых и традиционных областей, таких как пользовательские данные. Артефакты Windows могут привести исследование к нетрадиционным областям, таким как данные, созданные системой, или артефакты.

  • Windows предоставляет большое количество артефактов, которые полезны для следователей, а также для компаний и частных лиц, проводящих неформальные расследования.

  • Рост киберпреступности в последние годы является еще одной причиной значимости артефактов Windows.

Около 90% трафика в мире приходится на компьютеры, использующие Windows в качестве операционной системы. Вот почему для цифровых криминалистов артефакты Windows очень важны.

Операционная система Windows хранит различные типы доказательств, связанных с деятельностью пользователя в компьютерной системе. Это еще одна причина, которая показывает важность артефактов Windows для цифровой криминалистики.

Много раз следователь вращает расследование вокруг старых и традиционных областей, таких как пользовательские данные. Артефакты Windows могут привести исследование к нетрадиционным областям, таким как данные, созданные системой, или артефакты.

Windows предоставляет большое количество артефактов, которые полезны для следователей, а также для компаний и частных лиц, проводящих неформальные расследования.

Рост киберпреступности в последние годы является еще одной причиной значимости артефактов Windows.

Артефакты Windows и их скрипты Python

В этом разделе мы собираемся обсудить некоторые артефакты Windows и скрипты Python для извлечения информации из них.

Корзина

Это один из важных артефактов Windows для криминалистического расследования. В корзине Windows находятся файлы, которые были удалены пользователем, но еще не удалены системой. Даже если пользователь полностью удаляет файл из системы, он служит важным источником расследования. Это связано с тем, что экзаменатор может извлекать из удаленных файлов ценную информацию, например, исходный путь к файлу, а также время его отправки в корзину.

Обратите внимание, что хранение данных корзины зависит от версии Windows. В следующем скрипте Python мы будем иметь дело с Windows 7, где он создает два файла: файл $ R, который содержит фактическое содержимое переработанного файла, и файл $ I, который содержит исходное имя файла, путь, размер файла при удалении файла. ,

Для скрипта Python нам нужно установить сторонние модули, а именно pytsk3, pyewf и unicodecsv . Мы можем использовать pip для их установки. Мы можем выполнить следующие шаги для извлечения информации из корзины —

  • Во-первых, нам нужно использовать рекурсивный метод для сканирования через папку $ Recycle.bin и выбрать все файлы, начиная с $ I.

  • Далее мы будем читать содержимое файлов и анализировать доступные структуры метаданных.

  • Теперь мы будем искать связанный файл $ R.

  • Наконец, мы запишем результаты в файл CSV для просмотра.

Во-первых, нам нужно использовать рекурсивный метод для сканирования через папку $ Recycle.bin и выбрать все файлы, начиная с $ I.

Далее мы будем читать содержимое файлов и анализировать доступные структуры метаданных.

Теперь мы будем искать связанный файл $ R.

Наконец, мы запишем результаты в файл CSV для просмотра.

Давайте посмотрим, как использовать код Python для этой цели —

Во-первых, нам нужно импортировать следующие библиотеки Python —

from __future__ import print_function
from argparse import ArgumentParser

import datetime
import os
import struct

from utility.pytskutil import TSKUtil
import unicodecsv as csv

Далее нам нужно предоставить аргумент для обработчика командной строки. Обратите внимание, что здесь он будет принимать три аргумента: первый — это путь к файлу доказательств, второй — тип файла доказательств, а третий — желаемый выходной путь к отчету CSV, как показано ниже —

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Recycle Bin evidences')
   parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
   parser.add_argument('IMAGE_TYPE', help = "Evidence file format",
   choices = ('ewf', 'raw'))
   parser.add_argument('CSV_REPORT', help = "Path to CSV report")
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.CSV_REPORT)

Теперь определите функцию main (), которая будет обрабатывать всю обработку. Он будет искать файл $ I следующим образом:

def main(evidence, image_type, report_file):
   tsk_util = TSKUtil(evidence, image_type)
   dollar_i_files = tsk_util.recurse_files("$I", path = '/$Recycle.bin',logic = "startswith")
   
   if dollar_i_files is not None:
      processed_files = process_dollar_i(tsk_util, dollar_i_files)
      write_csv(report_file,['file_path', 'file_size', 'deleted_time','dollar_i_file', 'dollar_r_file', 'is_directory'],processed_files)
   else:
      print("No $I files found")

Теперь, если мы нашли файл $ I , он должен быть отправлен в функцию process_dollar_i (), которая будет принимать объект tsk_util, а также список файлов $ I , как показано ниже —

def process_dollar_i(tsk_util, dollar_i_files):
   processed_files = []
   
   for dollar_i in dollar_i_files:
      file_attribs = read_dollar_i(dollar_i[2])
      if file_attribs is None:
         continue
      file_attribs['dollar_i_file'] = os.path.join('/$Recycle.bin', dollar_i[1][1:])

Теперь найдите файлы $ R следующим образом:

recycle_file_path = os.path.join('/$Recycle.bin',dollar_i[1].rsplit("/", 1)[0][1:])
dollar_r_files = tsk_util.recurse_files(
   "$R" + dollar_i[0][2:],path = recycle_file_path, logic = "startswith")
   
   if dollar_r_files is None:
      dollar_r_dir = os.path.join(recycle_file_path,"$R" + dollar_i[0][2:])
      dollar_r_dirs = tsk_util.query_directory(dollar_r_dir)
   
   if dollar_r_dirs is None:
      file_attribs['dollar_r_file'] = "Not Found"
      file_attribs['is_directory'] = 'Unknown'
   
   else:
      file_attribs['dollar_r_file'] = dollar_r_dir
      file_attribs['is_directory'] = True
   
   else:
      dollar_r = [os.path.join(recycle_file_path, r[1][1:])for r in dollar_r_files]
      file_attribs['dollar_r_file'] = ";".join(dollar_r)
      file_attribs['is_directory'] = False
      processed_files.append(file_attribs)
   return processed_files  

Теперь определите метод read_dollar_i () для чтения файлов $ I , другими словами, для анализа метаданных. Мы будем использовать метод read_random () для чтения первых восьми байтов подписи. Это не вернет ничего, если подпись не совпадает. После этого нам нужно будет прочитать и распаковать значения из файла $ I, если это допустимый файл.

def read_dollar_i(file_obj):
   if file_obj.read_random(0, 8) != '\x01\x00\x00\x00\x00\x00\x00\x00':
      return None
   raw_file_size = struct.unpack('<q', file_obj.read_random(8, 8))
   raw_deleted_time = struct.unpack('<q',   file_obj.read_random(16, 8))
   raw_file_path = file_obj.read_random(24, 520)

Теперь, после извлечения этих файлов нам нужно интерпретировать целые числа в понятные человеку значения с помощью функции sizeof_fmt (), как показано ниже —

file_size = sizeof_fmt(raw_file_size[0])
deleted_time = parse_windows_filetime(raw_deleted_time[0])

file_path = raw_file_path.decode("utf16").strip("\x00")
return {'file_size': file_size, 'file_path': file_path,'deleted_time': deleted_time}

Теперь нам нужно определить функцию sizeof_fmt () следующим образом:

def sizeof_fmt(num, suffix = 'B'):
   for unit in ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi']:
      if abs(num) < 1024.0:
         return "%3.1f%s%s" % (num, unit, suffix)
      num /= 1024.0
   return "%.1f%s%s" % (num, 'Yi', suffix)

Теперь определим функцию для интерпретируемых целых чисел в форматированную дату и время следующим образом:

def parse_windows_filetime(date_value):
   microseconds = float(date_value) / 10
   ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(
      microseconds = microseconds)
   return ts.strftime('%Y-%m-%d %H:%M:%S.%f')

Теперь мы определим метод write_csv () для записи обработанных результатов в файл CSV следующим образом:

def write_csv(outfile, fieldnames, data):
   with open(outfile, 'wb') as open_outfile:
      csvfile = csv.DictWriter(open_outfile, fieldnames)
      csvfile.writeheader()
      csvfile.writerows(data)

Когда вы запустите приведенный выше скрипт, мы получим данные из файлов $ I и $ R.

Заметки

Windows Sticky Notes заменяет реальную привычку писать ручкой и бумагой. Эти заметки использовались для размещения на рабочем столе различных вариантов цветов, шрифтов и т. Д. В Windows 7 файл Sticky Notes хранится в виде файла OLE, поэтому в следующем скрипте Python мы исследуем этот файл OLE для извлечения метаданных из Sticky Notes.

Для этого скрипта Python нам нужно установить сторонние модули, а именно olefile, pytsk3, pyewf и unicodecsv. Мы можем использовать команду pip для их установки.

Мы можем выполнить шаги, описанные ниже, для извлечения информации из файла Sticky note, а именно StickyNote.sn

  • Во-первых, откройте файл улик и найдите все файлы StickyNote.snt.

  • Затем проанализируйте метаданные и содержимое из потока OLE и запишите содержимое RTF в файлы.

  • Наконец, создайте отчет CSV с этими метаданными.

Во-первых, откройте файл улик и найдите все файлы StickyNote.snt.

Затем проанализируйте метаданные и содержимое из потока OLE и запишите содержимое RTF в файлы.

Наконец, создайте отчет CSV с этими метаданными.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие библиотеки Python —

from __future__ import print_function
from argparse import ArgumentParser

import unicodecsv as csv
import os
import StringIO

from utility.pytskutil import TSKUtil
import olefile

Затем определите глобальную переменную, которая будет использоваться в этом скрипте —

REPORT_COLS = ['note_id', 'created', 'modified', 'note_text', 'note_file']

Далее нам нужно предоставить аргумент для обработчика командной строки. Обратите внимание, что здесь он будет принимать три аргумента: первый — это путь к файлу улик, второй — тип файла улик, а третий — желаемый путь вывода следующим образом:

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Evidence from Sticky Notes')
   parser.add_argument('EVIDENCE_FILE', help="Path to evidence file")
   parser.add_argument('IMAGE_TYPE', help="Evidence file format",choices=('ewf', 'raw'))
   parser.add_argument('REPORT_FOLDER', help="Path to report folder")
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT_FOLDER)

Теперь мы определим функцию main (), которая будет похожа на предыдущий скрипт, как показано ниже —

def main(evidence, image_type, report_folder):
   tsk_util = TSKUtil(evidence, image_type)
   note_files = tsk_util.recurse_files('StickyNotes.snt', '/Users','equals')

Теперь давайте пройдемся по полученным файлам. Затем мы вызовем функцию parse_snt_file () для обработки файла, а затем запишем файл RTF с помощью метода write_note_rtf () следующим образом:

report_details = []
for note_file in note_files:
   user_dir = note_file[1].split("/")[1]
   file_like_obj = create_file_like_obj(note_file[2])
   note_data = parse_snt_file(file_like_obj)
   
   if note_data is None:
      continue
   write_note_rtf(note_data, os.path.join(report_folder, user_dir))
   report_details += prep_note_report(note_data, REPORT_COLS,"/Users" + note_file[1])
   write_csv(os.path.join(report_folder, 'sticky_notes.csv'), REPORT_COLS,report_details)

Далее нам нужно определить различные функции, используемые в этом скрипте.

Прежде всего мы определим функцию create_file_like_obj () для считывания размера файла, взяв объект файла pytsk . Затем мы определим функцию parse_snt_file (), которая будет принимать файлоподобный объект в качестве входных данных и используется для чтения и интерпретации файла заметок.

def parse_snt_file(snt_file):
   
   if not olefile.isOleFile(snt_file):
      print("This is not an OLE file")
      return None
   ole = olefile.OleFileIO(snt_file)
   note = {}
   
   for stream in ole.listdir():
      if stream[0].count("-") == 3:
         if stream[0] not in note:
            note[stream[0]] = {"created": ole.getctime(stream[0]),"modified": ole.getmtime(stream[0])}
         content = None
         if stream[1] == '0':
            content = ole.openstream(stream).read()
         elif stream[1] == '3':
            content = ole.openstream(stream).read().decode("utf-16")
         if content:
            note[stream[0]][stream[1]] = content
	return note

Теперь создайте файл RTF, определив функцию write_note_rtf () следующим образом

def write_note_rtf(note_data, report_folder):
   if not os.path.exists(report_folder):
      os.makedirs(report_folder)
   
   for note_id, stream_data in note_data.items():
      fname = os.path.join(report_folder, note_id + ".rtf")
      with open(fname, 'w') as open_file:
         open_file.write(stream_data['0'])

Теперь мы переведем вложенный словарь в плоский список словарей, которые больше подходят для таблицы CSV. Это будет сделано путем определения функции prep_note_report () . Наконец, мы определим функцию write_csv () .

def prep_note_report(note_data, report_cols, note_file):
   report_details = []
   
   for note_id, stream_data in note_data.items():
      report_details.append({
         "note_id": note_id,
         "created": stream_data['created'],
         "modified": stream_data['modified'],
         "note_text": stream_data['3'].strip("\x00"),
         "note_file": note_file
      })
   return report_details
def write_csv(outfile, fieldnames, data):
   with open(outfile, 'wb') as open_outfile:
      csvfile = csv.DictWriter(open_outfile, fieldnames)
      csvfile.writeheader()
      csvfile.writerows(data)

После запуска вышеуказанного скрипта мы получим метаданные из файла Sticky Notes.

Файлы реестра

Файлы реестра Windows содержат много важных деталей, которые похожи на сокровищницу информации для судебного аналитика. Это иерархическая база данных, которая содержит детали, относящиеся к конфигурации операционной системы, действиям пользователя, установке программного обеспечения и т. Д. В следующем скрипте Python мы собираемся получить доступ к общей базовой информации из кустов SYSTEM и SOFTWARE .

Для этого скрипта Python нам нужно установить сторонние модули, а именно pytsk3, pyewf и Registry . Мы можем использовать pip для их установки.

Мы можем выполнить приведенные ниже шаги для извлечения информации из реестра Windows —

  • Во-первых, найдите кусты реестра для обработки как по имени, так и по пути.

  • Затем мы открываем эти файлы с помощью модулей StringIO и Registry.

  • Наконец нам нужно обработать каждый улей и вывести проанализированные значения на консоль для интерпретации.

Во-первых, найдите кусты реестра для обработки как по имени, так и по пути.

Затем мы открываем эти файлы с помощью модулей StringIO и Registry.

Наконец нам нужно обработать каждый улей и вывести проанализированные значения на консоль для интерпретации.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие библиотеки Python —

from __future__ import print_function
from argparse import ArgumentParser

import datetime
import StringIO
import struct

from utility.pytskutil import TSKUtil
from Registry import Registry

Теперь предоставьте аргумент для обработчика командной строки. Здесь он будет принимать два аргумента — первый — это путь к файлу доказательств, второй — тип файла доказательств, как показано ниже —

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Evidence from Windows Registry')
   parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
   parser.add_argument('IMAGE_TYPE', help = "Evidence file format",
   choices = ('ewf', 'raw'))
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE)

Теперь мы определим функцию main () для поиска кустов SYSTEM и SOFTWARE в папке / Windows / System32 / config следующим образом:

def main(evidence, image_type):
   tsk_util = TSKUtil(evidence, image_type)
   tsk_system_hive = tsk_util.recurse_files('system', '/Windows/system32/config', 'equals')
   tsk_software_hive = tsk_util.recurse_files('software', '/Windows/system32/config', 'equals')
   system_hive = open_file_as_reg(tsk_system_hive[0][2])
   software_hive = open_file_as_reg(tsk_software_hive[0][2])
   process_system_hive(system_hive)
   process_software_hive(software_hive)

Теперь определим функцию открытия файла реестра. Для этого нам нужно собрать размер файла из метаданных pytsk следующим образом:

def open_file_as_reg(reg_file):
   file_size = reg_file.info.meta.size
   file_content = reg_file.read_random(0, file_size)
   file_like_obj = StringIO.StringIO(file_content)
   return Registry.Registry(file_like_obj)

Теперь с помощью следующего метода мы можем обработать SYSTEM> hive —

def process_system_hive(hive):
   root = hive.root()
   current_control_set = root.find_key("Select").value("Current").value()
   control_set = root.find_key("ControlSet{:03d}".format(current_control_set))
   raw_shutdown_time = struct.unpack(
      '<Q', control_set.find_key("Control").find_key("Windows").value("ShutdownTime").value())
   
   shutdown_time = parse_windows_filetime(raw_shutdown_time[0])
   print("Last Shutdown Time: {}".format(shutdown_time))
   
   time_zone = control_set.find_key("Control").find_key("TimeZoneInformation")
      .value("TimeZoneKeyName").value()
   
   print("Machine Time Zone: {}".format(time_zone))
   computer_name = control_set.find_key("Control").find_key("ComputerName").find_key("ComputerName")
      .value("ComputerName").value()
   
   print("Machine Name: {}".format(computer_name))
   last_access = control_set.find_key("Control").find_key("FileSystem")
      .value("NtfsDisableLastAccessUpdate").value()
   last_access = "Disabled" if last_access == 1 else "enabled"
   print("Last Access Updates: {}".format(last_access))

Теперь нам нужно определить функцию для интерпретируемых целых чисел в форматированную дату и время следующим образом:

def parse_windows_filetime(date_value):
   microseconds = float(date_value) / 10
   ts = datetime.datetime(1601, 1, 1) + datetime.timedelta(microseconds = microseconds)
   return ts.strftime('%Y-%m-%d %H:%M:%S.%f')

def parse_unix_epoch(date_value):
   ts = datetime.datetime.fromtimestamp(date_value)
   return ts.strftime('%Y-%m-%d %H:%M:%S.%f')

Теперь с помощью следующего метода мы можем обработать улей ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ

def process_software_hive(hive):
   root = hive.root()
   nt_curr_ver = root.find_key("Microsoft").find_key("Windows NT")
      .find_key("CurrentVersion")
   
   print("Product name: {}".format(nt_curr_ver.value("ProductName").value()))
   print("CSD Version: {}".format(nt_curr_ver.value("CSDVersion").value()))
   print("Current Build: {}".format(nt_curr_ver.value("CurrentBuild").value()))
   print("Registered Owner: {}".format(nt_curr_ver.value("RegisteredOwner").value()))
   print("Registered Org: 
      {}".format(nt_curr_ver.value("RegisteredOrganization").value()))
   
   raw_install_date = nt_curr_ver.value("InstallDate").value()
   install_date = parse_unix_epoch(raw_install_date)
   print("Installation Date: {}".format(install_date))

После запуска вышеуказанного сценария мы получим метаданные, хранящиеся в файлах реестра Windows.

Важные артефакты в Windows-II

В этой главе рассказывается о некоторых более важных артефактах в Windows и их методе извлечения с использованием Python.

Действия пользователя

Windows, имеющая файл NTUSER.DAT для хранения различных действий пользователя. Каждый профиль пользователя имеет куст, как NTUSER.DAT , который хранит информацию и конфигурации, относящиеся конкретно к этому пользователю. Следовательно, это очень полезно для целей расследования судебно-медицинскими экспертами.

Следующий скрипт Python проанализирует некоторые ключи NTUSER.DAT для изучения действий пользователя в системе. Прежде чем продолжить, для скрипта Python нам нужно установить сторонние модули, а именно Registry, pytsk3 , pyewf и Jinja2 . Мы можем использовать pip для их установки.

Мы можем выполнить следующие шаги для извлечения информации из файла NTUSER.DAT

  • Сначала выполните поиск всех файлов NTUSER.DAT в системе.

  • Затем проанализируйте ключи WordWheelQuery, TypePath и RunMRU для каждого файла NTUSER.DAT .

  • Наконец, мы запишем эти уже обработанные артефакты в отчет HTML с помощью модуля jinja2.

Сначала выполните поиск всех файлов NTUSER.DAT в системе.

Затем проанализируйте ключи WordWheelQuery, TypePath и RunMRU для каждого файла NTUSER.DAT .

Наконец, мы запишем эти уже обработанные артефакты в отчет HTML с помощью модуля jinja2.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Прежде всего нам нужно импортировать следующие модули Python —

from __future__ import print_function
from argparse import ArgumentParser

import os
import StringIO
import struct

from utility.pytskutil import TSKUtil
from Registry import Registry
import jinja2

Теперь предоставьте аргумент для обработчика командной строки. Здесь он будет принимать три аргумента — первый — это путь к файлу улик, второй — тип файла улик, а третий — желаемый путь вывода к отчету HTML, как показано ниже —

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Information from user activities')
   parser.add_argument('EVIDENCE_FILE',help = "Path to evidence file")
   parser.add_argument('IMAGE_TYPE',help = "Evidence file format",choices = ('ewf', 'raw'))
   parser.add_argument('REPORT',help = "Path to report file")
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.REPORT)

Теперь давайте определим функцию main () для поиска всех файлов NTUSER.DAT , как показано ниже:

def main(evidence, image_type, report):
   tsk_util = TSKUtil(evidence, image_type)
   tsk_ntuser_hives = tsk_util.recurse_files('ntuser.dat','/Users', 'equals')
   
   nt_rec = {
      'wordwheel': {'data': [], 'title': 'WordWheel Query'},
      'typed_path': {'data': [], 'title': 'Typed Paths'},
      'run_mru': {'data': [], 'title': 'Run MRU'}
   }

Теперь мы попытаемся найти ключ в файле NTUSER.DAT и, как только вы его найдете, определите функции пользовательской обработки, как показано ниже:

for ntuser in tsk_ntuser_hives:
   uname = ntuser[1].split("/")

open_ntuser = open_file_as_reg(ntuser[2])
try:
   explorer_key = open_ntuser.root().find_key("Software").find_key("Microsoft")
      .find_key("Windows").find_key("CurrentVersion").find_key("Explorer")
   except Registry.RegistryKeyNotFoundException:
      continue
   nt_rec['wordwheel']['data'] += parse_wordwheel(explorer_key, uname)
   nt_rec['typed_path']['data'] += parse_typed_paths(explorer_key, uname)
   nt_rec['run_mru']['data'] += parse_run_mru(explorer_key, uname)
   nt_rec['wordwheel']['headers'] = \ nt_rec['wordwheel']['data'][0].keys()
   nt_rec['typed_path']['headers'] = \ nt_rec['typed_path']['data'][0].keys()
   nt_rec['run_mru']['headers'] = \ nt_rec['run_mru']['data'][0].keys()

Теперь передайте объект словаря и его путь методу write_html () следующим образом:

write_html(report, nt_rec)

Теперь определите метод, который берет дескриптор файла pytsk и считывает его в класс Registry через класс StringIO .

def open_file_as_reg(reg_file):
   file_size = reg_file.info.meta.size
   file_content = reg_file.read_random(0, file_size)
   file_like_obj = StringIO.StringIO(file_content)
   return Registry.Registry(file_like_obj)

Теперь мы определим функцию, которая будет анализировать и обрабатывать ключ WordWheelQuery из файла NTUSER.DAT следующим образом:

def parse_wordwheel(explorer_key, username):
   try:
      wwq = explorer_key.find_key("WordWheelQuery")
   except Registry.RegistryKeyNotFoundException:
      return []
   mru_list = wwq.value("MRUListEx").value()
   mru_order = []
   
   for i in xrange(0, len(mru_list), 2):
      order_val = struct.unpack('h', mru_list[i:i + 2])[0]
   if order_val in mru_order and order_val in (0, -1):
      break
   else:
      mru_order.append(order_val)
   search_list = []
   
   for count, val in enumerate(mru_order):
      ts = "N/A"
      if count == 0:
         ts = wwq.timestamp()
      search_list.append({
         'timestamp': ts,
         'username': username,
         'order': count,
         'value_name': str(val),
         'search': wwq.value(str(val)).value().decode("UTF-16").strip("\x00")
})
   return search_list  

Теперь мы определим функцию, которая будет анализировать и обрабатывать ключ TypedPaths из файла NTUSER.DAT следующим образом:

def parse_typed_paths(explorer_key, username):
   try:
      typed_paths = explorer_key.find_key("TypedPaths")
   except Registry.RegistryKeyNotFoundException:
      return []
   typed_path_details = []
   
   for val in typed_paths.values():
      typed_path_details.append({
         "username": username,
         "value_name": val.name(),
         "path": val.value()
      })
   return typed_path_details

Теперь мы определим функцию, которая будет анализировать и обрабатывать ключ RunMRU из файла NTUSER.DAT следующим образом:

def parse_run_mru(explorer_key, username):
   try:
      run_mru = explorer_key.find_key("RunMRU")
   except Registry.RegistryKeyNotFoundException:
      return []
   
   if len(run_mru.values()) == 0:
      return []
   mru_list = run_mru.value("MRUList").value()
   mru_order = []
   
   for i in mru_list:
      mru_order.append(i)
   mru_details = []
   
   for count, val in enumerate(mru_order):
      ts = "N/A"
      if count == 0:
         ts = run_mru.timestamp()
      mru_details.append({
         "username": username,
         "timestamp": ts,
         "order": count,
         "value_name": val,
         "run_statement": run_mru.value(val).value()
      })
   return mru_details

Теперь следующая функция будет обрабатывать создание отчета HTML —

def write_html(outfile, data_dict):
   cwd = os.path.dirname(os.path.abspath(__file__))
   env = jinja2.Environment(loader=jinja2.FileSystemLoader(cwd))
   template = env.get_template("user_activity.html")
   rendering = template.render(nt_data=data_dict)
   
   with open(outfile, 'w') as open_outfile:
      open_outfile.write(rendering)

Наконец мы можем написать HTML-документ для отчета. После запуска вышеуказанного скрипта мы получим информацию из файла NTUSER.DAT в формате документа HTML.

Файлы LINK

Файлы ярлыков создаются, когда пользователь или операционная система создает файлы ярлыков для файлов, которые часто используются, дважды щелкаются или доступны с системных дисков, таких как подключенное хранилище. Такие виды файлов ярлыков называются файлами ссылок. Получив доступ к этим файлам ссылок, исследователь может определить активность окна, например время и место, откуда были получены эти файлы.

Давайте обсудим скрипт Python, который мы можем использовать для получения информации из этих файлов Windows LINK.

Для скрипта Python установите сторонние модули, а именно pylnk, pytsk3, pyewf . Мы можем выполнить следующие шаги, чтобы извлечь информацию из файлов LNK

  • Сначала найдите файлы lnk в системе.

  • Затем извлеките информацию из этого файла, просматривая их.

  • Теперь, наконец, нам нужно эту информацию в отчете CSV.

Сначала найдите файлы lnk в системе.

Затем извлеките информацию из этого файла, просматривая их.

Теперь, наконец, нам нужно эту информацию в отчете CSV.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие библиотеки Python —

from __future__ import print_function
from argparse import ArgumentParser

import csv
import StringIO

from utility.pytskutil import TSKUtil
import pylnk

Теперь предоставьте аргумент для обработчика командной строки. Здесь он будет принимать три аргумента: первый — это путь к файлу улик, второй — тип файла улик, а третий — желаемый выходной путь к отчету CSV, как показано ниже —

if __name__ == '__main__':
   parser = argparse.ArgumentParser('Parsing LNK files')
   parser.add_argument('EVIDENCE_FILE', help = "Path to evidence file")
   parser.add_argument('IMAGE_TYPE', help = "Evidence file format",choices = ('ewf', 'raw'))
   parser.add_argument('CSV_REPORT', help = "Path to CSV report")
   args = parser.parse_args()
   main(args.EVIDENCE_FILE, args.IMAGE_TYPE, args.CSV_REPORT)

Теперь интерпретируйте файл улик, создав объект TSKUtil, и переберите файловую систему, чтобы найти файлы, оканчивающиеся на lnk . Это можно сделать, определив функцию main () следующим образом:

def main(evidence, image_type, report):
   tsk_util = TSKUtil(evidence, image_type)
   lnk_files = tsk_util.recurse_files("lnk", path="/", logic="endswith")
   
   if lnk_files is None:
      print("No lnk files found")
      exit(0)
   columns = [
      'command_line_arguments', 'description', 'drive_serial_number',
      'drive_type', 'file_access_time', 'file_attribute_flags',
      'file_creation_time', 'file_modification_time', 'file_size',
      'environmental_variables_location', 'volume_label',
      'machine_identifier', 'local_path', 'network_path',
      'relative_path', 'working_directory'
   ]

Теперь с помощью следующего кода мы будем перебирать файлы lnk , создавая функцию следующим образом:

parsed_lnks = []

for entry in lnk_files:
   lnk = open_file_as_lnk(entry[2])
   lnk_data = {'lnk_path': entry[1], 'lnk_name': entry[0]}
   
   for col in columns:
      lnk_data[col] = getattr(lnk, col, "N/A")
   lnk.close()
   parsed_lnks.append(lnk_data)
write_csv(report, columns + ['lnk_path', 'lnk_name'], parsed_lnks)

Теперь нам нужно определить две функции: одна откроет объект файла pytsk, а другая будет использована для написания отчета CSV, как показано ниже:

def open_file_as_lnk(lnk_file):
   file_size = lnk_file.info.meta.size
   file_content = lnk_file.read_random(0, file_size)
   file_like_obj = StringIO.StringIO(file_content)
   lnk = pylnk.file()
   lnk.open_file_object(file_like_obj)
   return lnk
def write_csv(outfile, fieldnames, data):
   with open(outfile, 'wb') as open_outfile:
      csvfile = csv.DictWriter(open_outfile, fieldnames)
      csvfile.writeheader()
      csvfile.writerows(data)

После запуска вышеуказанного скрипта мы получим информацию из обнаруженных файлов lnk в отчете CSV —

Файлы предварительной загрузки

Каждый раз, когда приложение запускается впервые из определенного места, Windows создает файлы предварительной выборки . Они используются для ускорения процесса запуска приложения. Расширение этих файлов — .PF, и они хранятся в папке «\ Root \ Windows \ Prefetch» .

Цифровые судебные эксперты могут раскрыть доказательства выполнения программы из указанного места вместе с данными пользователя. Файлы предварительной выборки являются полезными артефактами для экзаменатора, поскольку их запись сохраняется даже после удаления или удаления программы.

Давайте обсудим скрипт Python, который будет извлекать информацию из файлов предварительной загрузки Windows, как показано ниже —

Для сценария Python установите сторонние модули, а именно pylnk, pytsk3 и unicodecsv . Напомним, что мы уже работали с этими библиотеками в скриптах Python, которые мы обсуждали в предыдущих главах.

Мы должны следовать приведенным ниже шагам, чтобы извлечь информацию из файлов предварительной выборки

  • Во-первых, сканируйте файлы расширения .pf или файлы предварительной выборки.

  • Теперь выполните проверку подписи, чтобы устранить ложные срабатывания.

  • Затем проанализируйте формат файла предварительной загрузки Windows. Это отличается от версии для Windows. Например, для Windows XP это 17, для Windows Vista и Windows 7 это 23, 26 для Windows 8.1 и 30 для Windows 10.

  • Наконец, мы запишем проанализированный результат в файл CSV.

Во-первых, сканируйте файлы расширения .pf или файлы предварительной выборки.

Теперь выполните проверку подписи, чтобы устранить ложные срабатывания.

Затем проанализируйте формат файла предварительной загрузки Windows. Это отличается от версии для Windows. Например, для Windows XP это 17, для Windows Vista и Windows 7 это 23, 26 для Windows 8.1 и 30 для Windows 10.

Наконец, мы запишем проанализированный результат в файл CSV.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие библиотеки Python —

from __future__ import print_function
import argparse
from datetime import datetime, timedelta

import os
import pytsk3
import pyewf
import struct
import sys
import unicodecsv as csv
from utility.pytskutil import TSKUtil

Теперь предоставьте аргумент для обработчика командной строки. Здесь он будет принимать два аргумента: первый будет путь к файлу доказательств, а второй будет тип файла доказательств. Он также принимает необязательный аргумент для указания пути для сканирования файлов предварительной выборки —

if __name__ == "__main__":
   parser = argparse.ArgumentParser('Parsing Prefetch files')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
   parser.add_argument("OUTPUT_CSV", help = "Path to write output csv")
   parser.add_argument("-d", help = "Prefetch directory to scan",default = "/WINDOWS/PREFETCH")
   args = parser.parse_args()
   
   if os.path.exists(args.EVIDENCE_FILE) and \
      os.path.isfile(args.EVIDENCE_FILE):
   main(args.EVIDENCE_FILE, args.TYPE, args.OUTPUT_CSV, args.d)
else:
   print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
   sys.exit(1)

Теперь интерпретируйте файл улик, создав объект TSKUtil, и переберите файловую систему, чтобы найти файлы, заканчивающиеся на .pf . Это можно сделать, определив функцию main () следующим образом:

def main(evidence, image_type, output_csv, path):
   tsk_util = TSKUtil(evidence, image_type)
   prefetch_dir = tsk_util.query_directory(path)
   prefetch_files = None
   
   if prefetch_dir is not None:
      prefetch_files = tsk_util.recurse_files(".pf", path=path, logic="endswith")
   
   if prefetch_files is None:
      print("[-] No .pf files found")
      sys.exit(2)
   print("[+] Identified {} potential prefetch files".format(len(prefetch_files)))
   prefetch_data = []
   
   for hit in prefetch_files:
      prefetch_file = hit[2]
      pf_version = check_signature(prefetch_file)

Теперь определите метод, который будет проверять подписи, как показано ниже:

def check_signature(prefetch_file):
   version, signature = struct.unpack("^<2i", prefetch_file.read_random(0, 8))
   
   if signature == 1094927187:
      return version
   else:
      return None
   
   if pf_version is None:
      continue
   pf_name = hit[0]
   
   if pf_version == 17:
      parsed_data = parse_pf_17(prefetch_file, pf_name)
      parsed_data.append(os.path.join(path, hit[1].lstrip("//")))
      prefetch_data.append(parsed_data)

Теперь начните обработку файлов предварительной загрузки Windows. Здесь мы берем пример файлов предварительной загрузки Windows XP —

def parse_pf_17(prefetch_file, pf_name):
   create = convert_unix(prefetch_file.info.meta.crtime)
   modify = convert_unix(prefetch_file.info.meta.mtime)
def convert_unix(ts):
   if int(ts) == 0:
      return ""
   return datetime.utcfromtimestamp(ts)
def convert_filetime(ts):
   if int(ts) == 0:
      return ""
   return datetime(1601, 1, 1) + timedelta(microseconds=ts / 10)

Теперь извлеките данные, встроенные в предварительно выбранные файлы, используя структуру следующим образом:

pf_size, name, vol_info, vol_entries, vol_size, filetime, \
   count = struct.unpack("<i60s32x3iq16xi",prefetch_file.read_random(12, 136))
name = name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]

vol_name_offset, vol_name_length, vol_create, \
   vol_serial = struct.unpack("<2iqi",prefetch_file.read_random(vol_info, 20))
   vol_serial = hex(vol_serial).lstrip("0x")
   vol_serial = vol_serial[:4] + "-" + vol_serial[4:]
   vol_name = struct.unpack(
      "<{}s".format(2 * vol_name_length),
      prefetch_file.read_random(vol_info + vol_name_offset,vol_name_length * 2))[0]

vol_name = vol_name.decode("utf-16", "ignore").strip("/x00").split("/x00")[0]
return [
   pf_name, name, pf_size, create,
   modify, convert_filetime(filetime), count, vol_name,
   convert_filetime(vol_create), vol_serial ]

Поскольку мы предоставили версию предварительной выборки для Windows XP, но что, если она встретит версии предварительной выборки для других Windows. Затем он должен отобразить сообщение об ошибке следующим образом:

elif pf_version == 23:
   print("[-] Windows Vista / 7 PF file {} -- unsupported".format(pf_name))
   continue
elif pf_version == 26:
   print("[-] Windows 8 PF file {} -- unsupported".format(pf_name))
   continue
elif pf_version == 30:
   print("[-] Windows 10 PF file {} -- unsupported".format(pf_name))
continue

else:
   print("[-] Signature mismatch - Name: {}\nPath: {}".format(hit[0], hit[1]))
continue
write_output(prefetch_data, output_csv)

Теперь определите метод записи результата в отчет CSV следующим образом:

def write_output(data, output_csv):
   print("[+] Writing csv report")
   with open(output_csv, "wb") as outfile:
      writer = csv.writer(outfile)
      writer.writerow([
         "File Name", "Prefetch Name", "File Size (bytes)",
         "File Create Date (UTC)", "File Modify Date (UTC)",
         "Prefetch Last Execution Date (UTC)",
         "Prefetch Execution Count", "Volume", "Volume Create Date",
         "Volume Serial", "File Path" ])
      writer.writerows(data)

После запуска приведенного выше сценария мы получим информацию из файлов предварительной загрузки версии для Windows XP в электронную таблицу.

Важные артефакты в Windows-III

В этой главе будут объяснены дальнейшие артефакты, которые исследователь может получить во время криминалистического анализа в Windows.

Журналы событий

Файлы журнала событий Windows, как name -suggests, представляют собой специальные файлы, в которых хранятся важные события, например, когда пользователь регистрируется на компьютере, когда программа сталкивается с ошибкой, об изменениях в системе, доступе RDP, событиях, связанных с конкретным приложением, и т. Д. Кибер-исследователи всегда заинтересованы в событии информация журнала, потому что она предоставляет много полезной исторической информации о доступе системы. В следующем скрипте Python мы собираемся обработать как устаревшие, так и текущие форматы журнала событий Windows.

Для скрипта Python нам нужно установить сторонние модули, а именно pytsk3, pyewf, unicodecsv, pyevt и pyevt x. Мы можем следовать приведенным ниже инструкциям для извлечения информации из журналов событий.

  • Сначала найдите все журналы событий, которые соответствуют входному аргументу.

  • Затем выполните проверку подписи файла.

  • Теперь обработайте каждый найденный журнал событий соответствующей библиотекой.

  • Наконец, запишите результат в электронную таблицу.

Сначала найдите все журналы событий, которые соответствуют входному аргументу.

Затем выполните проверку подписи файла.

Теперь обработайте каждый найденный журнал событий соответствующей библиотекой.

Наконец, запишите результат в электронную таблицу.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие библиотеки Python —

from __future__ import print_function
import argparse
import unicodecsv as csv
import os
import pytsk3
import pyewf
import pyevt
import pyevtx
import sys
from utility.pytskutil import TSKUtil

Теперь предоставьте аргументы для обработчика командной строки. Обратите внимание, что здесь он будет принимать три аргумента: первый — это путь к файлу улик, второй — тип файла улик, а третий — имя журнала событий для обработки.

if __name__ == "__main__":
   parser = argparse.ArgumentParser('Information from Event Logs')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
   parser.add_argument(
      "LOG_NAME",help = "Event Log Name (SecEvent.Evt, SysEvent.Evt, ""etc.)")
   
   parser.add_argument(
      "-d", help = "Event log directory to scan",default = "/WINDOWS/SYSTEM32/WINEVT")
   
   parser.add_argument(
      "-f", help = "Enable fuzzy search for either evt or"" evtx extension", action = "store_true")
   args = parser.parse_args()
   
   if os.path.exists(args.EVIDENCE_FILE) and \ os.path.isfile(args.EVIDENCE_FILE):
      main(args.EVIDENCE_FILE, args.TYPE, args.LOG_NAME, args.d, args.f)
   else:
      print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
   sys.exit(1)

Теперь взаимодействуйте с журналами событий, чтобы запросить наличие указанного пользователем пути, создав наш объект TSKUtil . Это можно сделать с помощью метода main () следующим образом:

def main(evidence, image_type, log, win_event, fuzzy):
   tsk_util = TSKUtil(evidence, image_type)
   event_dir = tsk_util.query_directory(win_event)
   
   if event_dir is not None:
      if fuzzy is True:
         event_log = tsk_util.recurse_files(log, path=win_event)
   else:
      event_log = tsk_util.recurse_files(log, path=win_event, logic="equal")
   
   if event_log is not None:
      event_data = []
      for hit in event_log:
         event_file = hit[2]
         temp_evt = write_file(event_file)

Теперь нам нужно выполнить проверку подписи с последующим определением метода, который будет записывать весь контент в текущий каталог —

def write_file(event_file):
   with open(event_file.info.name.name, "w") as outfile:
      outfile.write(event_file.read_random(0, event_file.info.meta.size))
   return event_file.info.name.name
      if pyevt.check_file_signature(temp_evt):
         evt_log = pyevt.open(temp_evt)
         print("[+] Identified {} records in {}".format(
            evt_log.number_of_records, temp_evt))
         
         for i, record in enumerate(evt_log.records):
            strings = ""
            for s in record.strings:
               if s is not None:
                  strings += s + "\n"
            event_data.append([
               i, hit[0], record.computer_name,
               record.user_security_identifier,
               record.creation_time, record.written_time,
               record.event_category, record.source_name,
               record.event_identifier, record.event_type,
               strings, "",
               os.path.join(win_event, hit[1].lstrip("//"))
            ])
      elif pyevtx.check_file_signature(temp_evt):
         evtx_log = pyevtx.open(temp_evt)
         print("[+] Identified {} records in {}".format(
            evtx_log.number_of_records, temp_evt))
         for i, record in enumerate(evtx_log.records):
            strings = ""
            for s in record.strings:
			   if s is not None:
               strings += s + "\n"
         event_data.append([
            i, hit[0], record.computer_name,
            record.user_security_identifier, "",
            record.written_time, record.event_level,
            record.source_name, record.event_identifier,
            "", strings, record.xml_string,
            os.path.join(win_event, hit[1].lstrip("//"))
      ])
      else:
         print("[-] {} not a valid event log. Removing temp" file...".format(temp_evt))
         os.remove(temp_evt)
      continue
      write_output(event_data)
   else:
      print("[-] {} Event log not found in {} directory".format(log, win_event))
      sys.exit(3)
else:
   print("[-] Win XP Event Log Directory {} not found".format(win_event))
   sys.exit(2

Наконец, определите метод записи вывода в электронную таблицу следующим образом:

def write_output(data):
   output_name = "parsed_event_logs.csv"
   print("[+] Writing {} to current working directory: {}".format(
      output_name, os.getcwd()))
   
   with open(output_name, "wb") as outfile:
      writer = csv.writer(outfile)
      writer.writerow([
         "Index", "File name", "Computer Name", "SID",
         "Event Create Date", "Event Written Date",
         "Event Category/Level", "Event Source", "Event ID",
         "Event Type", "Data", "XML Data", "File Path"
      ])
      writer.writerows(data)

После успешного запуска вышеуказанного сценария мы получим информацию о журнале событий в электронной таблице.

Интернет история

История интернета очень полезна для судебных аналитиков; как большинство киберпреступлений происходит только через Интернет. Давайте посмотрим, как извлечь историю Интернета из Internet Explorer, когда мы обсуждаем криминалистику Windows, и Internet Explorer по умолчанию поставляется с Windows.

В Internet Explorer история интернета сохраняется в файле index.dat . Давайте посмотрим на скрипт Python, который будет извлекать информацию из файла index.dat .

Мы можем следовать приведенным ниже инструкциям для извлечения информации из файлов index.dat

  • Сначала выполните поиск файлов index.dat в системе.

  • Затем извлеките информацию из этого файла, просматривая их.

  • Теперь запишите всю эту информацию в отчет CSV.

Сначала выполните поиск файлов index.dat в системе.

Затем извлеките информацию из этого файла, просматривая их.

Теперь запишите всю эту информацию в отчет CSV.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие библиотеки Python —

from __future__ import print_function
import argparse

from datetime import datetime, timedelta
import os
import pytsk3
import pyewf
import pymsiecf
import sys
import unicodecsv as csv

from utility.pytskutil import TSKUtil

Теперь предоставьте аргументы для обработчика командной строки. Обратите внимание, что здесь он будет принимать два аргумента — первый будет путь к файлу доказательств, а второй будет тип файла доказательств —

if __name__ == "__main__":
parser = argparse.ArgumentParser('getting information from internet history')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("TYPE", help = "Type of Evidence",choices = ("raw", "ewf"))
   parser.add_argument("-d", help = "Index.dat directory to scan",default = "/USERS")
   args = parser.parse_args()
   
   if os.path.exists(args.EVIDENCE_FILE) and os.path.isfile(args.EVIDENCE_FILE):
      main(args.EVIDENCE_FILE, args.TYPE, args.d)
   else:
      print("[-] Supplied input file {} does not exist or is not a ""file".format(args.EVIDENCE_FILE))
      sys.exit(1)

Теперь интерпретируйте файл улик, создав объект TSKUtil, и переберите файловую систему, чтобы найти файлы index.dat. Это можно сделать, определив функцию main () следующим образом:

def main(evidence, image_type, path):
   tsk_util = TSKUtil(evidence, image_type)
   index_dir = tsk_util.query_directory(path)
   
   if index_dir is not None:
      index_files = tsk_util.recurse_files("index.dat", path = path,logic = "equal")
      
      if index_files is not None:
         print("[+] Identified {} potential index.dat files".format(len(index_files)))
         index_data = []
         
         for hit in index_files:
            index_file = hit[2]
            temp_index = write_file(index_file)

Теперь определим функцию, с помощью которой мы можем скопировать информацию из файла index.dat в текущий рабочий каталог, а затем они могут быть обработаны сторонним модулем —

def write_file(index_file):
   with open(index_file.info.name.name, "w") as outfile:
   outfile.write(index_file.read_random(0, index_file.info.meta.size))
return index_file.info.name.name

Теперь используйте следующий код для проверки подписи с помощью встроенной функции, а именно check_file_signature ()

if pymsiecf.check_file_signature(temp_index):
   index_dat = pymsiecf.open(temp_index)
   print("[+] Identified {} records in {}".format(
   index_dat.number_of_items, temp_index))

   for i, record in enumerate(index_dat.items):
   try:
      data = record.data
   if data is not None:
      data = data.rstrip("\x00")
   except AttributeError:
   
   if isinstance(record, pymsiecf.redirected):
      index_data.append([
         i, temp_index, "", "", "", "", "",record.location, "", "", record.offset,os.path.join(path, hit[1].lstrip("//"))])
   
   elif isinstance(record, pymsiecf.leak):
      index_data.append([
         i, temp_index, record.filename, "","", "", "", "", "", "", record.offset,os.path.join(path, hit[1].lstrip("//"))])
   continue
   
   index_data.append([
      i, temp_index, record.filename,
      record.type, record.primary_time,
      record.secondary_time,
      record.last_checked_time, record.location,
      record.number_of_hits, data, record.offset,
      os.path.join(path, hit[1].lstrip("//"))
   ])
   else:
      print("[-] {} not a valid index.dat file. Removing "
      "temp file..".format(temp_index))
      os.remove("index.dat")
      continue
      os.remove("index.dat")
      write_output(index_data)
   else:
      print("[-] Index.dat files not found in {} directory".format(path))
   sys.exit(3)
   else:
      print("[-] Directory {} not found".format(win_event))
   sys.exit(2)

Теперь определите метод, который будет печатать вывод в файле CSV, как показано ниже —

def write_output(data):
   output_name = "Internet_Indexdat_Summary_Report.csv"
   print("[+] Writing {} with {} parsed index.dat files to current "
   "working directory: {}".format(output_name, len(data),os.getcwd()))
   
   with open(output_name, "wb") as outfile:
      writer = csv.writer(outfile)
      writer.writerow(["Index", "File Name", "Record Name",
      "Record Type", "Primary Date", "Secondary Date",
      "Last Checked Date", "Location", "No. of Hits",
      "Record Data", "Record Offset", "File Path"])
      writer.writerows(data)

После запуска вышеуказанного скрипта мы получим информацию из файла index.dat в CSV-файле.

Объемные теневые копии

Теневая копия — это технология, включенная в Windows для создания резервных копий или снимков компьютерных файлов вручную или автоматически. Это также называется службой моментального снимка тома или службой теневого тома (VSS).

С помощью этих файлов VSS судебные эксперты могут получить некоторую историческую информацию о том, как система изменялась со временем и какие файлы существовали на компьютере. Технология теневого копирования требует, чтобы файловая система была NTFS для создания и хранения теневых копий.

В этом разделе мы рассмотрим скрипт Python, который помогает получить доступ к любому объему теневых копий, присутствующих в криминалистическом изображении.

Для скрипта Python нам нужно установить сторонние модули, а именно pytsk3, pyewf, unicodecsv, pyvshadow и vss . Мы можем следовать приведенным ниже инструкциям для извлечения информации из файлов VSS.

  • Сначала получите доступ к объему необработанного образа и определите все разделы NTFS.

  • Затем извлеките информацию из этих теневых копий, просматривая их.

  • Теперь, наконец, нам нужно создать список файлов данных в снимках.

Сначала получите доступ к объему необработанного образа и определите все разделы NTFS.

Затем извлеките информацию из этих теневых копий, просматривая их.

Теперь, наконец, нам нужно создать список файлов данных в снимках.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие библиотеки Python —

from __future__ import print_function
import argparse
from datetime import datetime, timedelta

import os
import pytsk3
import pyewf
import pyvshadow
import sys
import unicodecsv as csv

from utility import vss
from utility.pytskutil import TSKUtil
from utility import pytskutil

Теперь предоставьте аргументы для обработчика командной строки. Здесь он будет принимать два аргумента: первый — это путь к файлу улик, а второй — выходной файл.

if __name__ == "__main__":
   parser = argparse.ArgumentParser('Parsing Shadow Copies')
   parser.add_argument("EVIDENCE_FILE", help = "Evidence file path")
   parser.add_argument("OUTPUT_CSV", help = "Output CSV with VSS file listing")
   args = parser.parse_args()

Теперь проверьте правильность пути к входному файлу, а также отделите каталог от выходного файла.

directory = os.path.dirname(args.OUTPUT_CSV)
if not os.path.exists(directory) and directory != "":
   os.makedirs(directory)
if os.path.exists(args.EVIDENCE_FILE) and \ os.path.isfile(args.EVIDENCE_FILE):
   main(args.EVIDENCE_FILE, args.OUTPUT_CSV)
else:
   print("[-] Supplied input file {} does not exist or is not a "
   "file".format(args.EVIDENCE_FILE))
   
   sys.exit(1)

Теперь взаимодействуйте с томом файла улик, создав объект TSKUtil . Это можно сделать с помощью метода main () следующим образом:

def main(evidence, output):
   tsk_util = TSKUtil(evidence, "raw")
   img_vol = tsk_util.return_vol()

if img_vol is not None:
   for part in img_vol:
      if tsk_util.detect_ntfs(img_vol, part):
         print("Exploring NTFS Partition for VSS")
         explore_vss(evidence, part.start * img_vol.info.block_size,output)
      else:
         print("[-] Must be a physical preservation to be compatible ""with this script")
         sys.exit(2)

Теперь определите метод исследования файла теней анализируемого тома следующим образом:

def explore_vss(evidence, part_offset, output):
   vss_volume = pyvshadow.volume()
   vss_handle = vss.VShadowVolume(evidence, part_offset)
   vss_count = vss.GetVssStoreCount(evidence, part_offset)
   
   if vss_count > 0:
      vss_volume.open_file_object(vss_handle)
      vss_data = []
      
      for x in range(vss_count):
         print("Gathering data for VSC {} of {}".format(x, vss_count))
         vss_store = vss_volume.get_store(x)
         image = vss.VShadowImgInfo(vss_store)
         vss_data.append(pytskutil.openVSSFS(image, x))
write_csv(vss_data, output)

Наконец, определите метод записи результата в электронную таблицу следующим образом:

def write_csv(data, output):
   if data == []:
      print("[-] No output results to write")
      sys.exit(3)
   print("[+] Writing output to {}".format(output))
   if os.path.exists(output):
      append = True
with open(output, "ab") as csvfile:
      csv_writer = csv.writer(csvfile)
      headers = ["VSS", "File", "File Ext", "File Type", "Create Date",
         "Modify Date", "Change Date", "Size", "File Path"]
      if not append:
         csv_writer.writerow(headers)
      for result_list in data:
         csv_writer.writerows(result_list)

Как только вы успешно запустите этот скрипт на Python, мы получим информацию, хранящуюся в VSS, в электронную таблицу.

Исследование логарифмических артефактов

До сих пор мы видели, как получить артефакты в Windows, используя Python. В этой главе мы узнаем об исследовании артефактов на основе журналов с использованием Python.

Вступление

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

Различные основанные на логе артефакты и исследования в Python

В этом разделе давайте обсудим различные артефакты на основе журналов и их исследование в Python —

Timestamps

Временная метка передает данные и время активности в журнале. Это один из важных элементов любого файла журнала. Обратите внимание, что эти данные и значения времени могут быть в разных форматах.

Сценарий Python, показанный ниже, примет необработанную дату и время в качестве входных данных и предоставит отформатированную метку времени в качестве выходных данных.

Для этого скрипта нам нужно выполнить следующие шаги —

  • Сначала настройте аргументы, которые будут принимать значение необработанных данных вместе с источником данных и типом данных.

  • Теперь предоставьте класс для предоставления общего интерфейса для данных в разных форматах даты.

Сначала настройте аргументы, которые будут принимать значение необработанных данных вместе с источником данных и типом данных.

Теперь предоставьте класс для предоставления общего интерфейса для данных в разных форматах даты.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Сначала импортируйте следующие модули Python —

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

Теперь, как обычно, нам нужно предоставить аргумент для обработчика командной строки. Здесь он будет принимать три аргумента: первый будет значением даты для обработки, второй будет источником этого значения даты, а третий будет его типом —

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)

Теперь нам нужно определить класс, который будет принимать аргументы для значения даты, источника даты и типа значения —

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

Теперь мы определим метод, который будет действовать как контроллер точно так же, как метод 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']

Теперь нам нужно определить два метода, которые будут обрабатывать время эпохи Unix и 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')

После запуска вышеуказанного скрипта, предоставив метку времени, мы можем получить преобразованное значение в удобном для чтения формате.

Логи веб-сервера

С точки зрения эксперта по цифровым данным, журналы веб-сервера являются еще одним важным артефактом, поскольку они могут получать полезную статистику пользователя, а также информацию о пользователе и географическом местоположении. Ниже приведен сценарий Python, который после обработки логов веб-сервера создаст электронную таблицу для простого анализа информации.

Прежде всего нам нужно импортировать следующие модули Python —

from __future__ import print_function
from argparse import ArgumentParser, FileType

import re
import shlex
import logging
import sys
import csv

logger = logging.getLogger(__file__)

Теперь нам нужно определить шаблоны, которые будут анализироваться из журналов —

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

Теперь предоставьте аргумент для обработчика командной строки. Здесь он будет принимать два аргумента: первый — это обрабатываемый журнал IIS, второй — требуемый путь к CSV-файлу.

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

Теперь нам нужно определить метод main (), который будет обрабатывать скрипт для массовой информации журнала —

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

Наконец, нам нужно определить метод, который будет записывать вывод в электронную таблицу —

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)

После запуска вышеуказанного сценария мы получим журналы на основе веб-сервера в электронной таблице.

Сканирование важных файлов с использованием YARA

YARA (еще один рекурсивный алгоритм) — это утилита сопоставления с образцом, предназначенная для идентификации вредоносных программ и реагирования на инциденты. Мы будем использовать YARA для сканирования файлов. В следующем скрипте Python мы будем использовать YARA.

Мы можем установить YARA с помощью следующей команды —

pip install YARA

Мы можем следовать приведенным ниже инструкциям для использования правил YARA для сканирования файлов —

  • Сначала настройте и скомпилируйте правила YARA

  • Затем отсканируйте один файл, а затем выполните итерацию по каталогам для обработки отдельных файлов.

  • Наконец, мы экспортируем результат в CSV.

Сначала настройте и скомпилируйте правила YARA

Затем отсканируйте один файл, а затем выполните итерацию по каталогам для обработки отдельных файлов.

Наконец, мы экспортируем результат в CSV.

Код Python

Давайте посмотрим, как использовать код Python для этой цели —

Во-первых, нам нужно импортировать следующие модули Python —

from __future__ import print_function
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter

import os
import csv
import yara

Далее укажите аргумент для обработчика командной строки. Обратите внимание, что здесь он будет принимать два аргумента: первый — это путь к правилам YARA, второй — файл, который нужно сканировать.

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)

Теперь мы определим функцию main (), которая будет принимать путь к правилам yara и проверяемому файлу —

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)

Теперь определите метод, который будет выполнять итерацию по каталогу и передавать результат другому методу для дальнейшей обработки —

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

Затем определите две функции. Обратите внимание, что сначала мы будем использовать метод match () для объекта yrules, а другой сообщит, что информация о совпадении выводится на консоль, если пользователь не указал какой-либо выходной файл. Соблюдайте код, показанный ниже —

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)

Наконец, мы определим метод, который будет записывать вывод в файл CSV, как показано ниже —

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)

После успешного запуска вышеуказанного сценария мы можем предоставить соответствующие аргументы в командной строке и сгенерировать отчет CSV.