PowerShell — ключ, которым пользуются и админы, и атакующие

Пятый год подряд PowerShell входит в топ техник, которые Red Canary фиксирует у атакующих в реальных инцидентах. В отчёте за 2026 год — второе место. Не потому что PowerShell «взломан» или в нём дыра. А потому что он встроен в каждую Windows, его нельзя удалить, и он умеет дотянуться до всего: реестра, файлов, сети, памяти процессов, Active Directory.

Это и есть то, что в защите называют living off the land — «жить с земли». Не тащить с собой чужой инструмент, который поймает антивирус. Использовать то, что уже стоит в системе легально.

Если ты администрируешь Windows или просто интересуешься, как защищаются от таких атак — тебе нужно понимать PowerShell не как «чёрное окошко с командами», а как то, чем он на самом деле является.

Не CMD 2.0

Разница между CMD и PowerShell — как между сортировкой бумажных анкет по линейке и запросом в базу данных.

В CMD ты работаешь с текстом. Хочешь найти файл — берёшь строку вывода и ищешь в ней подстроку. Хочешь отсортировать процессы по памяти — команда sort считает символы слева направо и режет строку в заданной позиции. Если имя процесса длиннее обычного и сдвинуло колонку — сортировка ломается. Девятка окажется «больше» ста, потому что для текстовой сортировки «9» идёт после «1».

В PowerShell команда Get-Process возвращает не текст, а объекты. У каждого процесса есть свойство CPU — число, а не строка на экране. Когда ты пишешь Sort-Object CPU, PowerShell сравнивает именно это число, и ему всё равно, длинное имя у процесса или короткое. Данные и их отображение — это две разные вещи.

Отсюда и вся разница в возможностях. CMD показывает тебе текст. PowerShell даёт доступ к структуре системы.

Конвейер: команды передают друг другу не текст, а объекты

Ключевая идея PowerShell — конвейер (pipeline). Одна команда выдаёт объекты, следующая их фильтрует или сортирует, третья показывает результат.

powershell

Get-Process | Where-Object { $_.WorkingSet -gt 100MB } | Sort-Object WorkingSet -Descending

$_ — это «текущий объект в конвейере». $_.WorkingSet — его свойство, память в байтах. Ты не парсишь текст регулярками, как в CMD, — ты обращаешься к полю объекта напрямую.

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

Execution Policy — не защита

Многие думают, что Execution Policy защищает от вредоносных скриптов. Это не так, и Microsoft прямо пишет в документации: это не граница безопасности (security boundary).

Execution Policy не даёт случайно запустить скрипт двойным щелчком. От целенаправленной атаки она не защищает вообще:

powershell

powershell -ExecutionPolicy Bypass -File script.ps1

Или ещё проще — вставить код прямо в консоль. На прямой ввод политика не распространяется.

Реальная защита — это не запрет запуска, а видимость того, что было запущено.

Что реально ловит вредоносный PowerShell

AMSI (Antimalware Scan Interface) — встроенный в Windows стандарт, через который PowerShell отправляет содержимое скрипта антивирусу перед выполнением. Важный момент: проверка происходит уже после того, как код раскрыл сам себя — деобфусцировался. Поэтому обфускация сама по себе AMSI не обманывает.

Script Block Logging — записывает в журнал событий (Event ID 4104) реальный текст выполненного кода, уже в раскрытом виде. Без него расследовать инцидент постфактум почти невозможно: видно, что PowerShell запускался, но не видно, что он делал.

Constrained Language Mode — режим, в котором PowerShell разрешает только базовые команды и запрещает прямой вызов Win32 API и произвольных .NET-объектов. Включается автоматически, когда в системе работает AppLocker или WDAC в режиме Enforce — и это касается вообще всех, включая администраторов.

Три уровня защиты работают вместе: даже если атакующий обошёл один — остаются другие.

Что сделать прямо сейчас

  1. Проверь, какой у тебя языковой режим:

powershell

$ExecutionContext.SessionState.LanguageMode

Если не FullLanguage — значит, кто-то (возможно, ты сам) уже настроил ограничение.

  1. Проверь, включено ли логирование блоков скриптов:

powershell

Get-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"

Если команда выдаёт ошибку — значит, раздел реестра не создан, и логирование через GPO не настроено. Для домашней машины это норм. Для рабочей — стоит спросить у админа.

  1. Посмотри, какие антивирусы зарегистрированы как AMSI-провайдеры:

powershell

Get-ChildItem "HKLM:\SOFTWARE\Microsoft\AMSI\Providers"

Готовые скрипты в моём GitHub.