NtCreateNamedPipeFile
Crea el extremo servidor de un canal con nombre en el espacio de nombres \Device\NamedPipe.
Prototipo
NTSTATUS NtCreateNamedPipeFile( PHANDLE FileHandle, ULONG DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, ULONG NamedPipeType, ULONG ReadMode, ULONG CompletionMode, ULONG MaximumInstances, ULONG InboundQuota, ULONG OutboundQuota, PLARGE_INTEGER DefaultTimeout );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| FileHandle | PHANDLE | out | Recibe el handle al extremo servidor recién creado del canal con nombre. |
| DesiredAccess | ULONG | in | Máscara de acceso, típicamente GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE. |
| ObjectAttributes | POBJECT_ATTRIBUTES | in | Nombra el canal bajo \Device\NamedPipe (p. ej. \??\pipe\msagent_xx) y aporta el SECURITY_DESCRIPTOR. |
| IoStatusBlock | PIO_STATUS_BLOCK | out | Recibe el NTSTATUS final y el código de información (FILE_CREATED / FILE_OPENED). |
| ShareAccess | ULONG | in | Banderas FILE_SHARE_* que controlan la semántica de apertura concurrente del canal. |
| CreateDisposition | ULONG | in | FILE_CREATE, FILE_OPEN o FILE_OPEN_IF; comportamiento si el nombre ya existe. |
| CreateOptions | ULONG | in | FILE_SYNCHRONOUS_IO_NONALERT y similares — mismo conjunto que NtCreateFile. |
| NamedPipeType | ULONG | in | FILE_PIPE_BYTE_STREAM_TYPE o FILE_PIPE_MESSAGE_TYPE — formato de transporte. |
| ReadMode | ULONG | in | FILE_PIPE_BYTE_STREAM_MODE o FILE_PIPE_MESSAGE_MODE para las lecturas. |
| CompletionMode | ULONG | in | FILE_PIPE_QUEUE_OPERATION (bloqueante) o FILE_PIPE_COMPLETE_OPERATION (retorno inmediato). |
| MaximumInstances | ULONG | in | Número máximo de instancias servidoras concurrentes para este nombre; PIPE_UNLIMITED_INSTANCES = 0xFF. |
| InboundQuota | ULONG | in | Tamaño del búfer cliente→servidor, en bytes. |
| OutboundQuota | ULONG | in | Tamaño del búfer servidor→cliente, en bytes. |
| DefaultTimeout | PLARGE_INTEGER | in | Tiempo de espera por defecto para operaciones bloqueantes (unidades de 100 ns, negativo = relativo). NULL = 50 ms. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0xA8 | win10-1507 |
| Win10 1607 | 0xAA | win10-1607 |
| Win10 1703 | 0xAD | win10-1703 |
| Win10 1709 | 0xAE | win10-1709 |
| Win10 1803 | 0xAF | win10-1803 |
| Win10 1809 | 0xAF | win10-1809 |
| Win10 1903 | 0xB0 | win10-1903 |
| Win10 1909 | 0xB0 | win10-1909 |
| Win10 2004 | 0xB4 | win10-2004 |
| Win10 20H2 | 0xB4 | win10-20h2 |
| Win10 21H1 | 0xB4 | win10-21h1 |
| Win10 21H2 | 0xB5 | win10-21h2 |
| Win10 22H2 | 0xB5 | win10-22h2 |
| Win11 21H2 | 0xB8 | win11-21h2 |
| Win11 22H2 | 0xB9 | win11-22h2 |
| Win11 23H2 | 0xB9 | win11-23h2 |
| Win11 24H2 | 0xBB | win11-24h2 |
| Server 2016 | 0xAA | winserver-2016 |
| Server 2019 | 0xAF | winserver-2019 |
| Server 2022 | 0xB7 | winserver-2022 |
| Server 2025 | 0xBB | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 BB 00 00 00 mov eax, 0xBB F6 04 25 08 03 FE 7F 01 test byte ptr [0x7FFE0308], 1 75 03 jne short +3 0F 05 syscall C3 ret CD 2E int 2Eh C3 ret
Notas no documentadas
`NtCreateNamedPipeFile` es la mayor Native API por número de parámetros (14) y la base de `CreateNamedPipeW`. Los nombres de pipe viven bajo `\Device\NamedPipe\`; la forma user-mode es `\\.\pipe\<nombre>` o, remoto, `\\<host>\pipe\<nombre>`. Las aperturas remotas viajan por SMB y dependen del firewall/NetBIOS — por eso el beacon SMB de Cobalt Strike escucha en pipe en vez de en un socket TCP. El SSN cambia cada dos o tres feature updates (`0xA8` en Win10 1507 → `0xBB` en Win11 24H2), por lo que el shellcode portable lo resuelve dinámicamente.
Uso común por malware
Las named pipes son el canal IPC *de facto* del post-explotación moderno: - **Beacon SMB Cobalt Strike**: beacons pares se conectan a través de un pipe servidor (por defecto `\\.\pipe\msagent_xx`, `\\.\pipe\status_xx`, etc.). El tráfico C2 va encapsulado en el pipe sin tocar el adaptador de red del host de salida. - **Transporte named-pipe Sliver**: la misma idea — comunicación implante↔implante para movimiento lateral sin abrir nuevos puertos TCP. - **Servicios tipo PsExec** crean `\pipe\psexesvc` para el canal de retorno de comandos. - Muchas familias ransomware (Conti, BlackCat) coordinan sus workers de cifrado por una pipe para centralizar el reporte de progreso. El atacante elige un nombre que imita un servicio Microsoft legítimo (`\pipe\lsass`, `\pipe\spoolss`, `\pipe\mojo.*`) para mezclarse con el ruido IPC/navegador.
Oportunidades de detección
Sysmon **Event ID 17 (PipeEvent: Pipe Created)** y **18 (PipeEvent: Pipe Connected)** son las detecciones más informativas para este syscall. Nombres de pipe raros — sufijos aleatorios, nombres GUID, `msagent_*` en un host no objetivo de Cobalt, o aperturas `\pipe\` desde procesos inesperados (notepad.exe, wmiprvse.exe) — son indicadores fuertes de beacon SMB o implante peer-to-peer. El proveedor ETW `Microsoft-Windows-Kernel-File` cubre create/open de FO de pipe. Los EDR también alertan sobre la secuencia `NtCreateNamedPipeFile` seguida de `NtFsControlFile(FSCTL_PIPE_LISTEN)` desde un proceso no servicio.
Ejemplos de syscalls directos
asmx64 direct stub (Win11 24H2)
; Direct syscall stub for NtCreateNamedPipeFile (SSN 0xBB on Win11 24H2)
NtCreateNamedPipeFile PROC
mov r10, rcx ; FileHandle
mov eax, 0BBh ; SSN — version-sensitive, resolve dynamically
syscall
ret
NtCreateNamedPipeFile ENDPcCobalt-Strike-style SMB beacon listener
// Create \\.\pipe\msagent_42 as a message-mode server pipe.
#include <windows.h>
#include <winternl.h>
typedef NTSTATUS (NTAPI *pNtCreateNamedPipeFile)(
PHANDLE, ULONG, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK,
ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, ULONG, PLARGE_INTEGER);
HANDLE OpenBeaconPipe(void) {
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\??\\pipe\\msagent_42");
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL);
IO_STATUS_BLOCK iosb = {0};
LARGE_INTEGER timeout; timeout.QuadPart = -50LL * 10000LL; // 50 ms
HANDLE hPipe = NULL;
pNtCreateNamedPipeFile fn = (pNtCreateNamedPipeFile)GetProcAddress(
GetModuleHandleA("ntdll.dll"), "NtCreateNamedPipeFile");
fn(&hPipe,
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
&oa, &iosb,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT,
1 /* FILE_PIPE_MESSAGE_TYPE */,
1 /* FILE_PIPE_MESSAGE_MODE */,
0 /* FILE_PIPE_QUEUE_OP */,
0xFF /* PIPE_UNLIMITED_INSTANCES */,
0x1000, 0x1000,
&timeout);
return hPipe;
}rustwindows-sys wrapper
// Cargo: windows-sys = "0.59", features = ["Wdk_Storage_FileSystem", "Win32_System_IO"]
use std::ptr::null_mut;
use windows_sys::Wdk::Storage::FileSystem::NtCreateNamedPipeFile;
use windows_sys::Win32::Storage::FileSystem::*;
use windows_sys::Win32::System::IO::IO_STATUS_BLOCK;
use windows_sys::Win32::System::WindowsProgramming::*;
use windows_sys::Wdk::Foundation::OBJECT_ATTRIBUTES;
pub fn create_message_pipe(_name: &str) -> isize {
let mut handle: isize = 0;
let mut iosb: IO_STATUS_BLOCK = unsafe { std::mem::zeroed() };
let timeout: i64 = -50 * 10_000; // 50 ms relative
// ObjectAttributes / UNICODE_STRING construction elided — see ntdll helpers.
let oa: OBJECT_ATTRIBUTES = unsafe { std::mem::zeroed() };
unsafe {
NtCreateNamedPipeFile(
&mut handle,
(GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE) as u32,
&oa, &mut iosb,
(FILE_SHARE_READ | FILE_SHARE_WRITE) as u32,
FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT,
1, 1, 0, 0xFF, 0x1000, 0x1000,
&timeout as *const _ as *mut _,
);
}
handle
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20