Глава 4. Python и изыскания/ приобретение в реальном времени

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

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

В настоящее время многие всё ещё воспринимают цифровые доказательства как статические данные, которые проверяются после того как мы представляем цифровые носители. Естественно, это меняется, в особенности действия Реакции на происшествия криминального анализа, сокращённо DFIR (Digital Forensic Incident Response). Сбор, анализ и аргументация относительно происшествий "в реальном времени" - я начинал писать об этом и разрабатывать решения ещё в 2006.

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

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

  • Метод 1: Запуск CmdLet PowerShell или сценариев а затем сбором и последующей обработкой полученных результатов в Python.

  • Метод 2: Исполнение CmdLet PowerShell или сценариев и конвейерная отправка полученных результатов в выполняющие ожидание сценарии Python.

В этой главе будет изучен Метод 1, а Метод 2 будет обсуждаться в Главе 5. В обоих случаях эти методы будут изучаться на примерах.

Что означает `По примеру`?

Существуют в доступности буквально сотни книг по Python, причём большинство из них сосредоточенно именно на том как программировать и обычно применяют подход к обучению вас тонкостям самого языка программирования. Эти тексты предназначены тем, кто делает карьеру в области вычислительных наук, разработки программного обеспечения, веб- разработки или обработки Больших данных.

Наша цель здесь состоит в применении Python к конкретным задачам в области цифровых расследовваний и объединении Python c PowerShell для создания решений. Занимательно, что по ходу действия вы ознакомитесь с новыми методами техники создания сценариев.

Лучшая пришедшая мне в голову аналогия это освоение новой культуры. Вы можете прочесть о культуре Майя, прсмотреть фильмы о её истории и изучить карты тех стран, в которых они проживали. Или же вы можете отправиться туда и пройтись по их вселенной, поговорить с представителями майя, изучить их святые места и ознакомиться с культурой из первых рук.

Направление PowerShell при помощи Python

Поскольку неумолимо приближается дата кончины Python 2.7, для всех основанных на Знерщт приверов этой книги будет применяться Python 3.7. Python 2 и 3 содержат гигантское количество встроенных стандартных библиотек наряду с тысячами сторонних библиотек. По мере возможности будут применяться стандартные библиотеки Python для обеспечения максимально широкой межплатформенной совместимости. Вы можете получить Python 3.7 напрямую с www.python.org. На момент написания самой последней доступной версией является Python 3.7.2 {Прим. пер.: на момент перевода Python 3.7.3}, как это показано на Рисунке 4-1.

 

Рисунок 4-1


Download Python 3.7.3

Дополнительно к самой последней версии Python я настоятельно рекомендую применять Python Integrated Development Environment. Сам я предпочитаю WingIDE. {Прим. пер.: брр...}

Эта персональная редакция бесплатна и отлично подходит для большинства задач разработки и написания сценариев. На их вебсайте представлены великолепные руководства по настройке и применению WingDE, которые можно отыскать по: www.wingware.com.

 

Рисунок 4-2


Домашняя страница Wingware/ WingDE

Запуск cmdlet PowerShell из Python

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

В Главе 1 и Главе 2 рассматривались изучение, применение и криминалистические приложения CmdLet. Я надеюсь, вы уже поэкспериментировали с разнообразными дополнительными CmdLet. Следовательно, что если бы мы смогли исполнять CmdLet PowerShell из Python и перехватывать результаты? Так как PowerShell является неким исполняемым процессом, тем самым мы можем применять стандартную библиотеку Python, предоставляющую возможность запуска поцессов. Это делается с применением стандартной библиотеки subprocess. В Python для применения любой стандартной или сторонней библиотеки вам следует импортировать её. Это делается при помощи оператора импорта. В данном случае такой оператор это просто:


import subprocess
		

Это предоставляет доступ к методам и свойствам, содержащимся в данной библиотеке subprocess. Доступно монжество вариантов - наиболее популярным является применение метода check.output, который исполняет предписанный процесс и возвращает полученный результат. Вот некий пример:


runningProcesses = subprocess.check_output("powershell -Executionpolicy ByPass -Command Get-Process")
		
 

{Прим. пер.: приведём также аналог асинхронного варианта вызова подчинённого процесса (вызов метода await asyncio.create_subprocess_shell()), подробнее в наших переводах: Asyncio в Python 3 Цалеба Хаттингха и Полном руководстве параллельного программирования на Python Куан Нгуена}.


