Example #1
0
    def testMultiplePipesWithPid0(self):
        args = pipes.ListNamedPipesFlowArgs()

        pipe_foo = rdf_client.NamedPipe()
        pipe_foo.name = "foo-pipe"
        pipe_foo.client_pid = 0

        pipe_bar = rdf_client.NamedPipe()
        pipe_bar.name = "bar-pipe"
        pipe_bar.server_pid = 0

        proc = rdf_client.Process()
        proc.pid = 0
        proc.exe = r"C:\Windows\system32\notepad.exe"

        results = self._RunListNamedPipesFlow(
            args,
            pipe_results=[pipe_foo, pipe_bar],
            proc_results=[proc],
        )

        self.assertLen(results, 2)
        self.assertEqual(results[0].proc.exe,
                         r"C:\Windows\system32\notepad.exe")
        self.assertEqual(results[1].proc.exe,
                         r"C:\Windows\system32\notepad.exe")
Example #2
0
    def testPipeEndFilterServerNoMatch(self):
        args = pipes.ListNamedPipesFlowArgs()
        args.pipe_end_filter = pipes_pb2.ListNamedPipesFlowArgs.SERVER_END

        pipe = rdf_client.NamedPipe()
        pipe.name = "foo"
        pipe.flags = pipes.PIPE_TYPE_MESSAGE | pipes.PIPE_CLIENT_END

        results = self._RunListNamedPipesFlow(args, pipe_results=[pipe])
        self.assertEmpty(results)
Example #3
0
    def testPipeTypeFilterMessageNoMatch(self):
        args = pipes.ListNamedPipesFlowArgs()
        args.pipe_type_filter = pipes_pb2.ListNamedPipesFlowArgs.MESSAGE_TYPE

        pipe = rdf_client.NamedPipe()
        pipe.name = "foo"
        pipe.flags = pipes.PIPE_TYPE_BYTE | pipes.PIPE_CLIENT_END

        results = self._RunListNamedPipesFlow(args, pipe_results=[pipe])
        self.assertEmpty(results)
Example #4
0
    def testMultiplePipes(self):
        args = pipes.ListNamedPipesFlowArgs()

        pipe_foo = rdf_client.NamedPipe()
        pipe_foo.name = "foo"
        pipe_foo.server_pid = 0xf00

        pipe_baz = rdf_client.NamedPipe()
        pipe_baz.name = "baz"
        pipe_baz.server_pid = 0xb45

        results = self._RunListNamedPipesFlow(
            args,
            pipe_results=[pipe_foo, pipe_baz],
        )
        self.assertLen(results, 2)

        results_by_name = {result.pipe.name: result for result in results}
        self.assertEqual(results_by_name["foo"].pipe.server_pid, 0xf00)
        self.assertEqual(results_by_name["baz"].pipe.server_pid, 0xb45)
Example #5
0
    def testSinglePipe(self):
        args = pipes.ListNamedPipesFlowArgs()

        pipe = rdf_client.NamedPipe()
        pipe.name = "foo"
        pipe.server_pid = 1337

        results = self._RunListNamedPipesFlow(args, pipe_results=[pipe])
        self.assertLen(results, 1)
        self.assertEqual(results[0].pipe.name, "foo")
        self.assertEqual(results[0].pipe.server_pid, 1337)
Example #6
0
    def testPipeEndFilterClientMatch(self):
        args = pipes.ListNamedPipesFlowArgs()
        args.pipe_end_filter = pipes_pb2.ListNamedPipesFlowArgs.CLIENT_END

        pipe = rdf_client.NamedPipe()
        pipe.name = "foo"
        pipe.flags = pipes.PIPE_TYPE_MESSAGE | pipes.PIPE_CLIENT_END

        results = self._RunListNamedPipesFlow(args, pipe_results=[pipe])
        self.assertLen(results, 1)
        self.assertEqual(results[0].pipe.name, "foo")
Example #7
0
    def testPipeTypeFilterByteMatch(self):
        args = pipes.ListNamedPipesFlowArgs()
        args.pipe_type_filter = pipes_pb2.ListNamedPipesFlowArgs.BYTE_TYPE

        pipe = rdf_client.NamedPipe()
        pipe.name = "foo"
        pipe.flags = pipes.PIPE_TYPE_BYTE | pipes.PIPE_CLIENT_END

        results = self._RunListNamedPipesFlow(args, pipe_results=[pipe])
        self.assertLen(results, 1)
        self.assertEqual(results[0].pipe.name, "foo")
Example #8
0
    def testPipeNameRegex(self):
        args = pipes.ListNamedPipesFlowArgs()
        args.pipe_name_regex = "ba."

        pipe_foo = rdf_client.NamedPipe()
        pipe_foo.name = "foo"

        pipe_bar = rdf_client.NamedPipe()
        pipe_bar.name = "bar"

        pipe_baz = rdf_client.NamedPipe()
        pipe_baz.name = "baz"

        results = self._RunListNamedPipesFlow(
            args,
            pipe_results=[pipe_foo, pipe_bar, pipe_baz],
        )
        self.assertLen(results, 2)

        result_names = {result.pipe.name for result in results}
        self.assertIn("bar", result_names)
        self.assertIn("baz", result_names)
