• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Играем в (Windows) песочнице

Azrv3l

win32kfull
Эксперт
Регистрация
30.03.2019
Сообщения
215
Реакции
539
Исследование от: Alex Ilgayev

Введение
Два года назад Microsoft выпустила новую функцию в составе сборки Insiders build 18305Windows Sandbox.

У этой песочницы есть несколько полезных характеристик:
  • Интегрированная часть Windows 10 (Pro / Enterprise).
  • Работает поверх виртуализации Hyper-V.
  • Безупречный и одноразовый - запускается с чистого листа при каждом запуске и не имеет постоянного состояния.
  • Настраивается с помощью файла конфигурации, имеющего специальный формат (формат WSB). Вы можете настроить сеть, vGPU, сопоставленные папки, автоматический сценарий для запуска при входе пользователя в систему и многие другие параметры.
  • Развертывание основано на технологии контейнеров Windows.
Судя по сопутствующему техническому сообщению, мы можем сказать, что Microsoft достигла важной технической вехи. В результате песочница представляет лучшее из обоих миров: с одной стороны, песочница основана на технологии Hyper-V, что означает, что она наследует строгую безопасность виртуализации Hyper-V. С другой стороны, песочница содержит несколько функций, которые позволяют совместно использовать ресурсы с хост-машиной, чтобы снизить потребление ресурсов ЦП и памяти.

Одна из интересных особенностей имеет особое значение, и мы подробно остановимся на ней здесь.

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

1.jpg


Мы решили углубиться в эту технологию по нескольким причинам:
  • Отсутствие документации по его внутренним техническим особенностям, как официальной, так и от сообщества. Хотя он сочетает в себе две широко задокументированные технологии (контейнеры Windows и Hyper-V), нам все еще не известно, как все это работает вместе. Например, в техническом блоге упоминается технология контейнеров Windows, но в официальной документации создание контейнеров Windows и управление ими осуществляется с помощью утилиты Docker для Windows, которая не используется в Windows Sandbox.
  • К сожалению, Microsoft не позволяет настраивать песочницу, кроме настройки файла WSB. Это означает, что мы не можем установить какую-либо программу, требующую перезагрузки, или создать собственный базовый образ для песочницы.
В этой статье мы разберем несколько компонентов, последовательность выполнения, поддержку драйверов и схему реализации функции динамического изображения. Мы покажем, что задействовано несколько внутренних технологий, таких как настраиваемый тег повторной обработки NTFS, многоуровневое распределение VHDx, конфигурация контейнера для надлежащей изоляции, драйверы виртуального хранилища, vSMB через VMBus и многое другое. Мы также создадим настраиваемую песочницу FLARE VM для анализа вредоносных программ, время запуска которой составляет всего 10 секунд!

Основные компоненты
Сложная экосистема Hyper-V и ее модулей уже широко исследована. Было обнаружено несколько уязвимостей, таких как VmSwitch RCE, который может вызвать полный переход от гостя к хосту. Несколько лет назад Microsoft представила контейнеры Windows (в основном для серверов), функцию, которая позволяла запускать Docker изначально в Windows, чтобы упростить развертывание программного обеспечения.

Обе эти технологии также были представлены на платформе конечных точек Windows 10 в виде двух компонентов: WDAG (Application Guard в Защитнике Windows) и, совсем недавно, Windows Sandbox. В последнее время WDAG и еще одна интересная функция для изоляции Office были объединены в MDAG - Microsoft Defender Application Guard.

На конференции POC2018 Юнхай Чжан представил презентацию, в которой он подробно остановился на архитектуре и внутреннем устройстве WDAG. Как мы демонстрируем, Windows Sandbox использует те же технологии для своей базовой реализации.

Песочницу можно разделить на три компонента: две службы - CmService.dll и vmcompute.exe - и созданный рабочий процесс vmwp.exe.

2.jpg


Подготовка песочницы
У каждой виртуальной машиной на базе Hyper-V есть файл VHDx, виртуальный диск, который используется машиной. Чтобы понять, как создается диск, мы посмотрели на рабочую папку активно запущенной песочницы:
%PROGRAMDATA%\Microsoft\Windows\Containers. Удивительно, но мы нашли более 8 файлов VHDx.

3.jpg


Мы можем отслеживать основной файл VHDx по его динамическому размеру по следующему пути - Sandboxes\29af2772-55f9-4540-970f-9a7a9a6387e4\sandbox.vhdx, где GUID генерируется случайным образом при каждом запуске песочницы.

Когда мы вручную монтируем файл VHDx, мы видим, что большая часть его файловой системы отсутствует (это явление также видно в исследовании WDAG Чжана, упомянутом ранее).

4.jpg


Мы сразу видим знак «X» на значке папки. Если мы включим столбец «атрибуты» в проводнике, мы увидим два необычных атрибута NTFS. Это объясняется здесь:

O – Offline

L – Reparse Point


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

Чтобы понять, на что указывает повторная обработка и что там, мы углубимся в структуру NTFS.

Исследование записи MFT
В главной таблице файлов (MFT) хранится информация, необходимая для извлечения файлов из раздела NTFS. Файл может иметь одну или несколько записей MFT и один или несколько атрибутов. Мы можем запустить популярный инструмент форензики Volatility с опцией mftparser для анализа всех записей MFT в базовой файловой системе. Это можно сделать с помощью следующей команды:
Код:
volatility.exe -f sandbox.vhdx mftparser --output=body -D output --output-file=sandbox.body

