I'm working on an application which is made of two modules. These modules communicate through named pipes in the following environment:
The server runs with administrator rights (high integrity level). The client runs in low integrity level. So that the client can connect to the server, I need to create the pipe in low integrity level. I manage to do this only when the server runs in medium integrity level.
I tested the following setups :
Setup #4 shows that the named pipe gets created with different integrity level than the one of the process, which is good. However, the setup I am interested in is the first one.
I have a sample which makes it easy to test. If the connection is successful, the clients writes "Connected" and the server writes "Received connection". If the connection fails, the client writes "Failed" and the server stays on "Waiting".
Here is how I execute the client program (for the server, simply replace NamePipeClient with NamedPipeServer):
icacls NamedPipeClient.exe /setintegritylevel Medium
NamedPipeClient.exe
icacls NamedPipeClient.exe /setintegritylevel Low
NamedPipeClient.exe
icacls NamedPipeClient.exe /setintegritylevel High
NamedPipeClient.exe
Any help will be greatly appreciated!
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32.SafeHandles;
using System.IO.Pipes;
namespace NamedPipeServer
{
class Program
{
static void Main(string[] args)
{
SafePipeHandle handle = LowIntegrityPipeFactory.CreateLowIntegrityNamedPipe("NamedPipe/Test");
NamedPipeServerStream pipeServer = new NamedPipeServerStream(PipeDirection.InOut, true, false, handle);
pipeServer.BeginWaitForConnection(HandleConnection, pipeServer);
Console.WriteLine("Waiting...");
Console.ReadLine();
}
private static void HandleConnection(IAsyncResult ar)
{
Console.WriteLine("Received connection");
}
}
}
LowIntegrityPipeFactory.cs
using System;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.IO.Pipes;
using System.ComponentModel;
using System.IO;
using System.Security.Principal;
using System.Security.AccessControl;
namespace NamedPipeServer
{
static class LowIntegrityPipeFactory
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern SafePipeHandle CreateNamedPipe(string pipeName, int openMode,
int pipeMode, int maxInstances, int outBufferSize, int inBufferSize, int defaultTimeout,
SECURITY_ATTRIBUTES securityAttributes);
[DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = false)]
private static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(
[In] string StringSecurityDescriptor,
[In] uint StringSDRevision,
[Out] out IntPtr SecurityDescriptor,
[Out] out int SecurityDescriptorSize
);
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
private const string LOW_INTEGRITY_SSL_SACL = "S:(ML;;NW;;;LW)";
public static SafePipeHandle CreateLowIntegrityNamedPipe(string pipeName)
{
// convert the security descriptor
IntPtr securityDescriptorPtr = IntPtr.Zero;
int securityDescriptorSize = 0;
bool result = ConvertStringSecurityDescriptorToSecurityDescriptor(
LOW_INTEGRITY_SSL_SACL, 1, out securityDescriptorPtr, out securityDescriptorSize);
if (!result)
throw new Win32Exception(Marshal.GetLastWin32Error());
SECURITY_ATTRIBUTES securityAttributes = new SECURITY_ATTRIBUTES();
securityAttributes.nLength = Marshal.SizeOf(securityAttributes);
securityAttributes.bInheritHandle = 1;
securityAttributes.lpSecurityDescriptor = securityDescriptorPtr;
SafePipeHandle handle = CreateNamedPipe(@"\\.\pipe\" + pipeName,
PipeDirection.InOut, 100, PipeTransmissionMode.Byte, PipeOptions.Asynchronous,
0, 0, PipeAccessRights.ReadWrite, securityAttributes);
if (handle.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
return handle;
}
private static SafePipeHandle CreateNamedPipe(string fullPipeName, PipeDirection direction,
int maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options,
int inBufferSize, int outBufferSize, PipeAccessRights rights, SECURITY_ATTRIBUTES secAttrs)
{
int openMode = (int)direction | (int)options;
int pipeMode = 0;
if (maxNumberOfServerInstances == -1)
maxNumberOfServerInstances = 0xff;
SafePipeHandle handle = CreateNamedPipe(fullPipeName, openMode, pipeMode,
maxNumberOfServerInstances, outBufferSize, inBufferSize, 0, secAttrs);
if (handle.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
return handle;
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Pipes;
namespace NamedPipeClient
{
class Program
{
static void Main(string[] args)
{
try
{
var pipeClient = new NamedPipeClientStream(".", "NamedPipe/Test",
PipeDirection.InOut,
PipeOptions.None);
pipeClient.Connect(100);
}
catch (Exception ex)
{
Console.WriteLine("Failed: " + ex);
return;
}
Console.WriteLine("Connected");
Console.ReadLine();
}
}
}
Named pipes are also a networking protocol in the Server Message Block (SMB) suite, based on the use of a special inter-process communication (IPC) share. SMB's IPC can seamlessly and transparently pass the authentication context of the user across to Named Pipes.
Named pipes can be used to provide communication between processes on the same computer or between processes on different computers across a network. If the server service is running, all named pipes are accessible remotely.
A named pipe is a named, one-way or duplex pipe for communication between the pipe server and one or more pipe clients. All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles, and provides a separate conduit for client/server communication.
A pipe is a section of shared memory that processes use for communication. The process that creates a pipe is the pipe server. A process that connects to a pipe is a pipe client. One process writes information to the pipe, then the other process reads the information from the pipe.
Works for me on Windows 7 SP1
public static class NativeMethods
{
public const string LOW_INTEGRITY_SSL_SACL = "S:(ML;;NW;;;LW)";
public static int ERROR_SUCCESS = 0x0;
public const int LABEL_SECURITY_INFORMATION = 0x00000010;
public enum SE_OBJECT_TYPE
{
SE_UNKNOWN_OBJECT_TYPE = 0,
SE_FILE_OBJECT,
SE_SERVICE,
SE_PRINTER,
SE_REGISTRY_KEY,
SE_LMSHARE,
SE_KERNEL_OBJECT,
SE_WINDOW_OBJECT,
SE_DS_OBJECT,
SE_DS_OBJECT_ALL,
SE_PROVIDER_DEFINED_OBJECT,
SE_WMIGUID_OBJECT,
SE_REGISTRY_WOW64_32KEY
}
[DllImport("advapi32.dll", EntryPoint = "ConvertStringSecurityDescriptorToSecurityDescriptorW")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean ConvertStringSecurityDescriptorToSecurityDescriptor(
[MarshalAs(UnmanagedType.LPWStr)] String strSecurityDescriptor,
UInt32 sDRevision,
ref IntPtr securityDescriptor,
ref UInt32 securityDescriptorSize);
[DllImport("kernel32.dll", EntryPoint = "LocalFree")]
public static extern UInt32 LocalFree(IntPtr hMem);
[DllImport("Advapi32.dll", EntryPoint = "SetSecurityInfo")]
public static extern int SetSecurityInfo(SafeHandle hFileMappingObject,
SE_OBJECT_TYPE objectType,
Int32 securityInfo,
IntPtr psidOwner,
IntPtr psidGroup,
IntPtr pDacl,
IntPtr pSacl);
[DllImport("advapi32.dll", EntryPoint = "GetSecurityDescriptorSacl")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean GetSecurityDescriptorSacl(
IntPtr pSecurityDescriptor,
out IntPtr lpbSaclPresent,
out IntPtr pSacl,
out IntPtr lpbSaclDefaulted);
}
public class InterProcessSecurity
{
public static void SetLowIntegrityLevel(SafeHandle hObject)
{
IntPtr pSD = IntPtr.Zero;
IntPtr pSacl;
IntPtr lpbSaclPresent;
IntPtr lpbSaclDefaulted;
uint securityDescriptorSize = 0;
if (NativeMethods.ConvertStringSecurityDescriptorToSecurityDescriptor(NativeMethods.LOW_INTEGRITY_SSL_SACL, 1, ref pSD, ref securityDescriptorSize))
{
if (NativeMethods.GetSecurityDescriptorSacl(pSD, out lpbSaclPresent, out pSacl, out lpbSaclDefaulted))
{
var err = NativeMethods.SetSecurityInfo(hObject,
NativeMethods.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
NativeMethods.LABEL_SECURITY_INFORMATION,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
pSacl);
if (err != NativeMethods.ERROR_SUCCESS)
{
throw new Win32Exception(err);
}
}
NativeMethods.LocalFree(pSD);
}
}
}
Setup of server side
InterProcessSecurity.SetLowIntegrityLevel(pipeServer.SafePipeHandle);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With