import asyncio

async def run(cmd):
    proc = await asyncio.create_subprocess_shell(
        cmd,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE)

    stdout, stderr = await proc.communicate()

    print(f'[{cmd!r} exited with {proc.returncode}]')
    if stdout:
        print(f'[stdout]\n{stdout.decode()}')
    if stderr:
        print(f'[stderr]\n{stderr.decode()}')

asyncio.run(run('powershell -Executionpolicy ByPass -Command Get-Process'))
		

Одним из замечательных свойств WingIDE Python Integrated Development является возможность экспериментов с командами изнутри самой интерактивной оболочки, как это показано на Рисунке 4-3. Три больше чем знака (>>>) выступают в качестве его приглашения интерактивной оболочки. Это в точности такое же приглашение, которое вы получили бы если бы вы запустили Python из командной строки или окна терминала.

 

Рисунок 4-3


Исполнение CmdLet PowerShell из оболочки Python

Разобъём по частям все элементы кода субпроцессов по мере их следования на Рисунке 4-4.

 

Рисунок 4-4


Разбивка команды субпроцесса Python

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

  2. Оператор присвоения , или знак равенства (=) назначает полученный результат вашей команды подпроцесса самой переменной runningProcesses.

  3. subprocess.check_output выступает выбранным методом из нашей библиотеки subprocess. Он получает единственный параметр, заключаемый в кавычки и определяет ту командную строку, которую вы желаете исполнять.

  4. Заключённая в кавычки строка внутри круглых скобок определяет подлежащую исполнению команду. E-H задают все элементы этой исполняемой команды.

  5. powershell выступает в роли команды, или в данном случае процесса для выполнения.

  6. -Executionpolicy ByPass, по умолчанию, PowwerShell не выполняет сценарии или CmdLet без полномочий в явном виде. Указанный параметр -Executionpolicy определяет значение политики для нашей команды PowerShell. Параметр ByPass сообщает PowerShell о том что не следует ничего блокировать и не выпускать никаких предупреждений или приглашений.

  7. -Command определяет что следует за командой PowerShell. В данном случае это просто CmdLet, однако это может быть более сложная команда на основе конвейера. Если вы желаете исполнить некий сценарий PowerShell, данный литерал следует заменить на -File с последующим допустимым названием файла .ps1.

  8. Get-Process является неким особым CmdLet, который следует исполнить. В данном примере CmdLet Get-Process выполняется без параметров.

В Python 3.x, наш метод subprocess.check_output() возвращает некую строку байт, в то время как в Python 2.7 он возвращает простую строку. Следовательно, для отображения полученного из данной Command вывода, нашу переменную runningProcesses требуется декодировать что показано здесь:


print(runningProcesses.decode())
 	   

Выполнение данной команды из интерактивной оболочки Python WingIDE предоставляет результаты, отображаемые на Рисунке 4-5. Отметим, что для краткости полученные результаты усечены.

 

Рисунок 4-5


Вывод на печать содержимого переменной runningProcesses

На данный момент вы можете спросить зачем мне преодолевать все эти сложности исполнения команды или CmdLet PowerShell из Python? Чтобы ответить на этот вопрос, давайте возьмём этот пример для следующего уровня.

Создание базовых системных файлов при помощи PowerShell и Python

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

Получение относящейся к файлам информации выполняется при помощи CmdLet Get-ChildItem в рамках PowerShell и связанных с ним методов. То, чем мы интересуемся при определении базового уровня это:

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

  2. Само название каждого файла.

Получение этой информации выполняется достаточно просто из PowerShell при помощи показанной ниже команды Конвейера. Это отсекает отображённые на Рисунке 4-6.


Get-ChildItem c:\windows\system32\drivers\ |
Get-FileHash | Select-object -Property Hash, Path | Format-Table -HideTableHeaders
		
 

Рисунок 4-6


Получение хэш- значений и пути при помощи PowerShell (отмечаем, что вывод усечён)

Разбивка команды подробно описывается на Рисунке 4-7.

 

Рисунок 4-7


Разбивка конвейера Get-ChildItem, Get-FileHash, Select-Object и Format-Table

Создание некого сценария PowerShell с входными параметрами сделает эту команду слегка более полезной и повторно применяемой. Весь сценарий целиком приводится на Листинге 4-1.

 

