以低完整性级别打开命名管道

Ale*_*rin 14 c#

我正在开发一个由两个模块组成的应用程序.这些模块在以下环境中通过命名管道进行通信:

  • Windows 7家庭高级版x64
  • Visual Studio 2008
  • C#/ .Net 3.5

服务器以管理员权限运行(高完整性级别).客户端以低完整性级别运行.为了使客户端可以连接到服务器,我需要以低完整性级别创建管道.我设法只在服务器以中等完整性级别运行时才这样做.

我测试了以下设置:

  1. 服务器:高,客户端:低=>访问被拒绝
  2. server:high,client:medium => access refused
  3. server:high,client:high => OK
  4. server:medium,client:low => OK
  5. server:medium,client:medium => OK
  6. server:low,client:low => OK

设置#4显示创建的命名管道的完整性级别与进程的完整性级别不同,这很好.但是,我感兴趣的设置是第一个.

我有一个样本,可以很容易地测试.如果连接成功,客户端将写入"已连接",服务器将写入"已接收连接".如果连接失败,客户端将写入"失败",服务器将保持"等待"状态.

以下是我执行客户端程序的方法(对于服务器,只需将NamePipeClient替换为NamedPipeServer):

  • 中等诚信水平:
    • 打开命令提示符
    • icacls NamedPipeClient.exe/setintegritylevel Medium

    • NamedPipeClient.exe

  • 低完整性水平:
    • 打开命令提示符
    • icacls NamedPipeClient.exe/setintegritylevel低

    • NamedPipeClient.exe

  • 高完整性水平:
    • 在管理员模式下打开命令提示符
    • icacls NamedPipeClient.exe/setintegritylevel高

    • NamedPipeClient.exe

任何帮助将不胜感激!

服务器代码

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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

客户代码

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Dzm*_*oda 5

在 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

服务器端的设置

   InterProcessSecurity.SetLowIntegrityLevel(pipeServer.SafePipeHandle);
Run Code Online (Sandbox Code Playgroud)


Chr*_*son 4

您在管道上设置强制完整性标签的代码成功实现了这一点。但是,由于您的安全描述符没有定义 DACL,因此您的管道将使用默认的管道创建。

当尝试连接到高完整性服务器创建的管道时,DACL 会导致低完整性客户端失败。

在打开监听器之前,您需要修复服务器中的 DACL。我建议不要在创建管道之前尝试使用 P/Invoke 代码构建完整的描述符(这很难正确执行),而是建议利用 System.IO.Pipes 类在托管代码中将其作为在创建管道之后的单独步骤来完成。管道已创建,如下所示:

    // Fix up the DACL on the pipe before opening the listener instance
    // This won't disturb the SACL containing the mandatory integrity label
    NamedPipeServerStream handleForSecurity = null;
    try
    {
        handleForSecurity = new NamedPipeServerStream("NamedPipe/Test", PipeDirection.InOut, -1, PipeTransmissionMode.Byte, PipeOptions.None, 0, 0, null, System.IO.HandleInheritability.None, PipeAccessRights.ChangePermissions);
        PipeSecurity ps = handleForSecurity.GetAccessControl();
        PipeAccessRule aceClients = new PipeAccessRule(
            new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null), // or some other group defining the allowed clients
            PipeAccessRights.ReadWrite, 
            AccessControlType.Allow);
        PipeAccessRule aceOwner = new PipeAccessRule(
            WindowsIdentity.GetCurrent().Owner,
            PipeAccessRights.FullControl,
            AccessControlType.Allow);
        ps.AddAccessRule(aceClients);
        ps.AddAccessRule(aceOwner);
        handleForSecurity.SetAccessControl(ps);
    }
    finally
    {
        if (null != handleForSecurity) handleForSecurity.Close();
        handleForSecurity = null;
    }
Run Code Online (Sandbox Code Playgroud)

这对我有用,其余代码不变。