Пост имеет ознакомительный характер и предназначена для специалистов по безопасности. Автор и редакция не несут ответственности за любой вред, причиненный с применением изложенной информации. Распространение вредоносных программ, нарушение работы систем и нарушение тайны переписки преследуются по закону
Как-то вечером мне было скучно, и я начал играться со своим Defender, чтобы это не значило.
Если совсем просто AMSI - это как рамка металлодетектора, только для кода. Раньше антивирус смотрел только на файлы на диске. Но хакеры быстро сообразили, что можно не писать ничего на диск вообще, а просто запустить скрипт прямо в памяти через PowerShell. Антивирус такое не видел и молчал.
AMSI (Antimalware Scan Interface) появился в Windows 10 как ответ на волну атак через PowerShell. До него скрипты выполнялись вслепую, а антивирус видел файл на диске, но не то, что реально крутилось в памяти.
Как устроена цепочка 🧛
При запуске PowerShell, JScript или VBScript Windows автоматически загружает amsi.dll в процесс. Каждый блок кода перед исполнением прогоняется через функцию AmsiScanBuffer(). Провайдер Defender или сторонний AV получает содержимое, сканирует и возвращает вердикт. Результат AMSI_RESULT_DETECTED блокирует выполнение.
Звучит надёжно. Но есть один нюанс, который ломает всю идею.
Фундаментальная проблема архитектуры 👨💻
AMSI работает в контексте того же процесса, который хочет выполнить код. Атакующий уже внутри PowerShell и имеет ровно те же права, что и сам процесс. Вот такое архитектурное решение, у которого есть цена.
Патч AmsiScanBuffer: классика жанра 🤯
В памяти процесса находят адрес функции и перезаписывают первые байты так, чтобы она мгновенно возвращала 1 (AMSI_RESULT_CLEAN). После этого весь последующий код исполняется без единой проверки:
[Byte[]] $patch = 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3
$ptr = [Win32]::GetProcAddress($amsi, "AmsiScanBuffer")
[Marshal]::Copy($patch, 0, $ptr, 6)
Три строки и Defender слепой до конца сессии.
Форсирование ошибки инициализации 🙏
Если передать в AmsiScanBuffer невалидный контекст, функция вернёт ошибку. PowerShell трактует ошибку инициализации как "всё чисто" и продолжает выполнение. Этот метод работал годами вплоть до патчей 2023 года, без единой строки шеллкода.
Обфускация против сигнатур 💃
AMSI во многом опирается на строковые сигнатуры. Разбить детектируемую строку на части и собрать в рантайме уже обход:
$a = "Invoke-Mi" + "mikatz"
Примитивно, но работает против базовых правил. Продвинутые техники используют XOR-кодирование, Base64 с динамической сборкой или подстановку через символьные таблицы.
BYOVD, когда всё остальное закрыто 🍩
Если EDR блокирует патчинг пространства пользователя, атакующие уходят глубже. Загружается уязвимый легитимный драйвер (Bring Your Own Vulnerable Driver) и защита отключается прямо из кольца 0. Против этого AMSI бессилен по определению. Он просто не существует на том уровне.
Что реально повышает стоимость атаки 🤱
Constrained Language Mode в PowerShell закрывает доступ к .NET-рефлексии и большинство патчей просто не запустятся. ScriptBlock Logging пишет каждый блок кода до исполнения, даже обфусцированный. ETW фиксирует вызовы на уровне провайдера. Сам факт обращения к amsi.dll через WriteProcessMemory прекрасно видно в нормальном EDR.
AMSI не провалился. Он делает ровно то, для чего создан, он поднимает стоимость атаки и убивает ленивые скрипты с первого слоя. Но пока защита живёт в том же процессе, что и угроза, игра в кошки-мышки не заканчивается.
И ЧТО? 😇
AMSI, скорее уверенная заплатка, а не серебряная пуля. Ленивые скрипты с первой страницы Google она кладёт без вопросов, и таких в дикой природе большинство. Не будь этого механизма, Blue Team плакал бы заметно чаще.
Но питать иллюзий не стоит, путей обхода задокументировано столько, что под них есть отдельные репозитории и целые разделы в курсах по пентесту.
Подписывайтесь на канал