Листинг 4-1. Сценарий HashAquire.ps1


<#
.synopsis
Для предписанной папки собрать значения хэш- ключей и Названий файлов

- Пользователь определяет название целевого компьютера
- Пользователь определяет название целевой папки

Этот сценарий производит некий простейший файл вывода ascii output, содержащий SHA-256Hash и FilePath

.Description
Этот сценарий собирает Hash и Filenames с указанных компьютера и папки

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

.parameter UserName
Задаёт Имя пользователя с правами Администратора на Целевом компьютере

.parameter outFile
Определяет полный путь к файлу вывода

.example

HashAcquire
Собрать хеш- значения файлов в целевом компьютере
#>

# Раздел определения параметров
param(
    [string]$TargetFolder="c:/windows/system32/drivers/",
    [string]$ResultFile="c:/PS/baseline.txt"
)

Get-ChildItem $TargetFolder | Get-FileHash | Select-Object -Property Hash, Path | Format-Table -HideTableHeaders | Out-File $ResultFile -Encoding ascii
 	   

Данный сценарий имеет стандартные разделы для предоставления соответствующей поддержки Get-Help, показанной в Листинге 4-2.

 

Листинг 4-2. Результаты Get-Help для сценария PowerShell HashAquire.ps1


PS C:\PS> Get-Help .\HashAcquire.ps1

NAME
    C:\PS\HashAcquire.ps1

SYNOPSIS
    Для предписанной папки собрать значения хэш- ключей и Названий файлов

    - Пользователь определяет название целевого компьютера
    - Пользователь определяет название целевой папки

    Этот сценарий производит некий простейший файл вывода ascii output, содержащий SHA-256Hash и FilePath

SYNTAX
    C:\PS\HashAcquire.ps1 [[-TargetFolder] <String>] [[-ResultFile] <String>] [<CommonParameters>]

DESCRIPTION
    Этот сценарий собирает Hash и Filenames с указанных компьютера и папки

RELATED LINKS

REMARKS
    To see the examples, type: "get-help C:\PS\HashAcquire.ps1 -examples".
    For more information, type: "get-help C:\PS\HashAcquire.ps1 -detailed".
    For technical information, type: "get-help C:\PS\HashAcquire.ps1 -full".
 	   

Наш сценарий содержит два входных параметра, TargetFolder и ResultFile.


# Раздел определения параметров
param(
    [string]$TargetFolder="c:/windows/system32/drivers/",
    [string]$ResultFile="c:/PS/baseline.txt"
)
 	   

При использовании значений параметров по умолчанию, данный сценарий создаёт файл baseline.txt. Сокращённые результаты приводится на Рисунке 4-8. При подставке параметра для задания конкретной папки назначения данный сценарий может теперь применяться для любой допустимой папки.

[Замечание]Замечание

Доступ к некоторым папкам потребует полномочий администратора. Убедитесь что вы запускаете PowerShell с правми Администратора.


PS C:\PS>  .\HashAcquire.ps1
		
 

Рисунок 4-8


Сокращённые результаты baseline.txt

 

Создание конкретного базового уровня при помощи Python

Теперь, когда у нас имеется некий надёжный метод выделения значения хэша и названия файла при помощи сценария PowerShell HashAcquire.ps1, мы можем воспользоваться Python для создания по этим результатам некоторого базового уровня. Однако для этого вместо применения имеющейся интерактивной оболочки мы создадим некую сценарий/ программу Python.

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

[Замечание]Замечание

Наш имеющийся в настоящий момент сценарий обрабатывает только предписанный каталог. Тем не менее, CmdLet Get-ChildItem имеет необязательный параметр также и для получения вложенной папки. Этим параметром является -recurse, ознакомьтесь с его применением:


Get-Help Get-ChildItem
		

Вы обнаружите, что Get-ChildItem имеет много параметров и примеров применения.

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

[Замечание]Замечание

Словари Python, как и традиционные словари Веьстера, имеют Ключ и Значение, которые обычно именуются парой Key/Value. В Python и Ключ, и Значение должны иметь пригодный для хэширования тип, такой как integer, long, string или tuple (кортеж). Сама часть Значение пары Key/Value может быть списком или иным, не подлежащими хэшированию, типом данных. Кроме того, все ключи словаря обязаны быть уникальными (во многом как и словари из жизни).