Example #9
0
    def testProcExeRegex(self):
        args = pipes.ListNamedPipesFlowArgs()
        args.proc_exe_regex = r"C:\\Windows\\ba.\.exe"

        pipe_foo = rdf_client.NamedPipe()
        pipe_foo.name = "foo"
        pipe_foo.server_pid = 123

        proc_foo = rdf_client.Process()
        proc_foo.pid = 123
        proc_foo.exe = r"C:\Windows\foo.exe"

        pipe_bar = rdf_client.NamedPipe()
        pipe_bar.name = "bar"
        pipe_bar.server_pid = 456

        proc_bar = rdf_client.Process()
        proc_bar.pid = 456
        proc_bar.exe = r"C:\Windows\bar.exe"

        pipe_baz = rdf_client.NamedPipe()
        pipe_baz.name = "baz"
        pipe_baz.server_pid = 789

        proc_baz = rdf_client.Process()
        proc_baz.pid = 789
        proc_baz.exe = r"C:\Windows\baz.exe"

        results = self._RunListNamedPipesFlow(
            args,
            pipe_results=[pipe_foo, pipe_bar, pipe_baz],
            proc_results=[proc_foo, proc_bar, proc_baz],
        )
        self.assertLen(results, 2)

        result_names = {result.pipe.name for result in results}
        self.assertIn("bar", result_names)
        self.assertIn("baz", result_names)
Example #10
0
    def testMultiplePipesWithPids(self):
        args = pipes.ListNamedPipesFlowArgs()

        pipe_foo = rdf_client.NamedPipe()
        pipe_foo.name = "foo-pipe"
        pipe_foo.client_pid = 42

        pipe_bar = rdf_client.NamedPipe()
        pipe_bar.name = "bar-pipe"
        pipe_bar.server_pid = 1337

        pipe_baz = rdf_client.NamedPipe()
        pipe_baz.name = "baz-pipe"
        pipe_baz.server_pid = 108

        proc_foo = rdf_client.Process()
        proc_foo.exe = r"C:\Temp\foo.exe"
        proc_foo.pid = 42

        proc_baz = rdf_client.Process()
        proc_baz.exe = r"C:\Temp\baz.exe"
        proc_baz.pid = 108

        results = self._RunListNamedPipesFlow(
            args,
            pipe_results=[pipe_foo, pipe_bar, pipe_baz],
            proc_results=[proc_foo, proc_baz],
        )
        self.assertLen(results, 3)

        results_by_name = {result.pipe.name: result for result in results}
        self.assertEqual(results_by_name["foo-pipe"].proc.exe,
                         r"C:\Temp\foo.exe")
        self.assertEqual(results_by_name["baz-pipe"].proc.exe,
                         r"C:\Temp\baz.exe")
        self.assertEmpty(results_by_name["bar-pipe"].proc.exe)
Example #11
0
    def testSinglePipeWithClientPid(self):
        args = pipes.ListNamedPipesFlowArgs()

        pipe = rdf_client.NamedPipe()
        pipe.name = "foo"
        pipe.client_pid = 1337

        proc = rdf_client.Process()
        proc.pid = 1337
        proc.exe = r"C:\Windows\foo.exe"

        results = self._RunListNamedPipesFlow(
            args,
            pipe_results=[pipe],
            proc_results=[proc],
        )

        self.assertLen(results, 1)
        self.assertEqual(results[0].pipe.name, "foo")
        self.assertEqual(results[0].proc.exe, r"C:\Windows\foo.exe")
Example #12
0
    def testSinglePipeWithNoMatchingPid(self):
        args = pipes.ListNamedPipesFlowArgs()

        pipe = rdf_client.NamedPipe()
        pipe.name = "foo"
        pipe.server_pid = 1

        proc_bar = rdf_client.Process()
        proc_bar.pid = 2
        proc_bar.exe = r"C:\Windows\bar.exe"

        proc_baz = rdf_client.Process()
        proc_baz.pid = 3
        proc_baz.exe = r"C:\Windows\baz.exe"

        results = self._RunListNamedPipesFlow(
            args,
            pipe_results=[pipe],
            proc_results=[proc_bar, proc_baz],
        )

        self.assertLen(results, 1)
        self.assertEqual(results[0].pipe.name, "foo")
        self.assertEmpty(results[0].proc.exe)