Когда мы ищем в выходных данных запись kernel32.dll (образец системного файла), мы встречаем следующий текст:
Код:
0|[MFT FILE_NAME] Windows\System32\kernel32.dll (Offset: 0x3538c00)|1251|---a---S--o----|0|0|764456|1604310972|1596874670|1603021550|1596874670
0|[MFT STD_INFO] Windows\System32\kernel32.dll (Offset: 0x3538c00)|1251|---a---Sr-o----|0|0|764456|1606900209|1596874670|1603021550|1596874670

Мы можем видеть такие же атрибуты повторной обработки («S») и офлайн («o»), что и раньше, но Volatility не дает нам никакой дополнительной информации. Мы можем использовать смещение записи MFT, 0x3538c00, для запуска собственного ручного синтаксического анализа.

Для анализа мы использовали следующую документацию NTFS. Мы не предоставляем полную спецификацию формата MFT, но, проще говоря, записи MFT содержат переменное количество атрибутов, и каждый из них имеет свой собственный заголовок и полезную нагрузку. Мы ищем атрибут $REPARSE_POINT, который определяется порядковым номером 0xC0.

5.jpg


6.jpg


Наши усилия по синтаксическому анализу со структурами, перечисленными выше, дают следующие данные:
Код:
$REPARSE_POINT Attribute
--------------- Attribute Header ---------------
C0 00 00 00 - Type ($REPARSE_POINT)
78 00 00 00 - Length
00          - Non-resident flag
00          - Name length
00 00       - Offset to the name
00 00       - Flags
03 00       - Attribute Id (a)
5C 00 00 00 - Length of the attribute
18 00       - Offset to the attribute
00          - Indexed flag
00          - Padding
---------------- Attribute Data ----------------
18 10 00 90 - Reparse tag
54 00       - Reparse data length
00 00       - Padding
----------------- Reparse Data -----------------
01 00 00 00 - Version ?
00 00 00 00 - Reserved ?
77 F6 64 82 B0 40 A5 4C BF 9A 94 4A C2 DA 80 87 - Referenced GUID
3A 00       - Path string size
57 00 69 00 6E 00 64 00 6F 00 77 00 73 00 5C 00
53 00 79 00 73 00 74 00 65 00 6D 00 33 00 32 00
5C 00 6B 00 65 00 72 00 6E 00 65 00 6C 00 33 00
32 00 2E 00 64 00 6C 00 6C 00 - Path string

Несколько важных замечаний:
  • Мы не нашли общедоступной документации по структуре данных повторного анализа Microsoft, но отреверсить ее было несложно.
  • Тег повторной обработки 0x90001018 определяется здесь как IO_REPARSE_TAG_WCI_1 со следующим описанием:
«Используется фильтром изоляции контейнеров Windows. Только интерпретация на стороне сервера, не имеет смысла по сети».
  • При реверсинге модулей Windows в этом исследовании мы несколько раз сталкивались с указанным GUID 77 F6 64 82 B0 40 A5 4C BF 9A 94 4A C2 DA 80 87 как жестко закодированным значением. Это значение указывает ссылку на базовый уровень хоста, о котором мы поговорим позже.
  • Путь в данных повторной обработки показывает относительный путь к нашему образцу файла: Windows\System32\kernel32.dll
Основываясь на приведенной выше информации, мы можем сделать вывод, что файлы «связаны» базовой файловой системой (вероятно, с назначенным фильтром FS), но многие вопросы все еще остаются без ответа: как создается VHDx, какова цель других VHDx, и какой компонент отвечает за связывание с файлами хоста.

Уровни VHDx
Если мы отследим журналы Procmon во время создания песочницы, мы замечаем серию попыток доступа к VHDx:

7.png


Хотя первый - это «настоящий» VHDx, который мы проанализировали ранее, за ним следуют 3 других доступа к VHDx. Мы подозреваем, что Microsoft использовала несколько слоев для шаблонов виртуальных дисков.

Нашу теорию легко проверить, проверив файлы VHDx с помощью двоичного редактора:

8.jpg


Родительский локатор в формате VHDx может быть задан несколькими способами: абсолютный путь, относительный путь и путь к тому. Документацию можно найти здесь

Обладая этими знаниями, мы можем построить следующие слои:
  • Sandboxes\<new_sandbox_guid>\sandbox.vhdx - «настоящий» VHDx.
  • Sandboxes\<constant_guid_per_installation>\sandbox.vhdx - создается один раз для каждой установки песочницы.
  • BaseImages\0949cec7-8165-4167-8c7d-67cf14eeede0\Snapshot\SnapshotSandbox.vhdx - Возможно, относится к моментальному образу базового уровня.
  • PortableBaseLayer\SystemTemplateBase.vhdx - Базовый шаблон.
Когда мы просматриваем эти виртуальные диски, мы замечаем, что файлы все еще отсутствуют; некоторые системные папки пусты, а также папки для пользователей / программных файлов и различных других файлов.

Игра с Procmon приводит нас к пониманию того, что отсутствует еще один важный уровень: базовый уровень ОС.

Базовый уровень ОС
Основной файл базового уровня ОС находится в рабочей папке песочницы по следующему пути:
BaseImages\0949cec7-8165-4167-8c7d-67cf14eeede0\BaseLayer.vhdx.