Полный сценарий CreateBaseline.py показан в Листинге 4-3.

[Замечание]Замечание

Для сценариев powershell и python на протяжении всей оставшейся книги был создан каталог c:\PS для хранения в нём всех сценариев и результатов.

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

 

Листинг 4-3. Сценарий Python CreateBaseLine


	 '''
Step One Create a baseline hash list of target folder
December 2018, Python Forensics
'''
''' LIBRARY IMPORT SECTION '''
import subprocess       # subprocess library
import argparse         # argument parsing library
import os               # Operating System Path
import pickle           # Python object serialization

'''РАЗДЕЛ РАЗБОРА АРГУМЕНТА '''

def ValidatePath(thePath):
    ''' Проверяем значение Папки thePath
        она должна существовать и мы обязаны иметь права
        на чтение из этой папки.
        если что- то не верно, 
        возбуждаем соответствующую ошибку
    '''
    # Validate the path exists
    if not os.path.exists(thePath):
        raise argparse.ArgumentTypeError('Path does
        not exist')

    # Validate the path is readable
    if os.access(thePath, os.R_OK):
        return thePath
    else:
        raise argparse.ArgumentTypeError('Path is not readable')

#Конец проверки

''' Определяем командную строку и выполняем её разбор, проверяем значения аргументов и возвращаемые результаты'''

parser = argparse.ArgumentParser('File System Baseline Creator with PowerShell- Version 1.0 December 2018')

parser.add_argument('-b', '--baseline',
required=True,
help="Определяем свой получаемый в результате файл словаря базового уровня")

parser.add_argument('-p', '--Path',
required=True, type= ValidatePath,
help="Определяем значение папки назначения для базового уровня")

parser.add_argument('-t', '--tmp',
required=True,
help="Определяем временный файл результата для своего сценария PowerShell")

args = parser.parse_args()

baselineFile = args.baseline
targetPath   = args.Path
tmpFile      = args.tmp

''' Основной раздел сценария MAIN '''
if __name__ == '__main__':

    try:
        ''' Раздел исполнения POWERSHELL '''
         command = "powershell -ExecutionPolicy ByPass
-File C:/PS/HashAcquire.ps1"+"
-TargetFolder "+ targetPath+" -ResultFile "+ tmpFile
        print(command)
        powerShellResult = subprocess.run(command, stdout=subprocess.PIPE)
        if powerShellResult.stderr == None:

            ''' Раздел создания словаря '''
            baseDict = {}

            with open(tmpFile, 'r') as inFile:
                for eachLine in inFile:
                    lineList = eachLine.split()
                    if len(lineList) == 2:
                        hashValue = lineList[0]
                        fileName  = lineList[1]
                        baseDict[hashValue] = fileName
                    else:
                        continue

            with open(baselineFile, 'wb') as outFile:
                pickle.dump(baseDict, outFile)

                print("Baseline: ", baselineFile, " Создан с:", "{:,}".format(len(baseDict)), "записей")
                print("Сценарий успешно выполнен")
        else:
            print("Ошибка PowerShell:", p.stderr)

    except Exception as err:
        print ("не могу создать файл вывода: "+str(err))
        quit()
 	   

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

  1. Импорт библиотеки

  2. Разбор аргумента

  3. Основной код

  4. Исполнение PowerShell

  5. Создание словаря

Импорт библиотеки:

  • subprocess: Применяется для запуска необходимого сценария PowerShell

  • os: Используется для проверки файла и папки

  • argparse: Применяется для синтаксического разбора аргументов полученной командной строки

  • pickle: Используется для сохранения получаемого в результате словаря в неком файле для последующего применения

Разбор аргумента:

  • -b: задаёт значение имени файла базового уровня для получаемого в результате словаря.

  • -p: определяет значение пути назначения для его применения нашим сценарием PowerShell для сохрванения выделенных хэш- значений и имён файлов.

  • -t: задаёт значение имени временного файла, применяемого сценарием PowerShell для сохрванения выделенных хэш- значений и имён файлов.

Имеющаяся в Python библиотека argparse автоматически обрабатывает получаемую командную строку и убеждается что ваш пользователь ввёл все необходимые аргументы, а также воспроизводит подсказку при её запросе. Рисунок 4-9 отображает папку для проверки и получаемый в после исполнения данного сценария результат при наличии единственного параметра -h.

 

Рисунок 4-9


Выполнение запроса подсказки CreateBaseline.py

Обработка раздела аргументов в результате создаёт три переменные:

  1. [-b] baselineFile: Которая определяет получаемый результат файла словаря базового уровня. Этот файл будет создан нашим сценарием Python.

  2. [-p] targetPath: Которая передаётся в наш сценарий PowerShell для определения какая папка служит для базового уровня. Применяется нашим сценарием PowerShell.

  3. [-t] tmpFile: Которая передаётся в наш сценарий PowerShell для определения получаемого в результате временного текстового файла, который будет содержать необходимые промежуточные результаты. Наш сценарий Python воспользуется этим файлом после его выработки соответствующим сценарием PowerShell.

Основной код: Основной раздел выполняет центральные элементы нашего сценария по завершению всех предварительных настроек.

Исполнение PowerShell: Этот раздел запускает наш сценарий PowerShell. Вначале он создаёт некую переменную с именем command, которая будет применяться методом subprocess.run() для запуска этого сценария PowerShell. Отметим наше исполнение на это раз определяет некий файл, -File, вместо команды, -Command, что применялось в предыдущем примере. Он задаёт наш сценарий PowerShell HashAcquire.ps1. После выполнения данного субпроцесса команды проверяются значения стандартной ошибки или резултат stderr на предмет успшного завершения. Результатом должен быть None. Если это не так, наш сценарий Python выдаст сообщение о возвращаемой ошибке.

Создание словаря: Если наша команда PowerShell выполнена успешно, тогда наш сценарий Python после этого обрабатывает получаемый в результате файл для создания необходимого словаря. Так как получаемого в результате файла определяется самим сценарием PowerShell, при помощи итерационного цикла Python можно выполнить обработку всех строк этого файла для извлечения значений хэша и названия файла. Для каждой строки создаётся запись словаря с помощью значения хэша в качестве Key и значения имени файла как Value для соответствующей пары KEY/VALUE. После обработки всех строкдля сохранения созданного словаря применяется библиотека Python pickle в том файле, который был определён в вашей командной строке, и название которого теперь находится в переменной baselineFile. Нащ сценарий Python после этого выводит отчёт подробностей данного сценария. Если в процессе исполнения данного сценария Python возникли ошибки или исключительные ситуации, данный сценарий выдаст сообщение о такой исключительной ситуации.

Рисунок 4-10 отображает успешной исполнение сценариев Python CreateBaseline.py в сочетании с PowerShell HashAcquire.ps1. Как вы можете видеть, ваш сценарий воспроизвёл 447 словарных записей для тех файлов, которые содержатся в папке c:/windows/system32/drivers/ . Кроме того, в нашей папке c:/PS/ было создано два файла, baseline.txt и baseline.pickle.

 

Рисунок 4-10


Исполнение сочетания сценариев Python/ PowerShell

 

Проверка имеющегося базового уровня при помощи Python

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

  1. Имелись ли какие- то добавления файлов?

  2. Удалялись ли какие- то файлы?

  3. Изменялись ли какие- то файлы?

Мы собираемся повторно воспользоваться сценарием PowerShell HashAcquire.ps1 и внести некие изменения для обработки всех возвращаемых HashAcquire.ps1 изменений. В целом, сценарий VerifyBaseline.py выглядит почти идентично нашему сценарию CreateBaseline.py. Единственное изменение содержит:

  1. Добавим Раздел BASELINE DICTIONARY LOAD

  2. Добавим Раздел DICTIONARY TEST и связанные с ним функции проверки словаря.

Листинг 4-4 содержит полную проверку сценария Python. Отметим, что сценарий PowerShell HashAcquire.ps1 не изменялся.

 

Листинг 4-4. проверка сценария Python основного уровня


'''
Второй этап проверки списка базового уровня хэш- ключей с некой назначаемой папкой
December 2018, Python Forensics

'''

''' Раздел импорта библиотек '''

import subprocess       # библотека subprocess
import argparse         # библиотека синтаксического разбора аргусентов
import os               # Путь операционной системы
import pickle           # Упорядочение объекта Python

"'Раздел разбора аргументов "'

def ValidatePath(thePath):
    ''' Проверка значения папки thePath
        она обязана существовать и у нас должны иметься права 
        для чтения этой папки.
        возбуждаем возникшие в процессе ошибки если 
        результат не равен истине
    '''

    # Проверка существования данного пути
    if not os.path.exists(thePath):
        raise argparse.ArgumentTypeError('Path does not exist')
    # Проверка доступа на чтение этого пути
    if os.access(thePath, os.R_OK):
        return thePath
    else:
        raise argparse.ArgumentTypeError('Path is not readable')

#Конец ValidatePath ===================================

''' Определить и выполнить разбор получаемой командной строки, проверить получаемые параметры и вернуть результаты'''

parser = argparse.ArgumentParser('File System Baseline Validation with PowerShell- Version 1.0 December 2018')

parser.add_argument('-b', '--baseline',required=True,
help="Задайте источник файла базового уровня для проверки")

parser.add_argument('-p', '--Path',
type= ValidatePath, required=True,
help="Задайте источник файла целевой папки для проверки")

parser.add_argument('-t', '--tmp', required=True,
help="Задайте файл временого результата для нашего сценария PowerShell")

args = parser.parse_args()

baselineFile = args.baseline
targetPath   = args.Path
tmpFile      = args.tmp

def TestDictEquality(d1,d2):
    """ возвращает True если все ключи и значения остаются неизменными
        в противном случае возвращает False """
    if all(k in d2 and d1[k] == d2[k] for k in d1):
        if all(k in d1 and d1[k] == d2[k] for k in d2):
            return True
        else:
            return False
    else:
        return False

    '''
    return all(k in d2 and d1[k] == d2[k]
               for k in d1) \
        and all(k in d1 and d1[k] == d2[k]
               for k in d2)
    '''

def TestDictDiff(d1, d2):
    """ возвращает значение подмножества d1, в котором значения ключей не совпали со значениями в d2 или отличаются от значений в d2 по словарям """
    diff = {}

    for k,v in d1.items():
        if k in d2 and v in d2[k]:
            continue
        else:
            diff[k+v] = "Отличия Baseline"

    return diff

''' Основной Раздел сценария '''
if __name__ == '__main__':

    try:
        ''' Раздел исполнения POWERSHELL '''
        print()
        command = "powershell -ExecutionPolicy ByPass -File C:/PS/HashAcquire.ps1"+" -TargetFolder "+ targetPath+" -ResultFile "+ tmpFile
        print(command)
        print()

        powerShellResult = subprocess.run(command, stdout=subprocess.PIPE)
        if powerShellResult.stderr == None:

            ''' Раздел загрузки словаря BASELINE '''
            # Load in the baseline dictionary

            with open(baselineFile, 'rb') as baseIn:
                baseDict = pickle.load(baseIn)

            ''' Раздел создания словаря '''

            # Создать новый словарь для данного указанного каталога
            newDict  = {}

            with open(tmpFile, 'r') as inFile:
                for eachLine in inFile:
                    lineList = eachLine.split()
                    if len(lineList) == 2:
                        hashValue = lineList[0]
                        fileName  = lineList[1]
                        newDict[hashValue] = fileName
                    else:
                        continue

            ''' Раздел проверки словаря '''
            if TestDictEquality(baseDict, newDict):
                print("Изменения не выявлены")

            else:
                diff = TestDictDiff(newDict, baseDict)
                print(diff)
        else:
            print("Ошибка PowerShell:", p.stderr)

    except Exception as err:
        print ("Не могу создать файл вывода: "+str(err))
        quit()
 	   
 

Обзор разделов Нового кода в VerifyBaseline.py

Загрузка словаря: Этот радел загружает предписанный словарь из сохранённого файла pickle, который был создан в нашем сценарии CreateBaseline.py. Для восстановления словаря из заданного файла применяется метод pickle load().

Проверка словаря: Данный раздел применяет две только что созданные функции:

  • TestDictEquality()

  • TestDictDiff()

Функция TestDictEquality проводит сравнение вновь созданного словаря указанной папки назначения с тем словарём, который был загружен при помощи метода pickle.load(). Эти два словаря

  • baseDict

  • newDict

содержат все каталоги для сравнения. Для каждого из каталогов эти словари содержат значения SHA-256 Hash (ключа) и Filename (значение). Python предоставляет множество встроенных механизмов для сравнения и итерации по словарям. Имеющаяся функция TestDictEquality проверяет что эти два словаря в точности совпадают. И если это так, данная функция возвращает True. Если они не эквивалентны, тогда эти функции возвращают False. Для выявления отличий вызывается функция TestDictDiff(), в случае возникновения таковых.

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

Рисунок 4-11 отображает исполнение данного сценария VerifyBaseline.py, включая результаты новой справки и выявленное отсутствие различий.

 

Рисунок 4-11


Проверка исполнением базового уровня и подсказка с отстутствием изменений

Рисунок 4-12 показывает результат сценария VerifyBaseline.py с выявлением двух добавленных в c:/windows/system32/drivers безопасных файлов.

 

Рисунок 4-12


Проверка исполнением базового уровня с выявленными изменениями

Обзор исполнения Python при помощи PowerShell

Этот пример предоставляет элегантную модель выполнения PowerShell и последующей обработки результатов в Pythonю Что ешё более важно, эту модель можно расширить на некие иные варианты использования. Например:

  1. Изменив сценарий и параметры PowerShell можно добавить указание целевого ComputerName. Затем сценарий PowerShell может доьавить CmdLet Invoke-Command и после этого выполнить удалённую выемку, нечто что было бы не так просто сделать исключительно из Python. Тем самым мы используем PowerShell в качестве механизма извлечения, в то время как Python применяется как сервер обработки. Вот некий образец изменённой команды PowerShell, которая может понадобиться для этого:

    
    Invoke-Command -ComputerName $targetComputer -Credential $User -ScriptBlock {Get-ChildItem $TargetFolder | Get-FileHash | Select-Object -Property Hash, Path | Format-Table -HideTableHeaders | Out-File $ResultFile -Encoding ascii}
    		
  2. Наш CmdLet выборки ChildItem можно заменить изобильным разнообразием прочих риентированных на выемку сведений CmdLet, таких как:

    • Get-Process

    • Get-Service

    • Get-NetTCPConnections

    • Get-NetFirewallSetting

    • либо любых иных локальных или сетевых значений представляющих интерес для расследования

    Затем, сценарии Python CreateBaseline и VerifyBaseline могут быть применены без изменений для создания базового уровня и последующего выявления любых изменений в вашей среде.

  3. Нашу модель интерфейса с применением subprocess.run() {Прим. пер.: или его асинхронного аналога} можно применять и для прочих сценариев получения данных от сценариев PowwerShell. При помощи такой модели создания простого файла результатов ASCII можно построчно глотать строку за строкой в Python, устанавливая основательный интерфейс между Python и PowerShell. Конечно, вы можете возвращать получаемые данные через стандартный вывод. Однако этот метод менее стабилен при выработки значительного вывода PowerShell. {Прим. пер.: можно воспользоваться и обменом сообщений, например, см. наши переводы RabbitMQ для профессионалов Гайвина Роя, Практического программирования MQTT на Python Гастона К. Хайляра, или даже распределённых систем хранения ключ- значение, см. наш перевод Книга рецептов Redis 4.x Пеньчень Хуань, Зуофей Вань.}

Задачи для изучения: Осуществление удалённого исполнения сценария

Воспользуйтесь тем что вы узнали относительно исполнения сценариев PowerShell из Python и представленной модели, чтобы воспроизвести:

  1. Расширьте предлагаемое нами решение, изучив прочие CmdLet PowerShell, которые предоставляют значения для расследования или ответа на происшествие. Настройте как полагается сценарии PowerShell и Python.

    1. Get-Process

    2. Get-Service

    3. Get-NETTCPConnections

    4. Get-FirewallSettings

  2. Видоизмените сценарии PowerShell и Python с тем, чтобы они содержали доступ к прочим компьютерам. Это потребует изменений в обоих сценариях для предоставления требуемого названия (названий) дополнительного компьютера. Кроме того, сценарий PowerShell потребует добавления соответствующего CmdLet Invoke-Command.

Выводы

Эта глава была сосредоточена на исполнении CmdLet и сценариев PowerShell напрямую из Python. Она рассмотрела основной ключевой метод взаимодействия с PowerShell с применением библиотеки subprocess Python {Прим. пер.: или его асинхронного аналога}.

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

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

Глава 5 расширит интеграцию PowerShell и Python дополнительными примерами и методами.