Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Named pipe client failed to send data to server: "Stream was not writable"

I created a named pipe server like that \\.\pipe\mypipe in C++ and I am trying to connect it using PowerShell.
I succeed to connect but I want to send it some data and this is where it throws an error in PowerShell:

PS > $pipe = New-Object System.IO.Pipes.NamedPipeClientStream '.','mypipe','In'
PS > $pipe.Connect()
PS > $sw = New-Object System.IO.StreamWriter $pipe
New-Object : Exception calling ".ctor" with "1" argument(s): "Stream was not writable."
At line:1 char:7
+ $sw = New-Object System.IO.StreamWriter $pipe
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand

What does it mean "Stream was not writable" ? I set the permissions on the server to be for Everyone so I don’t think it should be a permissions issue.

My named pipe server:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    DWORD dwRes, dwDisposition;
    PSID pEveryoneSID = NULL, pAdminSID = NULL;
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea[2];
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld =
        SECURITY_WORLD_SID_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    SECURITY_ATTRIBUTES sa;
    LONG lRes;
    HKEY hkSub = NULL;
 
    // Create a well-known SID for the Everyone group.
    if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
        SECURITY_WORLD_RID,
        0, 0, 0, 0, 0, 0, 0,
        &pEveryoneSID))
    {
        ..
    }
 
    // Initialize an EXPLICIT_ACCESS structure for an ACE.
    // The ACE will allow Everyone read access to the key.
    ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS));
    //ea[0].grfAccessPermissions = KEY_READ;
    ea[0].grfAccessPermissions = GENERIC_READ | FILE_WRITE_DATA;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
 
    // Create a new ACL that contains the new ACEs.
    dwRes = SetEntriesInAcl(1, ea, NULL, &pACL);
    if (ERROR_SUCCESS != dwRes)
    {
        ...
    }
 
    // Initialize a security descriptor.  
    pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
        SECURITY_DESCRIPTOR_MIN_LENGTH);
    if (NULL == pSD)
    {
        ...
    }
 
    if (!InitializeSecurityDescriptor(pSD,
        SECURITY_DESCRIPTOR_REVISION))
    {
 
        ...
    }
 
 
    // Add the ACL to the security descriptor. 
    if (!SetSecurityDescriptorDacl(pSD,
        TRUE,     // bDaclPresent flag   
        pACL,
        //NULL,
        FALSE))   // not a default DACL 
    {
 
        ...
    }
 
    SECURITY_ATTRIBUTES SecurityAttrs = {
        sizeof(SECURITY_ATTRIBUTES),
        NULL,                               // assigned access token of calling process
        FALSE
    };
 
    DWORD openMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_OWNER;
    DWORD pipeMode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
 
    std::cout << "[+] Creating pipe server\n";
    for (;;) {
        // create the named pipe
        HANDLE pipe = NULL;
 
        DWORD msgSize = 1024;
        pipe = CreateNamedPipeA(
            "\\\\.\\pipe\\mypipe",
            openMode,
            pipeMode,
            2,              // max instances
            msgSize,        // out buffer size
            msgSize,        // in buffer size
            0,              // timeout. 0 ~= 50ms
            &SecurityAttrs);
 
        if (pipe == INVALID_HANDLE_VALUE) {
            DWORD err = GetLastError();
            std::cout << "[!] Pipe creation failed! " << err << std::endl;
            return err;
        }
 
        // wait for docker to connect to the client
        std::cout << "[+] Waiting for docker to connect\n";
        bool connected = ConnectNamedPipe(pipe, NULL) ? true : (
            GetLastError() == ERROR_PIPE_CONNECTED);
        if (!connected)
            continue;
        std::cout << "[+] Client connected\n";
 
        // read byte from pipe
        char buf[1024];
        DWORD bytesread = 0;
        bool status = ReadFile(
            pipe,
            &buf,
            msgSize,
            &bytesread,
            NULL);
 ...

>Solution :

You got the direction backwards – In means "receive only" (or read-only).

For a bi-directional pipe (which is what PIPE_ACCESS_DUPLEX specifies on the server side), use InOut:

$pipe = [System.IO.Pipes.NamedPipeClientStream]::new('.', 'mypipe', 'InOut')

The resulting stream object should now be both readable and writable

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading