Цифровая криминалистика Python - Краткое руководство
В этой главе вы познакомитесь с тем, что такое цифровая криминалистика, а также с ее историческим обзором. Вы также поймете, где можно применить цифровую криминалистику в реальной жизни и ее ограничения.
Что такое цифровая криминалистика?
Цифровую судебную экспертизу можно определить как отрасль судебной медицины, которая анализирует, исследует, идентифицирует и восстанавливает цифровые доказательства, хранящиеся на электронных устройствах. Он обычно используется для уголовного права и частных расследований.
Например, вы можете полагаться на цифровую судебную экспертизу для извлечения улик в случае, если кто-то украдет некоторые данные на электронном устройстве.
Краткий исторический обзор цифровой криминалистики
История компьютерных преступлений и исторический обзор цифровой криминалистики объясняются в этом разделе, как указано ниже -
1970-1980-е годы: первое компьютерное преступление
До этого десятилетия компьютерные преступления не признавались. Однако, если это должно было произойти, тогда существующие законы имели дело с ними. Позже, в 1978 году, первое компьютерное преступление было признано в Законе о компьютерных преступлениях Флориды, который включал законодательство против несанкционированного изменения или удаления данных в компьютерной системе. Но со временем, в связи с развитием технологий, количество совершаемых компьютерных преступлений также увеличилось. Для того, чтобы иметь дело с преступлениями, связанных с авторским правом, неприкосновенностью частной жизни и детской порнографией, были приняты различные другие законы.
1980-1990-е годы: десятилетие развития
Это десятилетие стало десятилетием развития цифровой криминалистики, все из-за первого в истории расследования (1986 г.), в ходе которого Клифф Столл выследил хакера по имени Маркус Хесс. В течение этого периода были разработаны два вида дисциплин цифровой криминалистики: первый был с помощью специальных инструментов и методов, разработанных практиками, которые восприняли это как хобби, а второй - научным сообществом. В 1992 г. срок“Computer Forensics”был использован в академической литературе.
2000–2010 годы: Десятилетие стандартизации
После того, как цифровая криминалистика достигла определенного уровня, возникла необходимость в разработке определенных стандартов, которым можно было бы следовать при проведении расследований. Соответственно, различные научные агентства и организации опубликовали руководства по цифровой криминалистике. В 2002 году Научная рабочая группа по цифровым доказательствам (SWGDE) опубликовала документ под названием «Лучшие практики компьютерной криминалистики». Еще одним пером в шапке был международный договор под руководством Европы, а именно:“The Convention on Cybercrime”был подписан 43 странами и ратифицирован 16 странами. Даже после таких стандартов все еще существует необходимость решить некоторые проблемы, которые были выявлены исследователями.
Процесс цифровой криминалистики
С момента первого в истории компьютерного преступления в 1978 году количество цифровых преступлений значительно увеличилось. Из-за этого приращения существует потребность в структурированном подходе к ним. В 1984 году был введен формализованный процесс, после чего было разработано множество новых и улучшенных процессов компьютерной криминалистики.
Процесс расследования компьютерной криминалистики включает три основных этапа, как описано ниже:
Этап 1: Приобретение или визуализация экспонатов
Первый этап цифровой криминалистики включает сохранение состояния цифровой системы, чтобы его можно было проанализировать позже. Это очень похоже на фотографирование, взятие образцов крови и т. Д. С места преступления. Например, он включает в себя захват изображения выделенных и нераспределенных областей жесткого диска или оперативной памяти.
Этап 2: Анализ
Входом этого этапа являются данные, полученные на этапе сбора данных. Здесь эти данные были изучены для выявления улик. Эта фаза дает следующие три вида свидетельств:
Inculpatory evidences - Эти свидетельства подтверждают данную историю.
Exculpatory evidences - Эти свидетельства противоречат заданной истории.
Evidence of tampering- Эти свидетельства показывают, что система была настроена так, чтобы избежать идентификации. Он включает в себя проверку файлов и содержимого каталогов для восстановления удаленных файлов.
Этап 3: презентация или отчет
Как следует из названия, на этом этапе представлены выводы и соответствующие доказательства расследования.
Приложения цифровой криминалистики
Цифровая криминалистика занимается сбором, анализом и сохранением доказательств, содержащихся в любом цифровом устройстве. Использование цифровой криминалистики зависит от приложения. Как упоминалось ранее, он используется в основном в следующих двух приложениях:
Уголовное право
В уголовном праве доказательства собираются для подтверждения или опровержения гипотезы в суде. Процедуры судебной экспертизы очень похожи на те, что используются в уголовных расследованиях, но с другими юридическими требованиями и ограничениями.
Частное расследование
В основном корпоративный мир использует цифровую криминалистику для частных расследований. Он используется, когда компании подозревают, что сотрудники могут выполнять на своих компьютерах незаконную деятельность, которая противоречит политике компании. Цифровая криминалистика - это один из лучших способов для компании или человека при расследовании неправомерных действий в цифровой среде.
Отрасли цифровой криминалистики
Цифровые преступления не ограничиваются только компьютерами, однако хакеры и преступники также используют небольшие цифровые устройства, такие как планшеты, смартфоны и т. Д., В очень больших масштабах. Некоторые устройства имеют энергозависимую память, а другие - энергонезависимую. Следовательно, в зависимости от типа устройств цифровая криминалистика имеет следующие ветви:
Компьютерная криминалистика
Эта ветвь цифровой криминалистики занимается компьютерами, встроенными системами и статической памятью, например USB-накопителями. С помощью компьютерной криминалистики можно исследовать широкий спектр информации, от журналов до реальных файлов на диске.
Мобильная криминалистика
Это касается исследования данных с мобильных устройств. Эта ветвь отличается от компьютерной криминалистики в том смысле, что мобильные устройства имеют встроенную систему связи, которая полезна для предоставления полезной информации, связанной с местоположением.
Сетевая криминалистика
Это касается мониторинга и анализа трафика компьютерной сети, как локальной, так и WAN (глобальной сети), с целью сбора информации, сбора доказательств или обнаружения вторжений.
Криминалистика баз данных
Этот раздел цифровой криминалистики занимается криминалистическим исследованием баз данных и их метаданных.
Навыки, необходимые для расследования в области цифровой криминалистики
Эксперты в области цифровой криминалистики помогают отслеживать хакеров, восстанавливать украденные данные, отслеживать компьютерные атаки до их источника и помогают в других типах расследований с участием компьютеров. Некоторые из ключевых навыков, необходимых для того, чтобы стать экспертом в области цифровой криминалистики, как описано ниже:
Выдающиеся мыслительные способности
Исследователь цифровой криминалистики должен быть выдающимся мыслителем и должен уметь применять различные инструменты и методологии для выполнения конкретного задания для получения результатов. Он / она должен уметь находить различные закономерности и проводить корреляции между ними.
Технические навыки
Эксперт в области цифровой криминалистики должен обладать хорошими технологическими навыками, потому что в этой области требуется знание сети и взаимодействия цифровых систем.
Увлечен кибербезопасностью
Поскольку сфера цифровой криминалистики - это раскрытие киберпреступлений, а это утомительная задача, для того, чтобы стать первоклассным следователем в области цифровой криминалистики, нужно много страсти.
Навыки коммуникации
Хорошие коммуникативные навыки необходимы для координации с различными командами и для извлечения любых недостающих данных или информации.
Умелое составление отчетов
После успешного выполнения сбора и анализа цифровой судебно-медицинский эксперт должен указать все выводы в окончательном отчете и презентации. Следовательно, он / она должны обладать хорошими навыками составления отчетов и вниманием к деталям.
Ограничения
Цифровая криминалистическая экспертиза предлагает определенные ограничения, обсуждаемые здесь:
Необходимо предоставить убедительные доказательства
Одним из основных недостатков расследования в области цифровой криминалистики является то, что эксперт должен соблюдать стандарты, необходимые для представления доказательств в суде, поскольку данные могут быть легко подделаны. С другой стороны, компьютерный судебно-медицинский эксперт должен иметь полное представление о юридических требованиях, процедурах обработки доказательств и документирования, чтобы представить убедительные доказательства в суде.
Инструменты расследования
Эффективность цифрового расследования полностью зависит от опыта эксперта по цифровой криминалистике и выбора подходящего инструмента расследования. Если использованный инструмент не соответствует установленным стандартам, то в суде доказательства могут быть отклонены судьей.
Отсутствие технических знаний у аудитории
Еще одно ограничение состоит в том, что некоторые люди не совсем знакомы с компьютерной криминалистикой; поэтому многие люди не разбираются в этой области. Следователи должны обязательно сообщить свои выводы в суды таким образом, чтобы помочь всем понять результаты.
Стоимость
Создание цифровых доказательств и их сохранение очень дорого обходятся. Следовательно, этот процесс не может быть выбран многими людьми, которые не могут позволить себе затраты.
В предыдущей главе мы узнали основы цифровой криминалистики, ее преимущества и ограничения. Эта глава познакомит вас с Python - важным инструментом, который мы используем в этом исследовании цифровой криминалистики.
Почему Python для цифровой криминалистики?
Python - популярный язык программирования, который используется в качестве инструмента для кибербезопасности, тестирования на проникновение, а также для проведения цифровых криминалистических исследований. Когда вы выбираете Python в качестве инструмента для цифровой криминалистики, вам не нужно какое-либо стороннее программное обеспечение для выполнения этой задачи.
Некоторые из уникальных особенностей языка программирования Python, которые делают его подходящим для проектов цифровой криминалистики, приведены ниже.
Simplicity of Syntax - Синтаксис Python прост по сравнению с другими языками, что упрощает его изучение и применение для цифровой криминалистики.
Comprehensive inbuilt modules - Обширные встроенные модули Python являются отличным помощником для проведения полного цифрового судебного расследования.
Help and Support - Будучи языком программирования с открытым исходным кодом, Python пользуется отличной поддержкой сообщества разработчиков и пользователей.
Особенности Python
Python, будучи высокоуровневым, интерпретируемым, интерактивным и объектно-ориентированным языком сценариев, предоставляет следующие функции:
Easy to Learn - Python - дружественный к разработчикам и простой в изучении язык, поскольку в нем меньше ключевых слов и простейшая структура.
Expressive and Easy to read- язык Python выразителен по своей природе; следовательно, его код более понятен и читаем.
Cross-platform Compatible - Python - это кроссплатформенный язык, что означает, что он может эффективно работать на различных платформах, таких как UNIX, Windows и Macintosh.
Interactive Mode Programming - Мы можем проводить интерактивное тестирование и отладку кода, потому что Python поддерживает интерактивный режим программирования.
Provides Various Modules and Functions - Python имеет большую стандартную библиотеку, которая позволяет нам использовать богатый набор модулей и функций для нашего скрипта.
Supports Dynamic Type Checking - Python поддерживает динамическую проверку типов и предоставляет динамические типы данных очень высокого уровня.
GUI Programming - Python поддерживает программирование GUI для разработки графических пользовательских интерфейсов.
Integration with other programming languages - Python можно легко интегрировать с другими языками программирования, такими как C, C ++, JAVA и т. Д.
Установка Python
Дистрибутив Python доступен для различных платформ, таких как Windows, UNIX, Linux и Mac. Нам нужно только загрузить двоичный код в соответствии с нашей платформой. В случае, если двоичный код для какой-либо платформы недоступен, у нас должен быть компилятор C, чтобы исходный код можно было скомпилировать вручную.
Этот раздел познакомит вас с установкой Python на различных платформах -
Установка Python в Unix и Linux
Вы можете выполнить шаги, показанные ниже, чтобы установить Python на машину Unix / Linux.
Step 1- Откройте веб-браузер. Введите и введите www.python.org/downloads/
Step 2 - Загрузите заархивированный исходный код, доступный для Unix / Linux.
Step 3 - Извлеките загруженные заархивированные файлы.
Step 4 - Если вы хотите настроить некоторые параметры, вы можете отредактировать Modules/Setup file.
Step 5 - Используйте следующие команды для завершения установки -
run ./configure script
make
make install
После того, как вы успешно выполните шаги, указанные выше, Python будет установлен в стандартном месте. /usr/local/bin и его библиотеки в /usr/local/lib/pythonXX где XX - версия Python.
Установка Python в Windows
Мы можем выполнить следующие простые шаги, чтобы установить Python на машину Windows.
Step 1- Откройте веб-браузер. Введите и введите www.python.org/downloads/
Step 2 - Загрузите установщик Windows python-XYZ.msi файл, где XYZ - это версия, которую нам нужно установить.
Step 3 - Теперь запустите этот файл MSI после сохранения файла установщика на локальном компьютере.
Step 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 - Тип setenv PATH "$PATH:/usr/local/bin/python" а затем нажмите Enter.
If using bash shell (Linux) - Тип export ATH="$PATH:/usr/local/bin/python" а затем нажмите Enter.
If using sh or ksh shell - Тип PATH="$PATH:/usr/local/bin/python" а затем нажмите Enter.
Настройка пути в Windows
Тип path %path%;C:\Python в командной строке и нажмите Enter.
Запуск Python
Вы можете выбрать любой из следующих трех методов для запуска интерпретатора Python:
Метод 1: Использование интерактивного переводчика
Для запуска Python можно легко использовать систему, которая предоставляет интерпретатор командной строки или оболочку. Например, Unix, DOS и т. Д. Вы можете выполнить шаги, указанные ниже, чтобы начать кодирование в интерактивном интерпретаторе -
Step 1 - Войти python в командной строке.
Step 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 вместе с графическим интерфейсом.
Macintosh IDE - Macintosh имеет IDLE IDE, которая доступна с основного веб-сайта и может быть загружена в виде файлов MacBinary или BinHex'd.
Теперь, когда вы освоились с установкой и запуском команд Python в локальной системе, давайте подробно рассмотрим концепции судебной экспертизы. В этой главе будут объяснены различные концепции работы с артефактами в цифровой криминалистике Python.
Необходимость создания отчета
Процесс цифровой криминалистики включает в себя отчетность в качестве третьей фазы. Это одна из самых важных частей процесса цифровой криминалистики. Создание отчета необходимо по следующим причинам -
Это документ, в котором цифровой судебно-медицинский эксперт описывает процесс расследования и его выводы.
Другой эксперт может сослаться на хороший цифровой криминалистический отчет для достижения того же результата в тех же репозиториях.
Это технический и научный документ, содержащий факты, обнаруженные в цифровых доказательствах с точностью до единиц.
Общие рекомендации по созданию отчетов
Отчеты написаны для предоставления информации читателю и должны начинаться с прочного основания. Исследователи могут столкнуться с трудностями при эффективном представлении своих выводов, если отчет подготовлен без каких-либо общих руководящих принципов или стандартов. Некоторые общие рекомендации, которые необходимо соблюдать при создании цифровых криминалистических отчетов, приведены ниже.
Summary - Отчет должен содержать краткое изложение информации, чтобы читатель мог понять цель отчета.
Tools used - Мы должны упомянуть инструменты, которые использовались для проведения процесса цифровой криминалистики, в том числе их назначение.
Repository - Предположим, мы исследовали чей-то компьютер, затем составили сводку доказательств и анализ соответствующих материалов, таких как электронная почта, внутренняя история поиска и т. Д., А затем они должны быть включены в отчет, чтобы можно было ясно представить дело.
Recommendations for counsel - В отчете должны быть рекомендации для адвоката продолжить или прекратить расследование на основании результатов, содержащихся в отчете.
Создание отчетов разного типа
В приведенном выше разделе мы узнали о важности отчета в цифровой криминалистике вместе с рекомендациями по его созданию. Некоторые из форматов в 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» и устанавливаем в качестве аргумента ключевого слова новой строки пустую строку.
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 | Бхопал | Менеджер |
Раман | 42 | Индор | Engg |
Мохан | 25 | Чандигарх | HR |
Паркаш | 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 | Бхопал |
Мохан | 25 | Чандигарх |
Паркаш | 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 на мобильных устройствах и связанных с ней концепциях.
Введение
Судебная экспертиза мобильных устройств - это отрасль цифровой криминалистики, которая занимается сбором и анализом мобильных устройств для получения цифровых доказательств, представляющих интерес для расследования. Эта ветвь отличается от компьютерной криминалистики, потому что мобильные устройства имеют встроенную систему связи, которая полезна для предоставления полезной информации, связанной с местоположением.
Хотя использование смартфонов в цифровой криминалистике растет день ото дня, оно все же считается нестандартным из-за своей неоднородности. С другой стороны, компьютерное оборудование, такое как жесткий диск, считается стандартом и развивается как стабильная дисциплина. В индустрии цифровой криминалистики ведется много споров о методах, используемых для нестандартных устройств, имеющих временные доказательства, такие как смартфоны.
Артефакты, извлекаемые с мобильных устройств
Современные мобильные устройства обладают большим количеством цифровой информации по сравнению со старыми телефонами, имеющими только журнал вызовов или SMS-сообщения. Таким образом, мобильные устройства могут предоставить следователям много информации о пользователе. Некоторые артефакты, которые можно извлечь с мобильных устройств, упомянуты ниже -
Messages - Это полезные артефакты, которые могут выявить душевное состояние владельца и даже дать следователю некоторую ранее неизвестную информацию.
Location History- Данные истории местоположений - это полезный артефакт, который могут использоваться следователями для проверки конкретного местоположения человека.
Applications Installed - Получая доступ к типу установленных приложений, исследователь может получить некоторое представление о привычках и мышлении мобильного пользователя.
Источники доказательств и обработка в Python
Смартфоны имеют базы данных SQLite и файлы PLIST в качестве основных источников доказательств. В этом разделе мы собираемся обработать источники доказательств на Python.
Анализ файлов PLIST
PLIST (список свойств) - это гибкий и удобный формат для хранения данных приложений, особенно на устройствах iPhone. Он использует расширение.plist. Такие файлы используются для хранения информации о пакетах и приложениях. Может быть в двух форматах:XML и binary. Следующий код Python откроется и прочитает файл PLIST. Обратите внимание, что прежде чем приступить к этому, мы должны создать свой собственныйInfo.plist файл.
Сначала установите стороннюю библиотеку с именем biplist следующей командой -
Pip install biplist
Теперь импортируйте несколько полезных библиотек для обработки файлов plist -
import biplist
import os
import sys
Теперь используйте следующую команду в разделе основного метода, который можно использовать для чтения файла 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 файл мобильного устройства и может извлекать ценную информацию из messageстол. Python имеет встроенную библиотеку с именемsqlite3для подключения к базе данных SQLite. Вы можете импортировать то же самое с помощью следующей команды -
import sqlite3
Теперь с помощью следующей команды мы можем подключиться к базе данных, скажем sms.db в случае мобильных устройств -
Conn = sqlite3.connect(‘sms.db’)
C = conn.cursor()
Здесь C - объект курсора, с помощью которого мы можем взаимодействовать с базой данных.
Теперь предположим, что если мы хотим выполнить определенную команду, скажем, чтобы получить детали из abc table, это можно сделать с помощью следующей команды -
c.execute(“Select * from abc”)
c.close()
Результат вышеуказанной команды будет сохранен в cursorобъект. Точно так же мы можем использовать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) используется 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 / Backup / |
Для обработки резервной копии 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, которые доступны повсюду. Иногда устройство подключается к этим открытым сетям автоматически.
В случае 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 с именем requestsдля доступа к 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 и временную метку в словарь Wi-Fi следующим образом:
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
Теперь давайте воспользуемся модулем запросов, чтобы WIGLE APIзвонки и нужно перейти к 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, мы можем получить результирующие данные в формате, называемом Extensible Metadata Platform (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() метод для извлечения и печати соответствующих значений, таких как заголовок, создатель, участник и т. д., следующим образом:
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()
Теперь распечатайте exports, names и addresses используя код, как показано ниже -
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.
Метаданные документа Office
Большая часть работы на компьютере выполняется в трех приложениях 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.
Понимание сетевой криминалистики
Сетевая криминалистика - это отрасль цифровой криминалистики, которая занимается мониторингом и анализом трафика компьютерной сети, как локального, так и WAN (глобальная сеть), в целях сбора информации, сбора доказательств или обнаружения вторжений. Сетевая криминалистика играет решающую роль в расследовании цифровых преступлений, таких как кража интеллектуальной собственности или утечка информации. Картина сетевых коммуникаций помогает исследователю решить некоторые важные вопросы следующим образом:
Какие веб-сайты были посещены?
Какой контент был загружен в нашу сеть?
Какой контент был загружен из нашей сети?
К каким серверам осуществляется доступ?
Кто-то отправляет конфиденциальную информацию за пределы корпоративных брандмауэров?
Интернет-поиск улик (IEF)
IEF - это инструмент цифровой криминалистики для поиска, анализа и представления цифровых доказательств, обнаруженных на различных цифровых носителях, таких как компьютеры, смартфоны, планшеты и т. Д. Он очень популярен и используется тысячами специалистов-криминалистов.
Использование IEF
Из-за своей популярности IEF широко используется профессионалами-криминалистами. Некоторые из вариантов использования IEF следующие:
Благодаря мощным возможностям поиска он используется для одновременного поиска нескольких файлов или носителей данных.
Он также используется для восстановления удаленных данных из нераспределенного пространства ОЗУ с помощью новых методов вырезания.
Если исследователи хотят восстановить веб-страницы в их исходном формате на дату их открытия, они могут использовать IEF.
Он также используется для поиска в логических или физических дисковых томах.
Выгрузка отчетов из IEF в CSV с использованием Python
IEF хранит данные в базе данных SQLite, и следующий сценарий Python будет динамически определять таблицы результатов в базе данных IEF и выгружать их в соответствующие файлы 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. В этой главе давайте разберемся в сетевой криминалистике с использованием Python на более глубоком уровне.
Сохранение веб-страницы с помощью Beautiful Soup
Всемирная паутина (WWW) - это уникальный источник информации. Однако его наследие находится под высоким риском из-за угрожающей скорости потери контента. Ряд учреждений, занимающихся культурным наследием, академических учреждений, некоммерческих организаций и частных предприятий изучили затронутые проблемы и внесли свой вклад в разработку технических решений для веб-архивирования.
Сохранение веб-страниц или веб-архивирование - это процесс сбора данных из World Wide Web, гарантирующий, что данные хранятся в архиве и делают их доступными для будущих исследователей, историков и общественности. Прежде чем перейти к сохранению веб-страницы, давайте обсудим некоторые важные вопросы, связанные с сохранением веб-страницы, как указано ниже -
Change in Web Resources - Веб-ресурсы постоянно меняются, что является проблемой для сохранения веб-страниц.
Large Quantity of Resources - Еще одна проблема, связанная с сохранением веб-страниц, - это большое количество ресурсов, которые необходимо сохранить.
Integrity - Веб-страницы должны быть защищены от несанкционированного изменения, удаления или удаления для защиты своей целостности.
Dealing with multimedia data - При сохранении веб-страниц нам также необходимо иметь дело с мультимедийными данными, и при этом могут возникнуть проблемы.
Providing access - Помимо сохранения, необходимо решить вопрос обеспечения доступа к веб-ресурсам и решения вопросов собственности.
В этой главе мы собираемся использовать библиотеку Python с именем Beautiful Soup для сохранения веб-страницы.
Что такое красивый суп?
Beautiful Soup - это библиотека Python для извлечения данных из файлов HTML и XML. Его можно использовать сurlibпотому что ему нужен ввод (документ или URL-адрес) для создания объекта супа, поскольку он не может получить саму веб-страницу. Вы можете подробно узнать об этом на сайте www.crummy.com/software/BeautifulSoup/bs4/doc/.
Обратите внимание, что перед его использованием мы должны установить стороннюю библиотеку, используя следующую команду -
pip install bs4
Затем, используя менеджер пакетов Anaconda, мы можем установить Beautiful Soup следующим образом:
conda install -c anaconda beautifulsoup4
Скрипт Python для сохранения веб-страниц
Здесь обсуждается сценарий Python для сохранения веб-страниц с использованием сторонней библиотеки под названием Beautiful Soup -
Сначала импортируйте необходимые библиотеки следующим образом:
from __future__ import print_function
import argparse
from bs4 import BeautifulSoup, SoupStrainer
from datetime import datetime
import hashlib
import logging
import os
import ssl
import sys
from urllib.request import urlopen
import urllib.error
logger = logging.getLogger(__name__)
Обратите внимание, что этот сценарий будет принимать два позиционных аргумента, один - это URL-адрес, который необходимо сохранить, а другой - желаемый выходной каталог, как показано ниже -
if __name__ == "__main__":
parser = argparse.ArgumentParser('Web Page preservation')
parser.add_argument("DOMAIN", help="Website Domain")
parser.add_argument("OUTPUT_DIR", help="Preservation Output Directory")
parser.add_argument("-l", help="Log file path",
default=__file__[:-3] + ".log")
args = parser.parse_args()
Теперь настройте ведение журнала для сценария, указав обработчик файла и потока для нахождения в цикле и задокументируйте процесс получения, как показано -
logger.setLevel(logging.DEBUG)
msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-10s""%(levelname)-8s %(message)s")
strhndl = logging.StreamHandler(sys.stderr)
strhndl.setFormatter(fmt=msg_fmt)
fhndl = logging.FileHandler(args.l, mode='a')
fhndl.setFormatter(fmt=msg_fmt)
logger.addHandler(strhndl)
logger.addHandler(fhndl)
logger.info("Starting BS Preservation")
logger.debug("Supplied arguments: {}".format(sys.argv[1:]))
logger.debug("System " + sys.platform)
logger.debug("Version " + sys.version)
Теперь давайте выполним проверку ввода в желаемом выходном каталоге следующим образом:
if not os.path.exists(args.OUTPUT_DIR):
os.makedirs(args.OUTPUT_DIR)
main(args.DOMAIN, args.OUTPUT_DIR)
Теперь мы определим main() функция, которая извлечет базовое имя веб-сайта, удалив ненужные элементы перед фактическим именем вместе с дополнительной проверкой входного URL-адреса следующим образом:
def main(website, output_dir):
base_name = website.replace("https://", "").replace("http://", "").replace("www.", "")
link_queue = set()
if "http://" not in website and "https://" not in website:
logger.error("Exiting preservation - invalid user input: {}".format(website))
sys.exit(1)
logger.info("Accessing {} webpage".format(website))
context = ssl._create_unverified_context()
Теперь нам нужно открыть соединение с URL-адресом с помощью метода urlopen (). Давайте использовать блок try-except следующим образом -
try:
index = urlopen(website, context=context).read().decode("utf-8")
except urllib.error.HTTPError as e:
logger.error("Exiting preservation - unable to access page: {}".format(website))
sys.exit(2)
logger.debug("Successfully accessed {}".format(website))
Следующие строки кода включают три функции, как описано ниже:
write_output() записать первую веб-страницу в выходной каталог
find_links() функция для определения ссылок на этой веб-странице
recurse_pages() функция для перебора и обнаружения всех ссылок на веб-странице.
write_output(website, index, output_dir)
link_queue = find_links(base_name, index, link_queue)
logger.info("Found {} initial links on webpage".format(len(link_queue)))
recurse_pages(website, link_queue, context, output_dir)
logger.info("Completed preservation of {}".format(website))
Теперь определим write_output() метод следующим образом -
def write_output(name, data, output_dir, counter=0):
name = name.replace("http://", "").replace("https://", "").rstrip("//")
directory = os.path.join(output_dir, os.path.dirname(name))
if not os.path.exists(directory) and os.path.dirname(name) != "":
os.makedirs(directory)
Нам нужно записать некоторые сведения о веб-странице, а затем мы регистрируем хэш данных, используя hash_data() метод следующим образом -
logger.debug("Writing {} to {}".format(name, output_dir)) logger.debug("Data Hash: {}".format(hash_data(data)))
path = os.path.join(output_dir, name)
path = path + "_" + str(counter)
with open(path, "w") as outfile:
outfile.write(data)
logger.debug("Output File Hash: {}".format(hash_file(path)))
Теперь определим hash_data() метод, с помощью которого мы читаем UTF-8 закодированные данные, а затем сгенерировать SHA-256 хеш его следующим образом -
def hash_data(data):
sha256 = hashlib.sha256()
sha256.update(data.encode("utf-8"))
return sha256.hexdigest()
def hash_file(file):
sha256 = hashlib.sha256()
with open(file, "rb") as in_file:
sha256.update(in_file.read())
return sha256.hexdigest()
Теперь давайте создадим Beautifulsoup объект вне данных веб-страницы под find_links() метод следующим образом -
def find_links(website, page, queue):
for link in BeautifulSoup(page, "html.parser",parse_only = SoupStrainer("a", href = True)):
if website in link.get("href"):
if not os.path.basename(link.get("href")).startswith("#"):
queue.add(link.get("href"))
return queue
Теперь нам нужно определить recurse_pages() путем предоставления ему входных данных URL-адреса веб-сайта, текущей очереди ссылок, непроверенного контекста SSL и выходного каталога следующим образом:
def recurse_pages(website, queue, context, output_dir):
processed = []
counter = 0
while True:
counter += 1
if len(processed) == len(queue):
break
for link in queue.copy(): if link in processed:
continue
processed.append(link)
try:
page = urlopen(link, context=context).read().decode("utf-8")
except urllib.error.HTTPError as e:
msg = "Error accessing webpage: {}".format(link)
logger.error(msg)
continue
Теперь напишите вывод каждой веб-страницы, к которой осуществляется доступ, в файл, передав имя ссылки, данные страницы, каталог вывода и счетчик следующим образом:
write_output(link, page, output_dir, counter)
queue = find_links(website, page, queue)
logger.info("Identified {} links throughout website".format(
len(queue)))
Теперь, когда мы запускаем этот скрипт, предоставляя URL-адрес веб-сайта, выходной каталог и путь к файлу журнала, мы получим подробную информацию об этой веб-странице, которую можно будет использовать в будущем.
Охота на вирусы
Вы когда-нибудь задумывались, как судебные аналитики, исследователи в области безопасности и респонденты могут понять разницу между полезным программным обеспечением и вредоносным ПО? Ответ заключается в самом вопросе, потому что без изучения вредоносных программ, быстро создаваемых хакерами, исследователи и специалисты совершенно не могут отличить полезное ПО от вредоносного. В этом разделе давайте обсудимVirusShare, инструмент для выполнения этой задачи.
Понимание VirusShare
VirusShare - это крупнейшая частная коллекция образцов вредоносных программ, которая предоставляет исследователям безопасности, специалистам по реагированию на инциденты и судебным аналитикам образцы живого вредоносного кода. Он содержит более 30 миллионов образцов.
Преимущество VirusShare - это список хэшей вредоносных программ, который находится в свободном доступе. Кто угодно может использовать эти хэши для создания исчерпывающего набора хешей и использовать его для выявления потенциально вредоносных файлов. Но перед тем, как использовать VirusShare, предлагаем вам посетитьhttps://virusshare.com Больше подробностей.
Создание хеш-списка с разделителями на новой строке из VirusShare с использованием Python
Список хэшей от VirusShare может использоваться различными инструментами криминалистической экспертизы, такими как X-way и EnCase. В сценарии, обсуждаемом ниже, мы собираемся автоматизировать загрузку списков хэшей из VirusShare, чтобы создать список хэшей, разделенных новой строкой.
Для этого скрипта нам понадобится сторонняя библиотека Python. tqdm который можно скачать следующим образом -
pip install tqdm
Обратите внимание, что в этом сценарии сначала мы прочитаем страницу хешей VirusShare и динамически определим самый последний список хешей. Затем мы инициализируем индикатор выполнения и загрузим хеш-список в желаемом диапазоне.
Сначала импортируйте следующие библиотеки -
from __future__ import print_function
import argparse
import os
import ssl
import sys
import tqdm
from urllib.request import urlopen
import urllib.error
Этот скрипт примет один позиционный аргумент, который будет желаемым путем для хеш-набора -
if __name__ == '__main__':
parser = argparse.ArgumentParser('Hash set from VirusShare')
parser.add_argument("OUTPUT_HASH", help = "Output Hashset")
parser.add_argument("--start", type = int, help = "Optional starting location")
args = parser.parse_args()
Теперь мы выполним стандартную проверку ввода следующим образом:
directory = os.path.dirname(args.OUTPUT_HASH)
if not os.path.exists(directory):
os.makedirs(directory)
if args.start:
main(args.OUTPUT_HASH, start=args.start)
else:
main(args.OUTPUT_HASH)
Теперь нам нужно определить main() функционировать с **kwargs в качестве аргумента, потому что это создаст словарь, который мы можем ссылаться на поддержку предоставленных ключевых аргументов, как показано ниже -
def main(hashset, **kwargs):
url = "https://virusshare.com/hashes.4n6"
print("[+] Identifying hash set range from {}".format(url))
context = ssl._create_unverified_context()
Теперь нам нужно открыть страницу хэшей VirusShare, используя urlib.request.urlopen()метод. Мы будем использовать блок try-except следующим образом:
try:
index = urlopen(url, context = context).read().decode("utf-8")
except urllib.error.HTTPError as e:
print("[-] Error accessing webpage - exiting..")
sys.exit(1)
Теперь определите последний хеш-список из загруженных страниц. Вы можете сделать это, найдя последний экземпляр HTMLhrefв хеш-список VirusShare. Это можно сделать с помощью следующих строк кода -
tag = index.rfind(r'a href = "hashes/VirusShare_')
stop = int(index[tag + 27: tag + 27 + 5].lstrip("0"))
if "start" not in kwa<rgs:
start = 0
else:
start = kwargs["start"]
if start < 0 or start > stop:
print("[-] Supplied start argument must be greater than or equal ""to zero but less than the latest hash list, ""currently: {}".format(stop))
sys.exit(2)
print("[+] Creating a hashset from hash lists {} to {}".format(start, stop))
hashes_downloaded = 0
Теперь мы будем использовать tqdm.trange() метод для создания цикла и индикатора выполнения следующим образом:
for x in tqdm.trange(start, stop + 1, unit_scale=True,desc="Progress"):
url_hash = "https://virusshare.com/hashes/VirusShare_"\"{}.md5".format(str(x).zfill(5))
try:
hashes = urlopen(url_hash, context=context).read().decode("utf-8")
hashes_list = hashes.split("\n")
except urllib.error.HTTPError as e:
print("[-] Error accessing webpage for hash list {}"" - continuing..".format(x))
continue
После успешного выполнения вышеуказанных шагов мы откроем текстовый файл хеш-набора в режиме +, чтобы добавить его в конец текстового файла.
with open(hashset, "a+") as hashfile:
for line in hashes_list:
if not line.startswith("#") and line != "":
hashes_downloaded += 1
hashfile.write(line + '\n')
print("[+] Finished downloading {} hashes into {}".format(
hashes_downloaded, hashset))
После запуска вышеуказанного скрипта вы получите последний список хешей, содержащий хеш-значения MD5 в текстовом формате.
В предыдущих главах обсуждались важность и процесс сетевой криминалистики, а также используемые концепции. В этой главе давайте узнаем о роли электронных писем в цифровой криминалистике и их расследовании с использованием Python.
Роль электронной почты в расследовании
Электронная почта играет очень важную роль в деловом общении и стала одним из самых важных приложений в Интернете. Это удобный режим для отправки сообщений и документов не только с компьютеров, но и с других электронных устройств, таких как мобильные телефоны и планшеты.
Отрицательная сторона электронных писем состоит в том, что преступники могут утечь важную информацию о своей компании. Следовательно, в последние годы роль электронной почты в цифровой криминалистике возросла. В цифровой криминалистике электронные письма рассматриваются как важные доказательства, и анализ заголовков электронных писем стал важным для сбора доказательств в ходе судебно-экспертного процесса.
При проведении криминалистической экспертизы электронной почты следователь преследует следующие цели:
- Выявить главного преступника
- Собрать необходимые доказательства
- К представлению результатов
- Чтобы построить корпус
Проблемы электронной почты
Электронная криминалистика играет очень важную роль в расследовании, поскольку большая часть общения в нынешнюю эпоху зависит от электронной почты. Однако судебно-медицинский следователь электронной почты может столкнуться со следующими проблемами во время расследования:
Поддельные электронные письма
Самая большая проблема в судебной экспертизе электронной почты - это использование поддельных электронных писем, которые создаются путем манипулирования заголовками и написания сценариев и т. Д. В этой категории преступники также используют временную электронную почту, которая представляет собой службу, которая позволяет зарегистрированному пользователю получать электронную почту на временный адрес, срок действия которого истекает. через определенный промежуток времени.
Спуфинг
Еще одна проблема судебной экспертизы электронной почты - это спуфинг, когда преступники представляли электронное письмо как чужое. В этом случае машина получит как поддельный, так и оригинальный IP-адрес.
Анонимная пересылка по электронной почте
Здесь сервер электронной почты удаляет идентифицирующую информацию из сообщения электронной почты перед его дальнейшей пересылкой. Это приводит к еще одной большой проблеме для расследования электронной почты.
Методы, используемые в судебной экспертизе электронной почты
Экспертиза электронной почты - это исследование источника и содержания электронной почты в качестве доказательства для идентификации фактического отправителя и получателя сообщения вместе с некоторой другой информацией, такой как дата / время передачи и намерение отправителя. Он включает в себя исследование метаданных, сканирование портов, а также поиск по ключевым словам.
Некоторые из распространенных методов, которые можно использовать для судебно-медицинской экспертизы электронной почты:
- Анализ заголовка
- Исследование сервера
- Исследование сетевого устройства
- Отпечатки отправителя почтовой программы
- Программные встроенные идентификаторы
В следующих разделах мы узнаем, как получать информацию с помощью Python для расследования электронной почты.
Извлечение информации из файлов EML
Файлы EML - это в основном электронные письма в формате файлов, которые широко используются для хранения сообщений электронной почты. Это структурированные текстовые файлы, совместимые с несколькими почтовыми клиентами, такими как Microsoft Outlook, Outlook Express и Windows Live Mail.
EML-файл хранит заголовки электронной почты, основной контент и данные вложения в виде простого текста. Он использует base64 для кодирования двоичных данных и кодировку Quoted-Print (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 библиотека для настройки Outlook API что дополнительно позволяет получить доступ к 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, размер, SenderName, отправлено и т. д.
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, вам необходимо выполнить следующие действия:
открыто My account приборная доска.
Перейдите в раздел «Личная информация и конфиденциальность» и выберите ссылку «Управление контентом».
Вы можете создать новый архив или управлять существующим. Если мы нажмем,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
Все библиотеки были использованы и объяснены в более ранних сценариях, за исключением mailbox библиотека, которая используется для разбора файлов 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)))
Теперь определите метод чтения для mailbox библиотека следующим образом -
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
Теперь давайте определим функцию для извлечения имен файлов из message чтобы точно представить имена этих файлов следующим образом -
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 и каталог, полный вложений.
В этой главе будут объяснены различные концепции криминалистической экспертизы Microsoft 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 для просмотра.
Давайте посмотрим, как использовать код 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 file, если это действительный файл.
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 с этими метаданными.
Код 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.
Наконец, нам нужно обработать каждый улей и вывести проанализированные значения на консоль для интерпретации.
Код 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> улей -
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')
Теперь с помощью следующего метода мы можем обработать SOFTWARE улей -
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 и способах их извлечения с помощью Python.
Действия пользователя
Windows с NTUSER.DATфайл для хранения различных действий пользователя. У каждого профиля пользователя есть улей вродеNTUSER.DAT, в котором хранится информация и конфигурации, относящиеся конкретно к этому пользователю. Следовательно, он очень полезен для расследования, проводимого судебными аналитиками.
Следующий скрипт Python проанализирует некоторые ключи NTUSER.DATдля изучения действий пользователя в системе. Прежде чем продолжить, для скрипта Python нам необходимо установить сторонние модули, а именноRegistry, pytsk3, pyewf и Jinja2. Мы можем использовать pip для их установки.
Мы можем выполнить следующие шаги, чтобы извлечь информацию из NTUSER.DAT файл -
Сначала ищите все NTUSER.DAT файлы в системе.
Затем проанализируйте WordWheelQuery, TypePath and RunMRU ключ для каждого NTUSER.DAT файл.
Наконец, мы запишем эти уже обработанные артефакты в HTML-отчет, используя Jinja2 fmodule.
Код 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 дескриптор файла и считайте его в класс реестра через 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.
Код 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 создает prefetch files. Они используются для ускорения процесса запуска приложения. Расширение для этих файлов.PF и они хранятся в ”\Root\Windows\Prefetch” папка.
Эксперты по цифровой криминалистике могут выявить доказательства выполнения программы из указанного места вместе с данными пользователя. Файлы предварительной выборки являются полезными артефактами для исследователя, поскольку их запись остается даже после удаления или деинсталляции программы.
Давайте обсудим скрипт Python, который будет извлекать информацию из файлов предварительной выборки Windows, как указано ниже -
Для скрипта Python установите сторонние модули, а именно pylnk, pytsk3 и unicodecsv. Напомним, что мы уже работали с этими библиотеками в сценариях Python, которые мы обсуждали в предыдущих главах.
Чтобы извлечь информацию из prefetch файлы -
Сначала просканируйте .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.
Журналы событий
Файлы журнала событий Windows, как name –suggests, представляют собой специальные файлы, в которых хранятся важные события, например, когда пользователь входит в систему, когда программа обнаруживает ошибку, об изменениях в системе, доступе RDP, событиях, связанных с приложением и т. Д. Кибер-исследователей всегда интересуют события информация журнала, потому что она предоставляет много полезной исторической информации о доступе к системе. В следующем скрипте Python мы собираемся обрабатывать как устаревшие, так и текущие форматы журнала событий Windows.
Для скрипта Python нам необходимо установить сторонние модули, а именно pytsk3, pyewf, unicodecsv, pyevt and pyevtИкс. Мы можем выполнить следующие шаги, чтобы извлечь информацию из журналов событий -
Сначала найдите все журналы событий, соответствующие входному аргументу.
Затем выполните проверку подписи файла.
Теперь обработайте каждый найденный журнал событий с помощью соответствующей библиотеки.
Наконец, запишите результат в электронную таблицу.
Код 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.
Код 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.
Затем извлеките информацию из этих теневых копий, перебирая их.
Теперь, наконец, нам нужно создать список файлов данных в снимках.
Код 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.
Отметки времени
Отметка времени передает данные и время активности в журнале. Это один из важных элементов любого файла журнала. Обратите внимание, что эти значения данных и времени могут иметь различные форматы.
Скрипт 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.
Код 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.