Посмотрев на процесс установки через Procmon, мы увидим, что следующий файл .wim (Windows Imaging Format):
C:\Windows\Containers\serviced\WindowsDefenderApplicationGuard.wim, извлекается в папку PortableBaseLayer с тем же именем и является скопирован и переименован в файл базового слоя выше.
Это показывает еще одно сходство между WDAG и Windows Sandbox.

Когда мы просматривали диск BaseLayer.vhdx, мы могли видеть полную структуру созданной песочницы, но системные файлы все еще «физически» отсутствовали. Анализ записи MFT для kernel32.dll, как мы делали ранее, приводит к тому же атрибуту $REPARSE_POINT, но с другим тегом: 0xA0001027: IO_REPARSE_TAG_WCI_LINK_1. Запомните этот тег на будущее.

9.jpg


Кроме того, когда мы запускаем команду mountvol, мы видим, что VHDx базового уровня монтируется в тот же каталог, где он существует:

10.jpg


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

Эта служба запускает исполняемый файл с именем cmimageworker.exe с одним из следующих параметров командной строки, expandpbl/deploy/clean, для выполнения этих действий.

11.jpg


Мы можем наблюдать вызов computestorage!HcsSetupBaseOSLayer в cmimageworker.exe и часть фактического создания базового уровня в computestorage.dll.

12.jpg


13.jpg


Microsoft выпустила следующее заявление относительно песочницы:
Код:
Это часть Windows - все, что требуется для этой функции, входит в состав Windows 10 Pro и Enterprise. Нет необходимости скачивать VHD!

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

Запуск песочницы
Запуск приложения Windows Sandbox запускает поток выполнения, здесь мы не будем вдаваться в подробности. Мы просто упомянем, что поток приводит к тому, что CmService выполняет vmcompute!HcsRpc_CreateSystem через вызов RPC. Другая важная служба, vmcompute.exe, запускает и координирует все вычислительные системы (контейнеры) на хосте.

В нашем случае команда CreateSystem также получает следующий конфигурационный JSON, который описывает желаемую машину:

Примечание - JSON вырезан для удобства чтения. Вы можете получить доступ к полному JSON в Приложении A.
JSON:
{
    "Owner": "Madrid",
        ...
    "VirtualMachine": {
                ...
        "Devices": {
            "Scsi": {
                "primary": {
                    "Attachments": {
                        "0": {
                            "Type": "VirtualDisk",
                            "Path": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\Sandboxes\\025b00c8-849a-4e00-bcb2-c2b8ec698bab\\sandbox.vhdx",
                                                        ...
                        }
                    }
                }
            },
                        ...
            "VirtualSmb": {
                "Shares": [{
                    "Name": "os",
                    "Path": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\BaseImages\\0949cec7-8165-4167-8c7d-67cf14eeede0\\BaseLayer\\Files",
                                        ...
                }],
`            },
                        ...
        },
                ...
        "RunInSilo": {
            "SiloBaseOsPath": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\BaseImages\\0949cec7-8165-4167-8c7d-67cf14eeede0\\BaseLayer\\Files",
            "NotifySiloJobCreated": true,
            "FileSystemLayers": [{
                "Id": "8264f677-40b0-4ca5-bf9a-944ac2da8087",
                "Path": "C:\\",
                "PathType": "AbsolutePath"
            }]
        },
                ...
    },
        ...
}

Этот JSON создается в CmService!Container::Manager::Hcs::Details::GenerateCreateComputeSystemJson. Нам не удалось отследить ни один файл, который помогает построить эту конфигурацию.

Прежде чем мы начнем анализировать интересные поля в JSON, мы хотим упомянуть эту статью Palo Alto Networks. В статье рассказывается о внутреннем устройстве контейнера и о том, как связаны объекты Job и Silo.

Первый интересный тег конфигурации - RunInSilo. Этот тег запускает поток кода в vmcompute, который приводит нас к следующей трассировке стека:
Код:
3: kd> k
# Child-SP          RetAddr               Call Site
00 ffff9a00`8da57648 fffff806`85d2b7fb     wcifs!WcPortMessage
01 ffff9a00`8da57650 fffff806`85d63499     FLTMGR!FltpFilterMessage+0xdb
... (REDUCTED)
0b 0000004d`4218dbf0 00007ffa`08c5363d     FLTLIB!FilterSendMessage+0x31
0c 0000004d`4218dc40 00007ffa`08c48686     wc_storage!WciSetupFilter+0x195
0d 0000004d`4218dcf0 00007ffa`22e06496     wc_storage!WcAttachFilterEx+0x156
0e 0000004d`4218dee0 00007ffa`22de5a66     container!container::FilesystemProvider::Setup+0x15e
0f 0000004d`4218dfc0 00007ffa`22ded4ad     container!container_runtime::CreateContainerObject+0x106
10 0000004d`4218e010 00007ffa`22decf3c     container!container::CreateContainer+0x10d
11 0000004d`4218e4a0 00007ff6`fcf0bc7f     container!WcCreateContainer+0x1c
12 0000004d`4218e4d0 00007ff6`fcf0c5c4     vmcompute!ComputeService::JobUtilities::ConvertJobObjectToContainer+0xcb
13 0000004d`4218e590 00007ff6`fce8573f     vmcompute!ComputeService::JobUtilities::CreateSiloForIsolatedWorkerProcess+0x4dc
14 0000004d`4218e8c0 00007ff6`fce875c5     vmcompute!ComputeService::Management::Details::PrepareJobForWorkerProcess+0x17b
15 0000004d`4218e9a0 00007ff6`fcee6cbb     vmcompute!ComputeService::Management::Details::ConstructVmWorker+0xfd5
... (REDUCTED)

Из стека мы можем понять, что всякий раз, когда вычислительная система получает конфигурацию разрозненного хранилища, она создает и настраивает контейнер с помощью вызова container!WcCreateContainer. В рамках своей конфигурации он также взаимодействует с драйвером wcifs.sys через FLTLIB!FilterSendMessage. Мы вскоре объясним что это за драйвер и в чём его назначение.

Вторая интересная особенность - это тег VirtualSmb для создания соответствующих общих ресурсов для смонтированного пути базового уровня, о котором мы упоминали ранее. Мы скоро вернемся к этому.

Изоляция контейнеров
Как видно из трассировки стека, создание контейнера включает открытие канала связи фильтра на порт \WcifsPort с помощью драйвера wcifs.sys, драйвера фильтра Windows Container Isolation FS Filter. Это распространенный метод взаимодействия кода пользовательского режима с драйверами фильтров.

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

Драйверы фильтров файловой системы обычно довольно сложные, и этот не исключение. К счастью, Джеймс Форшоу из Google Project Zero недавно написал отличную статью, в которой объясняется низкоуровневый дизайн драйверов фильтров Windows FS, что помогает нам понять логику в нашем случае.

Логику драйвера можно разделить на 2 части:
  • Конфигурация драйвера - Конфигурация зависит от того, работает ли драйвер в гостевой или хост-системе.
  • Обработка обратных вызовов операций, таких как WcPreCreate, WcPostCreate, WcPreRead и WcPostRead. Эти обратные вызовы содержат основную логику, манипулирование данными и правильные перенаправления.
Мы объясним некоторые методы, которые использует этот драйвер для понимания экосистемы песочницы.

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

Гость получает через реестр набор параметров для первоначальной настройки. Некоторые из этих параметров находятся в HKLM\SYSTEM\CurrentControlSet\Control и HKLM\SYSTEM\CurrentControlSet\Control\BootContainer, как мы можем видеть ниже:

14.jpg


15.jpg


Вы могли заметить IO_REPARSE_TAG_WCI_1 (код 0x90001018), который мы видели ранее в «реальном» файле VHDx. Этот тег вместе с IO_REPARSE_TAG_WCI_LINK_1, который мы видели как тег повторной обработки в BaseLayer.vhdx, жестко запрограммирован в методе wcifs!WcSetBootConfiguration:

16.jpg


Вторая, более важная часть гостевой конфигурации находится в wcifs!WcSetupVsmbUnionContext, где он устанавливает виртуализированный уровень, известный как объединенный контекст. За кулисами драйвер хранит настроенные данные о нескольких объектах контекста и обращается к ним с помощью соответствующего NT API - FltGetInstanceContext, PsGetSiloContext и FltGetFileContext. Эти настраиваемые объекты содержат деревья AVL и хэш-таблицы для эффективного поиска виртуализированных слоев.

У метода WcSetupVsmbUnionContext есть еще два интересных артефакта. Один - это путь vSMB, который является частью уровня, а другой - GUID HOST_LAYER_ID, который мы видели ранее в проанализированном MFT и в JSON, который описывает виртуальную машину:

17.jpg


18.jpg


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

Конфигурация хоста
Для хост-системы основная конфигурация происходит, когда родительский вычислительный процесс, vmcompute, инициирует создание контейнера и отправляет настраиваемое сообщение в \WcifsPort. Это запускает wcifs!WcPortMessage, который представляет собой процедуру обратного вызова для любого сообщения, отправляемого на этот конкретный порт.

Ниже приведена частичная реконструкция сообщения, отправленного службой драйверу фильтра:
Код:
struct WcifsPortMsg
{
  DWORD MsgCode;
  DWORD MsgSize;
  WcifsPortMsgSetUnion Msg;
};

struct WcifsPortMsgSetUnion
{
  DWORD MsgVersionOrCode;
  DWORD MsgSize;
  DWORD NumUnions;
  wchar_t InstanceName[50];
  DWORD InstanceNameLen;
  DWORD ReparseTag;
  DWORD ReparseTagLink;
  DWORD NotSure;
  HANDLE Job;
  BYTE ContextData[1];
};

Поле ContextData также содержит пути к устройствам, которые объединение должно отображать.

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

19.jpg


Не вдаваясь в технические детали, драйвер определяет и заботится о двух настраиваемых тегах повторной обработки:
  • IO_REPARSE_TAG_WCI_1 - это основной тег, который указывает, что экземпляр файла на диске является виртуальным, а реальный путь можно найти в его внутренних структурах. Примеры использования этого «преобразования»:
    • Гость конвертирует файлы из собственного пути C:\Windows\system32\kernel32.dll в путь vSMB\Device\vmsmb\VSMB- {dcc079ae-60ba-4d07-847c-3493609c0870}\os\Windows\System32\kernel32.dll.
    • Хост преобразует файлы из пути устройства базового уровня C:\ProgramData\Microsoft\Windows\Containers\BaseImages\0949cec7-8165-4167-8c7d-67cf14eeede0\BaseLayer\Files\Windows\System32\en-US\apphelp.dll.mui на реальный путь C:\Windows\System32\en-US\apphelp.dll.mui. Это преобразование довольно интересно, поскольку оно происходит в основном в пустых системных папках на базовом уровне, которые содержат этот тег повторной обработки (например, в папке en-US).
  • IO_REPARSE_TAG_WCI_LINK_1 - этот тег используется только на хосте, насколько мы можем судить, и связывает системные файлы из пути к устройству базового уровня C:\ProgramData\Microsoft\Windows\Containers\BaseImages\0949cec7-8165-4167-8c7d-67cf14eeede0\BaseLayer\Files\Windows\System32\kernel32.dll на реальный путь C:\Windows\System32\kernel32.dll. По сравнению с предыдущим пунктом, в этом примере запись файла DLL существует на базовом уровне и имеет этот тег повторной обработки.
Открытие того, что vSMB является основным методом совместного использования базового уровня ОС, было весьма неожиданным. Теперь, когда мы знаем, что это важнейший метод коммуникации в экосистеме, следующий естественный шаг - копнуть глубже.

(v)SMB File Sharing

Во время установки в песочнице мы заметили, что vmcompute создает несколько виртуальных общих ресурсов, вызывая CreateFileW на устройство поставщика хранилища и отправляя IOCTL 0x240328. Пример пути для такого вызова может выглядеть так: \??\STORVSP\VSMB\??\C:\ProgramData\Microsoft\Windows\Containers\BaseImages\0949cec7-8165-4167-8c7d-67cf14eeede0\BaseLayer\Files

Эти общие ресурсы создаются методом vmcompute!ComputeService::Storage::OpenVsmbRootShare. Мы можем увидеть его поток в следующей трассировке стека:
Код:
3: kd> k
# Child-SP          RetAddr               Call Site
00 ffff9a00`8d48a178 fffff806`85fd6af8     storvsp!VspFileCreate
01 (Inline Function) --------`--------     Wdf01000!FxFileObjectFileCreate::Invoke+0x29 [minkernel\wdf\framework\shared\inc\private\common\FxFileObjectCallbacks.hpp @ 58]
... (REDUCTED)
11 0000004d`4210d690 00007ff6`fcf33700     KERNELBASE!CreateFileW+0x66
12 0000004d`4210d6f0 00007ff6`fceb8180     vmcompute!ComputeService::Storage::OpenVsmbRootShare+0x3ac
13 0000004d`4210d850 00007ff6`fceba0fc     vmcompute!ComputeService::VirtualMachine::Details::ConfigureVSMB+0x598
14 0000004d`4210da30 00007ff6`fceba908     vmcompute!ComputeService::VirtualMachine::Details::InitializeDeviceSettings+0x918
15 0000004d`4210eb90 00007ff6`fce86abd     vmcompute!ComputeService::VirtualMachine::CreateVirtualMachineConfiguration+0x68
16 0000004d`4210ebe0 00007ff6`fcee6cbb     vmcompute!ComputeService::Management::Details::ConstructVmWorker+0x4cd
... (REDUCTED)

Кроме того, когда мы сопоставляем папки хоста с гостевой системой, используя конфигурацию файла WSB, вызывается тот же метод. Например, сопоставление папки Sysinternals приводит к следующему вызову драйвера:
\??\STORVSP\VSMB\??\C:\Users\hyperv-root\Desktop\SysinternalsSuite.

Доступ к файлам через (v)SMB
После создания этих общих ресурсов мы можем получить к ним доступ в гостевой системе через созданный псевдоним. Мы можем использовать команду type для печати kernel32.dll хоста по следующему пути:
\\.\Vmsmb\VSMB-{dcc079ae-60ba-4d07-847c-3493609c0870}\os\Windows\System32\kernel32.dll

20.jpg


Для обслуживания файлов vSMB модуль vmusrv, который является частью рабочего процесса виртуальной машины, создает рабочий поток. Этот модуль представляет собой vSMB-сервер пользовательского режима, который запрашивает пакеты непосредственно из VMBus в подпрограмме vmusrv!VSmbpWorkerRecvLoop, а затем приступает к их обработке.

Обслуживание операции создания файла
Каждый раз, когда vmusrv получает запрос Create SMB, он инициирует новый запрос к драйверу поставщика хранилища. Такой вызов может выглядеть так:
Код:
2: kd> k
# Child-SP          RetAddr               Call Site
... (REDUCTED)
0c ffff9a00`8d9522e0 fffff806`892c4741     storvsp!VspVsmbCommonRelativeCreate+0x369
0d ffff9a00`8d952510 fffff806`892c3b7e     storvsp!VspVsmbHandleRelativeCreateFileRequest+0x321
0e ffff9a00`8d952790 fffff806`892c0f85     storvsp!VspVsmbDispatchIoControlForProcess+0x11e
0f ffff9a00`8d9527e0 fffff806`8100e522     storvsp!VspFastIoDeviceControl+0x175
... (REDUCTED)
13 000000ae`9c0ff298 00007ffa`110c0c0a     ntdll!NtDeviceIoControlFile+0x14
14 000000ae`9c0ff2a0 00007ffa`110c0456     vmusrv!CShare::OpenFileRelativeToShareRootInternal+0x306
15 000000ae`9c0ff3e0 00007ffa`110b9381     vmusrv!CShare::OpenFileRelativeToShareRoot+0x356
16 000000ae`9c0ff510 00007ffa`110b4451     vmusrv!CFSObject::CreateFileW+0x185
17 000000ae`9c0ff690 00007ffa`1109a568     vmusrv!CShare::Create+0x91
18 000000ae`9c0ff740 00007ffa`1109d74d     vmusrv!ProviderCallback_Create+0x30
19 000000ae`9c0ff780 00007ffa`1109c299     vmusrv!SrvCreateFile+0x331
1a 000000ae`9c0ff860 00007ffa`1109c6f0     vmusrv!Smb2ExecuteCreateReal+0x111
1b 000000ae`9c0ff940 00007ffa`110a08da     vmusrv!Smb2ExecuteCreate+0x30
1c 000000ae`9c0ff970 00007ffa`11098907     vmusrv!Smb2ExecuteProviderCallback+0x7e
1d 000000ae`9c0ff9d0 00007ffa`11088311     vmusrv!Smb2PacketProcessing+0x97
1e 000000ae`9c0ffa40 00007ffa`11087225     vmusrv!Smb2PacketProcessingCallback+0x11
... (REDUCTED)

Связь с поставщиком хранилища осуществляется через IOCTL с кодом 0x240320, а указанным дескриптором является путь vSMB, открытый на этапе инициализации:

21.jpg


Если мы внимательно посмотрим на storvsp!VspVsmbCommonRelativeCreate, мы увидим, что каждое выполнение сопровождается вызовом nt!IoCreateFileEx. Этот вызов содержит относительный путь к желаемому файлу с дополнительным полем RootDirectory, которое представляет папку \Files в смонтированном базовом уровне VHDx:

22.jpg


Обслуживание операции чтения/записи
Операции чтения/записи выполняются рабочим потоком в vmusrv!CFSObject :: Read/vmusrv!CFSObject::Write. Если файл достаточно мал, поток просто выполняет ReadFile/WriteFile для дескриптора. В противном случае он отображает файл в память и эффективно передает его через RDMA поверх VMBus. Эта передача выполняется в vmusrv!SrvConnectionExecuteRdmaTransfer, в то время как обмен данными по RDMA осуществляется с устройством RootVMBus (имя хост-устройства VMBus) с использованием IOCTL 0x3EC0D3 или 0x3EC08C.
Код:
2: kd> k
... (REDUCTED)
06 ffffad0e`3bee7650 fffff800`36225b62     vmbusr!RootIoctlRdmaFileIoHandleMappingComplete+0x10f
07 ffffad0e`3bee7690 fffff800`361fee21     vmbusr!RootIoctlRdmaFileIo+0xf2
08 ffffad0e`3bee76f0 fffff800`339da977     vmbusr!RootIoctlDeviceControlPreprocess+0x191
... (REDUCTED)
12 00000009`ae27f7e8 00007ffe`281ce773     ntdll!NtDeviceIoControlFile+0x14
13 00000009`ae27f7f0 00007ffe`281dcbd2     vmusrv!SrvConnectionExecuteRdmaTransfer+0x24f
14 00000009`ae27f940 00007ffe`281d4874     vmusrv!CFile::ReadFileRdma+0xc2
15 00000009`ae27f9c0 00007ffe`281c218e     vmusrv!CFSObject::Read+0x94
16 00000009`ae27fa00 00007ffe`281c08da     vmusrv!Smb2ExecuteRead+0x1be
17 00000009`ae27fa60 00007ffe`281b8907     vmusrv!Smb2ExecuteProviderCallback+0x7e
18 00000009`ae27fac0 00007ffe`281a6a4e     vmusrv!Smb2PacketProcessing+0x97
19 00000009`ae27fb30 00007ffe`3bba6fd4     vmusrv!SmbWorkerThread+0xce
... (REDUCTED)

23.jpg


Поток Гость-Хост
Основываясь на некоторых выводах из этой статьи, объясняющих взаимосвязь Storvsc.sys/Storvsp.sys, мы можем объединить все предыдущие технические блоки в следующий поток доступа к файлам.

24.jpg


  1. Мы используем команду type, чтобы открыть и распечатать содержимое файла kernel32.dll. Это системный файл, поэтому песочнице не принадлежит его копия, а используется копия хоста.
  2. Гость не знает, что файл не существует, поэтому он выполняет обычный доступ к файлу через стек драйверов файловой системы вплоть до стека драйверов хранилища.
  3. Потребитель хранилища Hyper-V Storvsc.sys является драйвером минипорта, что означает, что он действует как виртуальное хранилище для гостя. Он принимает и пересылает запросы SCSI по шине VMBus.
  4. У поставщика хранилища Storvsp.sys есть рабочий поток, ожидающий новых сообщений через VMBus на storvsp!VspPvtKmclProcessingComplete.
  5. Провайдер анализирует запрос VMBus и передает его vhdparser!NVhdParserExecuteScsiRequestDisk, который выполняет vhdmp.sys, драйвер парсера VHD.
  6. В конце концов, vhdmp.sys обращается к физическому экземпляру sandbox.vhdx через диспетчер фильтров и выполняет операцию чтения/записи. В этом случае он считывает данные, запрошенные менеджером фильтров гостевой файловой системы. Эти данные возвращаются диспетчеру фильтров для дальнейшего анализа.
  7. Как объяснялось ранее, возвращенная запись помечается тегом повторной обработки WCI и GUID уровня хоста. Когда wcifs.sys выполняет операцию пост-создания для файла, он ищет контекст объединения для этого устройства и заменяет файловый объект следующим: \Device\vmsmb\VSMB-{dcc079ae-60ba-4d07-847c- 3493609c0870}\os\Windows\System32\kernel32.dll
  8. Устройство \Device\vmsmb было создано как общий ресурс SMB, поэтому диспетчер фильтров обращается к нему, как к любому другому обычному общему ресурсу. Незаметно для себя он выполняет SMB-запросы к хосту через VMBus.
  9. Сервер vSMB пользовательского режима vmusrv.dll опрашивает устройство \\.\VMbus\ на наличие новых сообщений в своем методе рабочего потока vmusrv!SmbWorkerThread.
  10. Как мы показали ранее, в операции создания сервер связывается с поставщиком хранилища через IOCTL на дескрипторе смонтированного базового уровня ОС: \Device\STORVSP\VSMB\??\C:\ProgramData\Microsoft\Windows\Containers\BaseImages\0949cec7-8165-4167-8c7d-67cf14eeede0\BaseLayer\Files
  11. Провайдер хранилища выполняет запрос файла через IoCreateFileEx. Этот запрос является относительным и содержит RootDirectory смонтированного уровня ОС. Это заставляет диспетчер фильтров открыть файл на смонтированном уровне ОС.
  12. Подобно шагу (7), возвращенная запись содержит тег повторной обработки WCI, который заставляет wcifs.sys изменять объект файла в методе пост-создания. Он изменяет файловый объект на его физический путь: C:\Windows\System32\kernel32.dll
  13. Получает доступ к файлу ядра kernel32.dll и возвращается к гостю.
  14. Для операции ReadFile драйвер wcifs.sys сохраняет состояние контекста поверх объекта файла, чтобы помочь ему выполнить операцию чтения/записи. Кроме того, рабочий поток vmusrv выполняет запрос чтения либо с прямым доступом к файлу, либо через RDMA поверх VMBus.
Фактический процесс намного сложнее, поэтому мы постарались сосредоточиться на компонентах, имеющих решающее значение для виртуализации.

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

Например, если мы сопоставим папку SysinternalsSuite с папкой гостевого рабочего стола, путь C:\Users\WDAGUtilityAccount\Desktop\SysinternalsSuite\Procmon.exe изменится на \Device\vmsmb\VSMB-{dcc079ae-60ba-4d07-847c- 3493609c0870}\db64085bcd96aab59430e21d1b386e1b37b53a7194240ce5e3c25a7636076b67\Procmon.exe, при этом остальная часть процесса останется прежней.

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

Модификация состоит из нескольких простых шагов:
  1. Остановите CmService, службу, которая создает и поддерживает базовый уровень. При выгрузке сервиса снимается и монтирование базового уровня.
  2. Смонтируйте базовый слой (он находится в файле C:\ProgramData\Microsoft\Windows\Containers\BaseImages\0949cec7-8165-4167-8c7d-67cf14eeede0\BaseLayer.vhdx). Это можно сделать двойным щелчком или с помощью утилиты diskmgmt.msc.
  3. Внесите изменения в базовый слой. В нашем случае мы добавили все файлы установки FLARE.
  4. Размонтируйте базовый слой.
  5. Запустите CmService.
В тот момент, когда мы запускаем песочницу, у нас есть потрясающая виртуальная машина FLARE!

25.jpg


Итоги
Когда мы начали исследовать Windows Sandbox, мы понятия не имели, что такая «простая» операция сводится к сложному потоку с несколькими внутренними недокументированными технологиями Microsoft, такими как vSMB и Container Isolation.

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

Если вы хотите получить обратную связь, напишите нам в twitter.

Ссылки
Дополнение А
Конфигурация Windows Sandbox JSON для vmwp
JSON:
{
    "Owner": "Madrid",
    "SchemaVersion": {
        "Major": 2,
        "Minor": 1
    },
    "VirtualMachine": {
        "StopOnReset": true,
        "Chipset": {
            "Uefi": {
                "BootThis": {
                    "DeviceType": "VmbFs",
                    "DevicePath": "\\EFI\\Microsoft\\Boot\\bootmgfw.efi"
                }
            }
        },
        "ComputeTopology": {
            "Memory": {
                "SizeInMB": 1024,
                "Backing": "Virtual",
                "BackingPageSize": "Small",
                "FaultClusterSizeShift": 4,
                "DirectMapFaultClusterSizeShift": 4,
                "EnablePrivateCompressionStore": true,
                "EnableHotHint": true,
                "EnableColdHint": true,
                "SharedMemoryMB": 2048,
                "SharedMemoryAccessSids": ["S-1-5-21-2542268174-3140522643-1722854894-1001"],
                "EnableEpf": true,
                "EnableDeferredCommit": true
            },
            "Processor": {
                "Count": 4,
                "SynchronizeHostFeatures": true,
                "EnableSchedulerAssist": true
            }
        },
        "Devices": {
            "Scsi": {
                "primary": {
                    "Attachments": {
                        "0": {
                            "Type": "VirtualDisk",
                            "Path": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\Sandboxes\\025b00c8-849a-4e00-bcb2-c2b8ec698bab\\sandbox.vhdx",
                            "CachingMode": "ReadOnlyCached",
                            "NoWriteHardening": true,
                            "DisableExpansionOptimization": true,
                            "IgnoreRelativeLocator": true,
                            "CaptureIoAttributionContext": true
                        }
                    }
                }
            },
            "HvSocket": {
                "HvSocketConfig": {
                    "DefaultBindSecurityDescriptor": "D:P(A;;FA;;;SY)",
                    "DefaultConnectSecurityDescriptor": "D:P(A;;FA;;;SY)",
                    "ServiceTable": {
                        "befcbc10-1381-45ab-946e-b1a12d6bce94": {
                            "BindSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "ConnectSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "AllowWildcardBinds": true
                        },
                        "7d2e0620-034a-4438-b0fd-ae27fc0172a1": {
                            "BindSecurityDescriptor": "D:P(A;;FA;;;SY)(A;;FA;;;S-1-5-83-0)",
                            "ConnectSecurityDescriptor": "D:P(D;;FA;;;WD)"
                        },
                        "a715ac94-b745-4889-9a0f-772d85a3cfa4": {
                            "BindSecurityDescriptor": "D:P(A;;FA;;;LS)",
                            "ConnectSecurityDescriptor": "D:P(A;;FA;;;LS)",
                            "AllowWildcardBinds": true
                        },
                        "7b3014c3-284a-40d4-a97f-9d23a75c6a80": {
                            "BindSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "ConnectSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "AllowWildcardBinds": true
                        },
                        "e97910d9-55bb-455e-9170-114fdfce763d": {
                            "BindSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "ConnectSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "AllowWildcardBinds": true
                        },
                        "e5afd2e3-9b98-4913-b37c-09de98772940": {
                            "BindSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "ConnectSecurityDescriptor": "D:P(D;;FA;;;WD)",
                            "AllowWildcardBinds": true
                        },
                        "abd802e8-ffcc-40d2-a5f1-f04b1d12cbc8": {
                            "BindSecurityDescriptor": "D:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;S-1-15-3-3)(A;;FA;;;S-1-5-21-2542268174-3140522643-1722854894-1001)",
                            "ConnectSecurityDescriptor": "D:P(D;;FA;;;WD)"
                        },
                        "f58797f6-c9f3-4d63-9bd4-e52ac020e586": {
                            "BindSecurityDescriptor": "D:P(A;;FA;;;SY)",
                            "ConnectSecurityDescriptor": "D:P(A;;FA;;;SY)",
                            "AllowWildcardBinds": true
                        }
                    }
                }
            },
            "EnhancedModeVideo": {
                "ConnectionOptions": {
                    "AccessSids": ["S-1-5-21-2542268174-3140522643-1722854894-1001"],
                    "NamedPipe": "\\\\.\\pipe\\025b00c8-849a-4e00-bcb2-c2b8ec698bab"
                }
            },
            "GuestCrashReporting": {
                "WindowsCrashSettings": {
                    "DumpFileName": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\Dumps\\025b00c8-849a-4e00-bcb2-c2b8ec698bab.dmp",
                    "MaxDumpSize": 4362076160,
                    "DumpType": "Full"
                }
            },
            "VirtualSmb": {
                "Shares": [{
                    "Name": "os",
                    "Path": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\BaseImages\\0949cec7-8165-4167-8c7d-67cf14eeede0\\BaseLayer\\Files",
                    "Options": {
                        "ReadOnly": true,
                        "TakeBackupPrivilege": true,
                        "NoLocks": true,
                        "ReparseBaseLayer": true,
                        "PseudoOplocks": true,
                        "PseudoDirnotify": true,
                        "SupportCloudFiles": true
                    }
                }],
                "DirectFileMappingInMB": 2048
            },
            "Licensing": {
                "ContainerID": "00000000-0000-0000-0000-000000000000",
                "PackageFamilyNames": []
            },
            "Battery": {},
            "KernelIntegration": {}
        },
        "GuestState": {
            "GuestStateFilePath": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\Sandboxes\\025b00c8-849a-4e00-bcb2-c2b8ec698bab\\sandbox.vmgs"
        },
        "RestoreState": {
            "TemplateSystemId": "97d51d87-c49d-488f-bc29-33017f7703b9"
        },
        "RunInSilo": {
            "SiloBaseOsPath": "C:\\ProgramData\\Microsoft\\Windows\\Containers\\BaseImages\\0949cec7-8165-4167-8c7d-67cf14eeede0\\BaseLayer\\Files",
            "NotifySiloJobCreated": true,
            "FileSystemLayers": [{
                "Id": "8264f677-40b0-4ca5-bf9a-944ac2da8087",
                "Path": "C:\\",
                "PathType": "AbsolutePath"
            }]
        },
        "LaunchOptions": {
            "Type": "None"
        },
        "GuestConnection": {}
    },
    "ShouldTerminateOnLastHandleClosed": true
}

От ТС
За оригиналом вам сюда.
Довольно подробное иследование от checkpoint, самому очень интересно было переводить.

Перевод:
Azrv3l cпециально для xss.pro
BTC: bc1qs2fk7zftnwwhhdrw9ge6ncxrspeyta7dymjwkj
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх