Источник: https://github.com/AnaktaCTF/CTF/blob/main — Forensic/Анализ дампов памяти Windows.md

Введение

Оперативная память — это «рабочая область» современных операционных систем, в которой хранятся данные активных процессов, сетевые соединения, расшифрованные строки и даже учетные записи пользователей в виде открытых структур. В отличие от файлов на диске, которые могут быть зашифрованы, удалены или модифицированы, данные в ОЗУ отражают текущее состояние системы в момент захвата дампа. Это делает Memory Forensics одним из важнейших инструментов при расследовании инцидентов: будь то анализ целевого взлома, исследование вредоносного ПО или аудит утечек.

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

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

1. Подготовка тестового стенда и инструменты для съёмки дампа

Для корректного анализа важна изолированная среда: лучше всего использовать виртуальную машину (VirtualBox, VMware или Hyper-V) со снимком («снэпшотом») «чистой» системы. Это позволяет быстро вернуть исходное состояние, избежать фоновых шумов сторонних приложений и обеспечить воспроизводимость экспериментов.

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

Существует два основных инструмента для съёмки дампа на Windows:

  • WinPmem – утилита проекта [OSForensics] , позволяющая захватить всю ОЗУ в формате raw. Она вызывается из командной строки и поддерживает опции для сжатия, шифрования и сохранения в формате AFF4;
  • DumpIt – портативный исполняемый файл, не требующий установки, который после запуска автоматически собирает дамп и сохраняет его рядом с исполняемым файлом.

Использование любого из них сводится к запуску от имени администратора. В случае WinPmem достаточно перейти в папку утилиты и выполнить команду:

winpmem.exe -o memory.raw --format raw

DumpIt же не требует подготовки: двойной клик по DumpIt.exe запустит процедуру съёмки и выдаст файл memory.raw. В обоих случаях необходимо дождаться завершения всех операций, не перезагружая виртуальную машину, чтобы полученный дамп был целостным.

2. Установка и базовая настройка Volatility 3

Volatility 3 — это современный фреймворк для анализа дампов памяти, написанный на Python и обладающий модульной архитектурой. Он умеет работать с образами разных форматов (RAW, EWF, HPAK, AFF4), поддерживает Windows, Linux и macOS, а также допускает расширение за счёт плагинов.

Для установки Volatility 3 в рамках изолированного окружения выполните следующие действия:

  1. Создание виртуального окружения.
    Откройте терминал (или PowerShell) и в каталоге проекта запустите команду:

    python3 -m venv venv-vol3
    

    После этого активируйте окружение:

    source venv-vol3/bin/activate      # В Linux/macOS
    venv-vol3\Scripts\activate         # В Windows
    
  2. Обновление pip и установка Volatility 3.

    pip install --upgrade pip setuptools
    pip install volatility3
    
  3. Проверка корректности установки.
    Введите команду vol -h, и вы должны увидеть справку по основным параметрам запуска, доступным командам и списку встроенных плагинов.

  4. Подключение сторонних плагинов (по необходимости).
    Многие исследователи дополняют стандартный набор своими разработками. Обычно для установки требуется клонировать репозиторий и выполнить в нём:

    pip install .
    

    или указать ссылку на пакет в requirements.txt.

В результате у вас появится исполняемый скрипт vol (или volatility3) в venv-vol3/bin, готовый к анализу любых дампов памяти.

3. Основные плагины Volatility 3

3.1 pslist и psscan: процессы «на виду» и скрытые

Плагин pslist опирается на связные списки EPROCESS, поддерживаемые ядром Windows. При запуске он выводит все процессы, зарегистрированные в списке активных. Для исследования используйте команду:

vol -f memory.raw windows.pslist

Вы получите таблицу с полями: PID, PPID, имя процесса, время создания и приоритета. Однако злоумышленник может удалить свой процесс из этого списка, и тогда его уже не покажет pslist. Здесь на помощь приходит psscan, сканирующий память на предмет сигнатур структур EPROCESS независимо от списка:

vol -f memory.raw windows.psscan

Сравнение выходных данных обеих команд позволяет обнаружить процессы, «спрятанные» от стандартного списка, и выявить завершённые процессы, скрытые от обычных механизмов.

3.2 malfind: поиск инъекций и «подозрительных» страниц

malfind анализирует виртуальные адресные пространства процессов на предмет участков с атрибутом «исполняемая+неизвестная» память. Это классический признак внедрения DLL или shellcode. Пример запуска:

vol -f memory.raw windows.malfind --dump-dir dumps

Утилита сохранит каждый обнаруженный участок в отдельный файл в папке dumps. Аналитик может открыть эти фрагменты в дизассемблере (Ghidra, IDA Pro) и понять, какой именно код был внедрён и откуда он пришёл.

3.3 dlllist и handles: библиотеки и ресурсы

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

vol -f memory.raw windows.dlllist --pid 3456

Он полезен при анализе DLL-хиддинга, когда вредоносный загрузчик внедряет в легитимный процесс свои библиотеки.
handles возвращает открытые дескрипторы объекта ядра (файлы, реестр, сокеты):

vol -f memory.raw windows.handles --pid 3456

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

3.4 Дополнительные плагины: vadinfo, connscan, clipboard

  • vadinfo показывает детальную информацию о Virtual Address Descriptors (VAD) каждого процесса: диапазоны виртуальной памяти, атрибуты страниц, права доступа. Анализ этих данных выявляет участки, которые могли быть динамически созданы злоумышленником;
  • connscan и netscan ищут в памяти структуры для TCP/UDP соединений, отображая локальные и удалённые адреса, PID процесса и состояние соединения. Это помогает восстановить сетевую активность без логов в файрволе;
  • clipboard извлекает содержимое буфера обмена Windows, где могут храниться скопированные пароли или другие ценные сведения.

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

4. Создание собственного Python-скрипта на базе API Volatility 3

Когда ручное применение плагинов становится рутинным, имеет смысл автоматизировать некоторые задачи. Volatility 3 предоставляет Python-API, позволяющее вызывать плагины из кода, обрабатывать их результаты и формировать собственные отчеты.

4.1 Структура скрипта: контекст и конфигурация

В основе лежит создание объекта Context и конфигурация путей до образа памяти и символов:

import json
import logging
from volatility3.framework import contexts
from volatility3.framework.configuration import requirements
from volatility3.plugins.windows import lsa_secrets, netscan

# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Создаем контекст Volatility
ctx = contexts.Context()

# Указываем местоположение памяти и таблицу символов Windows
ctx.config['plugins.LayerStacker.single_location'] = 'memory.raw'
ctx.config['plugins.LayerStacker.primary.symbol_table'] = 'nt_symbols'

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

4.2 Вызов плагинов и обработка результатов

После инициализации контекста можно создавать экземпляры плагинов и запускать их метод run(). Ниже — пример извлечения LSA secrets (хэшей и паролей пользователей):

def extract_lsa_secrets():
    plugin = lsa_secrets.LsaDecrypt(ctx, config_path='plugins.LayerStacker')
    for secret in plugin.run():
        name = secret.Name
        try:
            value = secret.Data.decode('utf-16le')
        except Exception:
            value = repr(secret.Data)
        yield {'name': name, 'value': value}

Для сетевых соединений используется плагин netscan:

def extract_network_sessions():
    plugin = netscan.NetScan(ctx, config_path='plugins.LayerStacker')
    for entry in plugin.run():
        yield {
            'pid': entry.ProcessId,
            'process_name': entry.ProcessName,
            'local': f"{entry.LocalAddress}:{entry.LocalPort}",
            'remote': f"{entry.RemoteAddress}:{entry.RemotePort}",
            'state': entry.State
        }

Каждую запись удобно преобразовать в словарь и собрать в список для дальнейшего экспорта.

4.3 Основной блок исполнения и сохранение артефактов

Завершающий фрагмент скрипта объединяет данные и сохраняет в JSON:

if __name__ == '__main__':
    secrets = list(extract_lsa_secrets())
    sessions = list(extract_network_sessions())

    report = {
        'lsa_secrets': secrets,
        'network_sessions': sessions
    }

    with open('memory_report.json', 'w', encoding='utf-8') as f:
        json.dump(report, f, ensure_ascii=False, indent=2)
    logger.info("Отчет сохранен в memory_report.json")

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

5. Расширение скрипта: анализ реестра и вытягивание артефактов Windows

Нередко исследователю требуется не только LSA-секреты и сетевые данные, но и информация из реестра, активных сессий пользователя, недавно открытых файлов. Volatility 3 включает плагины registry_hive и userassist, которые можно вызвать аналогичным образом:

from volatility3.plugins.windows.registry_hive import HiveList
from volatility3.plugins.windows.userassist import UserAssist

def extract_regristries():
    hive_plugin = HiveList(ctx, config_path='plugins.LayerStacker')
    for hive in hive_plugin.run():
        yield {'hive_path': hive.FileFullPathName, 'description': hive.HiveName}

def extract_userassist():
    ua = UserAssist(ctx, config_path='plugins.LayerStacker')
    for entry in ua.run():
        yield {
            'user_sid': entry.SID,
            'exe_path': entry.Application,
            'run_count': entry.RunCount
        }

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

6. Формирование отчёта и визуализация результатов

После получения JSON-отчёта удобнее представить данные в читаемом виде и подготовить к дальнейшему анализу и хранению.

6.1 Конвертация в CSV

С помощью Python-библиотеки pandas выполнить преобразование элементов массива в отдельные таблицы:

import pandas as pd

report = pd.read_json('memory_report.json')
lsa_df = pd.json_normalize(report['lsa_secrets'])
net_df = pd.json_normalize(report['network_sessions'])

lsa_df.to_csv('lsa_secrets.csv', index=False, encoding='utf-8-sig')
net_df.to_csv('network_sessions.csv', index=False, encoding='utf-8-sig')

Каждая строка CSV будет содержать поля, соответствующие имени секрета, значению или параметрам сетевой сессии.

6.2 Построение графа сетевых соединений

Для наглядности сетевой активности можно воспользоваться библиотеками networkx и matplotlib. Пример кода:

import networkx as nx
import matplotlib.pyplot as plt

df = pd.read_csv('network_sessions.csv')
G = nx.Graph()

for _, row in df.iterrows():
    src = row['local']
    dst = row['remote']
    G.add_edge(src, dst, pid=row['pid'], label=row['process_name'])

plt.figure(figsize=(12, 8))
pos = nx.spring_layout(G, k=0.5)
nx.draw_networkx_nodes(G, pos, node_size=300)
nx.draw_networkx_edges(G, pos)
nx.draw_networkx_labels(G, pos, font_size=8)
plt.title('Граф сетевых соединений, извлечённых из дампа памяти')
plt.axis('off')
plt.show()

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

7. Интеграция с SIEM и Osquery

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

7.1 Filebeat + Elasticsearch + Kibana

  1. Установите Filebeat на сервер аналитики или отдельную машину.

  2. В filebeat.yml задайте input для папки с CSV:

    filebeat.inputs:
    - type: log
      enabled: true
      paths:
        - /opt/memory_analysis/*.csv
      fields:
        source: memory_forensics
    
  3. Настройте Ingest Pipeline в Elasticsearch, чтобы парсить CSV-строки и преобразовывать поля pid, local, remote в отдельные атрибуты.

  4. В Kibana создайте дашборды: карта сети, гистограмму количества открытых соединений по PID, таблицу LSA secrets с возможностью фильтрации по имени.

7.2 Расширение Osquery

Osquery поддерживает плагины-расширения, написанные на Python. Можно адаптировать наш скрипт как extension, отвечающий на SQL-запросы:

SELECT pid, process_name, local, remote, state FROM memory_sessions;
SELECT name, value FROM memory_lsa_secrets;

Для этого используется библиотека osquery-extension-sdk и регистрация таблиц с колбэк-функциями, возвращающими строки из JSON-файла.

8. Защита дампов памяти и рекомендации по безопасности

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

  • Шифрование и контроль доступа. Храните дампы только во внутренних сегментах, с правами доступа по принципу наименьших привилегий. Используйте BitLocker, VeraCrypt или LUKS для шифрования каталогов с анализируемыми образами.
  • Журналы аудита. Любое чтение или копирование файлов дампа должно фиксироваться службой аудита ОС и перенаправляться в SIEM. Анализ этих логов позволит выявить попытки несанкционированного доступа.
  • Изоляция среды. Привилегированные исследовательские машины должны быть физически либо виртуально отделены от продакшена. Запускать анализ только на стендах, подготовленных для этой цели.
  • Автоматическое удаление устаревших дампов. Настройте скрипт очистки, удаляющий образы старше заранее установленного периода (например, 7–14 дней). Это предотвратит накопление конфиденциальной информации без надобности.
  • Сегментация сети. Храните дампы в недоступном для внешних сетей хранилище, ограничьте доступ с помощью VLAN и межсетевых экранах.

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