Windows命名管道访问控制

时间:2016-11-28 12:55:17

标签: windows ipc named-pipes nonblocking

我的进程(服务器)通过CreateProcess创建子进程(客户端),我在这些进程之间进行IPC。我从匿名管道开始,但很快我发现它不支持重复操作,如here所述。

因此,命名管道是我的第二选择。我的困惑是:如果我创建了一个命名管道,是否可以将此管道的访问权限仅限于之前调用CreateProcess创建的子进程?因此,即使另一个进程获得了管道的名称,它仍然无法读取或写入管道。

我的IPC使用仅限于本地计算机和单一平台(Windows)。

顺便说一句,我可以为这些过程更改两个代码。

2 个答案:

答案 0 :(得分:1)

可以使用lpSecurityAttributes参数显式地为新管道分配ACL。这将允许您确保,如果另一个用户登录,则无法连接到管道。

但是,如果在父进程中创建管道的两端,则渎职的范围很小,因此通常不需要显式设置ACL。打开管道的客户端之后,无论如何都没有其他进程可以连接到管道(如果您希望它们这样做,则必须创建第二个实例),因此只有非常短暂的间隔,在此期间另一个进程可以干扰;即使发生了这种情况,也无法连接客户端,所以你会知道出了什么问题。

换句话说,攻击的范围仅限于拒绝服务,并且由于攻击过程需要在同一台机器上运行,因此只需通过控制CPU就可以实现更有效的拒绝服务。 / p>

请注意:

  • 创建管道时应使用FILE_FLAG_FIRST_PIPE_INSTANCE标志,以确保知道是否存在名称冲突。

  • 出于显而易见的原因,您还应该使用PIPE_REJECT_REMOTE_CLIENTS

  • 命名管道的默认权限不允许其他非管理用户创建新实例,因此在这种情况下,中间人攻击风格不存在风险。

  • 以同一用户或管理用户身份运行的恶意进程可能可能您的连接(无论您是否设置了ACL)但由于任何此类恶意程序也可能将恶意代码直接注入父母和/或孩子,因此无需担心这一点。攻击者已经在the air-tight hatchway的错误一边;锁定窗户对你没有任何帮助。

  • 如果您的进程使用提升的权限运行,您可能在管道上设置ACL。默认ACL可能允许作为相同用户上下文运行的非提升进程连接到中间人。您可以通过设置仅授予管理员完全访问权限的ACL来解决此问题。风险仍然很小,但在这种特殊情况下,深度防御措施可能是恰当的。

  • An anonymous pipe is implemented as a named pipe with a unique name,因此您实际上并没有使用命名管道丢失任何内容。攻击者原则上可以使用匿名管道,就像命名管道一样容易。(编辑:根据RbMm,这不再是真的。)

答案 1 :(得分:-2)

异步(重叠)操作当然完全由匿名管道支持。支持异步操作或不支持 - 仅取决于调用FILE_SYNCHRONOUS_IO_[NO]NALERTZwCreateNamedPipeFile中使用的ZwOpenFile,而不是来自哪个名称(或空)具有管道。 CreatePipe使用FILE_SYNCHRONOUS_IO_NONALERT选项创建管道对 - 只是因为从此api返回的此句柄不能用于异步操作。遗憾的是CreatePipe没有参数来改变这种行为,但我们可以自己完成这项任务

从vista开始,我们可以创建匿名(未命名)和异步管道对,但为此你需要使用ndll api。下一代码几乎是类似的CreatePipe内部代码,除了我创建异步管道对。

NTSTATUS CreatePipeAnonymousPair(PHANDLE phServerPipe, PHANDLE phClientPipe)
{
    HANDLE hFile;

    IO_STATUS_BLOCK iosb;

    static UNICODE_STRING NamedPipe = RTL_CONSTANT_STRING(L"\\Device\\NamedPipe\\");

    OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &NamedPipe, OBJ_CASE_INSENSITIVE };

    NTSTATUS status;

    if (0 <= (status = ZwOpenFile(&hFile, SYNCHRONIZE, &oa, &iosb, FILE_SHARE_VALID_FLAGS, 0)))
    {
        oa.RootDirectory = hFile;

        static LARGE_INTEGER timeout = { 0, MINLONG };
        static UNICODE_STRING empty = {};

        oa.ObjectName = &empty;

        if (0 <= (status = ZwCreateNamedPipeFile(phServerPipe,
            FILE_READ_ATTRIBUTES|FILE_READ_DATA|
            FILE_WRITE_ATTRIBUTES|FILE_WRITE_DATA|
            FILE_CREATE_PIPE_INSTANCE, 
            &oa, &iosb, FILE_SHARE_READ|FILE_SHARE_WRITE,
            FILE_CREATE, 0, FILE_PIPE_BYTE_STREAM_TYPE, FILE_PIPE_BYTE_STREAM_MODE,
            FILE_PIPE_QUEUE_OPERATION, 1, 0, 0, &timeout)))
        {

            oa.RootDirectory = *phServerPipe;
            oa.Attributes = OBJ_CASE_INSENSITIVE|OBJ_INHERIT;

            if (0 > (status = ZwOpenFile(phClientPipe, FILE_READ_ATTRIBUTES|FILE_READ_DATA|
                FILE_WRITE_ATTRIBUTES|FILE_WRITE_DATA, &oa, &iosb, FILE_SHARE_VALID_FLAGS, 0)))
            {
                ZwClose(oa.RootDirectory);
                *phServerPipe = 0;
            }
        }

        ZwClose(hFile);
    }

    return status;
}

请注意,hClientPipe创建为Inherited - 因此可以将其传递给子进程。同样,当您在ConnectNamedPipe中使用hServerPipe时FALSE GetLastError() == ERROR_PIPE_CONNECTED(因为客户端已经连接)/或者如果您将使用FSCTL_PIPE_LISTEN - 您获得{{ 1}} - 这真的不是错误,但是正确的代码