Example #13
0
def ListNamedPipes() -> Iterator[rdf_client.NamedPipe]:
    """Yields all named pipes available in the system."""
    if platform.system() != "Windows":
        raise RuntimeError(f"Unsupported platform: {platform.system()}")

    # pylint: disable=g-import-not-at-top
    # pytype: disable=import-error
    import ctypes
    import ctypes.wintypes
    import win32api
    import win32file
    import win32pipe
    import winerror
    # pytype: enable=import-error
    # pylint: enable=g-import-not-at-top

    # The `GetNamedPipeHandleState` function provided by the `win32pipe` module is
    # broken (calling it results in invalid function exception). Hence, we need to
    # go to a lower level and use raw Windows API calls to get this information.
    #
    # https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-getnamedpipehandlestatew
    # pytype: disable=module-attr
    GetNamedPipeHandleStateW = ctypes.windll.kernel32.GetNamedPipeHandleStateW  # pylint: disable=invalid-name
    # pytype: enable=module-attr
    GetNamedPipeHandleStateW.argtypes = [
        ctypes.wintypes.HANDLE,
        ctypes.wintypes.LPDWORD,
        ctypes.wintypes.LPDWORD,
        ctypes.wintypes.LPDWORD,
        ctypes.wintypes.LPDWORD,
        ctypes.wintypes.LPWSTR,
        ctypes.wintypes.DWORD,
    ]
    GetNamedPipeHandleStateW.restype = ctypes.wintypes.BOOL

    # For some reason the `GetNamedPipeClientComputerName` function does not exist
    # in `win32pipe`. Hence, we implement a low-level wrapper for Windows API for
    # it ourselves.
    #
    # https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-getnamedpipeclientcomputernamew
    # pytype: disable=module-attr
    GetNamedPipeClientComputerNameW = ctypes.windll.kernel32.GetNamedPipeClientComputerNameW  # pylint: disable=invalid-name
    # pytype: enable=module-attr
    GetNamedPipeClientComputerNameW.argtypes = [
        ctypes.wintypes.HANDLE,
        ctypes.wintypes.LPWSTR,
        ctypes.wintypes.ULONG,
    ]
    GetNamedPipeClientComputerNameW.restype = ctypes.wintypes.BOOL

    # https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names
    for name in os.listdir(r"\\.\pipe"):
        pipe = rdf_client.NamedPipe()
        pipe.name = name

        try:
            handle = win32file.CreateFile(f"\\\\.\\pipe\\{name}", 0, 0, None,
                                          win32file.OPEN_EXISTING, 0, None)
        except win32file.error as error:
            # There might be some permission issues. We log the error and skip getting
            # pipe details, but still yield a result with at least the name filled-in.
            logging.error("Cannot open pipe '%s': %s", name, error)
            yield pipe
            continue

        with contextlib.closing(handle):
            try:
                pipe_info = win32pipe.GetNamedPipeInfo(handle)
                flags, in_buffer_size, out_buffer_size, max_instance_count = pipe_info

                pipe.flags = flags
                pipe.in_buffer_size = in_buffer_size
                pipe.out_buffer_size = out_buffer_size
                pipe.max_instance_count = max_instance_count
            except win32pipe.error as error:
                # Getting the information might fail (for whatever reason), but we don't
                # want to fail action execution as other probing calls might succeed.
                logging.error("Failed to get info about pipe '%s': '%s'", name,
                              error)

            try:
                pipe.server_pid = win32pipe.GetNamedPipeServerProcessId(handle)
            except win32pipe.error as error:
                # See similar comment for `GetNamedPipeInfo` for more information.
                message = "Failed to get server pid of pipe '%s': '%s'"
                logging.error(message, name, error)

            try:
                pipe.client_pid = win32pipe.GetNamedPipeClientProcessId(handle)
            except win32pipe.error as error:
                # See similar comment for `GetNamedPipeInfo` for more information.
                message = "Failed to get client pid of pipe '%s': '%s'"
                logging.error(message, name, error)

            cur_instance_count = ctypes.wintypes.DWORD()
            status = GetNamedPipeHandleStateW(
                ctypes.wintypes.HANDLE(int(handle)),
                None,
                ctypes.byref(cur_instance_count),
                None,
                None,
                None,
                0,
            )

            if status == 0:
                # See similar comment for `GetNamedPipeInfo` for more information.
                error = win32api.GetLastError()
                logging.error("Failed to get state of pipe '%s': %s", name,
                              error)
            else:
                pipe.cur_instance_count = cur_instance_count.value

            client_computer_name = (ctypes.wintypes.WCHAR *
                                    _COMPUTER_NAME_MAX_SIZE)()  # pytype: disable=not-callable
            status = GetNamedPipeClientComputerNameW(
                ctypes.wintypes.HANDLE(int(handle)),
                client_computer_name,
                _COMPUTER_NAME_MAX_SIZE,
            )

            if status == 0:
                # See similar comment for `GetNamedPipeInfo` for more information.
                error = win32api.GetLastError()
                # Not being able to get computer name of a local pipe is expected, there
                # is no need to log errors in such cases.
                if error != winerror.ERROR_PIPE_LOCAL:
                    logging.error("Failed to get hostname of pipe '%s': %s",
                                  name, error)
            else:
                pipe.client_computer_name = client_computer_name.value

            yield pipe