【发布时间】:2010-07-19 15:17:04
【问题描述】:
我正在开发一个由两个模块组成的应用程序。这些模块在以下环境中通过命名管道进行通信:
- Windows 7 家庭高级版 x64
- Visual Studio 2008
- C#/.Net 3.5
服务器以管理员权限运行(高完整性级别)。客户端以低完整性级别运行。为了使客户端可以连接到服务器,我需要创建低完整性级别的管道。只有当服务器以中等完整性级别运行时,我才能做到这一点。
我测试了以下设置:
- 服务器:高,客户端:低 => 访问被拒绝
- 服务器:高,客户端:中 => 访问被拒绝
- 服务器:高,客户端:高 => 好的
- 服务器:中,客户端:低 => 好的
- 服务器:中等,客户端:中等 => 好的
- 服务器:低,客户端:低 => 好的
设置 #4 显示命名管道的创建具有与进程之一不同的完整性级别,这很好。但是,我感兴趣的设置是第一个。
我有一个易于测试的样本。如果连接成功,客户端会写入“已连接”,服务器会写入“已接收连接”。如果连接失败,客户端写入“Failed”,服务器保持“Waiting”状态。
这是我执行客户端程序的方式(对于服务器,只需将 NamePipeClient 替换为 NamedPipeServer):
- 中等完整性等级:
- 打开命令提示符
icacls NamedPipeClient.exe /setintegritylevel 中
NamedPipeClient.exe
- 低完整性级别:
- 打开命令提示符
icacls NamedPipeClient.exe /setintegritylevel 低
NamedPipeClient.exe
- 高完整性级别:
- 在管理员模式下打开命令提示符
icacls NamedPipeClient.exe /setintegritylevel 高
NamedPipeClient.exe
任何帮助将不胜感激!
服务器代码
程序.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;
}
}
}
客户端代码
程序.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();
}
}
}
【问题讨论】:
-
问题可能出在“S:(ML;;NW;;;LW)”的 LOW_INTEGRITY_SSL_SACL 字符串中。 NW“表示阻止较低完整性级别的进程写入较高完整性级别的对象(SDDL_NO_WRITE_UP)。”删除 NW 可能会解决您的问题。
-
你解决问题了吗?我尝试了几种解决方案,但在完全禁用 UAC 的 Windows 7 SP1 Enterprise 64 位上,Low 管道无论如何都无法访问安全 SID 较低的 Medium 管道。
-
@DzmitryLahoda:不,我没能解决它。我不得不以不同的方式进行操作,并以中等完整性级别运行服务器。这实际上是一种更安全的方法,因为最终没有真正需要以管理员模式运行服务器。
-
经过几天的黑客攻击stackoverflow.com/questions/3282365/…,我设法解决了类似的问题
-
请注意,Windows XP 不支持完整性级别。因此,例如对 ConvertStringSecurityDescriptorToSecurityDescriptor() 的调用将失败,Windows 代码为 1804(数据类型不正确)。 - 不明显。如果您在 Windows XP 上运行代码,希望这可以为您节省一两分钟。
标签: c#