Пример #1
0
    def process(self, cmd, delim=True) -> Tuple[str, str]:
        """ Run a command in the context of the remote host and return the
        output. This is run synchrounously.

            :param cmd: The command to run. Either a string or an argv list.
            :param has_pty: Whether a pty was spawned
        """

        if isinstance(cmd, list):
            cmd = shlex.join(cmd)

        sdelim = util.random_string(10)
        edelim = util.random_string(10)

        if delim:
            command = f" echo; echo {sdelim}; {cmd}; echo {edelim}"
        else:
            command = f" {cmd}"

        # Send the command to the remote host
        self.client.send(command.encode("utf-8") + b"\n")

        if delim:
            # Receive until we get our starting delimeter on a line by itself
            while not self.recvuntil(b"\n").startswith(sdelim.encode("utf-8")):
                pass

        return sdelim, edelim
Пример #2
0
    def enumerate(self, session: "pwncat.manager.Session"):

        query_system_info = """
        function query_sysinfo {
          $os_info = (Get-CimInstance Win32_operatingsystem)
          $hostname = [System.Net.Dns]::GetHostName()

          [PsCustomObject]@{
            HostName = $hostname;
            BuildNumber = $os_info.BuildNumber;
            BuildType = $os_info.BuildType;
            CountryCode = $os_info.CountryCode;
            TimeZone = $os_info.CurrentTimeZone;
            DEP = [PsCustomObject]@{
              Available = $os_info.DataExecutionPrevention_Available;
              Available32 = $os_info.DataExecutionPrevention_32bitApplications;
              Drivers = $os_info.DataExecutionPrevention_Drivers;
              SupportPolicy = $os_info.DataExecutionPrevention_SupportPolicy;
            };
            Debug = $os_info.Debug;
            Description = $os_info.Description;
            InstallDate = $os_info.InstallDate;
            LastBootUpTime = $os_info.LastBootUpTime;
            Name = $os_info.Name;
            Architecture = $os_info.OSArchitecture;
            Language = $os_info.OSLanguage;
            Suite = $os_info.OSProductSuite;
            Type = $os_info.OSType;
            ServicePackMajor = $os_info.ServicePackMajorVersion;
            ServicePackMinor = $os_info.ServicePackMinorVersion;
            Version = $os_info.Version;
          }
        }
        query_sysinfo
        """.replace("query_sysinfo", random_string(8))

        try:
            info = session.platform.powershell(query_system_info)[0]
        except PowershellError as exc:
            raise ModuleFailed(f"failed to load sysinfo function: {exc}")

        yield DistroVersionData(
            self.name,
            info["Name"].split("|")[0],
            info["BuildType"],
            info["BuildNumber"],
            info["Version"],
        )

        yield HostnameData(self.name, info["HostName"])

        yield ArchData(self.name, info["Architecture"])
Пример #3
0
def test_platform_dir_io(session):
    """Test creating a directory and interacting with the contents"""

    # Create a path object representing the new remote directory
    path = session.platform.Path(random_string())

    # Create the directory
    path.mkdir()

    # We construct a new path object to avoid cached stat results
    assert session.platform.Path(str(path)).is_dir()

    # Create a file
    (path / "test.txt").touch()

    assert "test.txt" in [item.name for item in path.iterdir()]
Пример #4
0
    def tempfile(self, mode: str, length: int = None):
        """ Create a temporary file on the remote system and return an open file
        handle to it. This uses `mktemp` on the remote system to create the file
        and then opens it with `PtyHandler.open`. """

        # Reading a new temporary file doesn't make sense
        if "w" not in mode:
            raise ValueError("expected write mode for temporary files")

        mktemp = self.which("mktemp")
        if mktemp is None:
            path = "/tmp/tmp" + util.random_string(8)
        else:
            path = self.run(mktemp).strip().decode("utf-8")

        return self.open(path, mode, length=length)
Пример #5
0
    def subprocess(
        self,
        cmd,
        mode="rb",
        data: bytes = None,
        exit_cmd: str = None,
        no_job=False,
        name: str = None,
    ) -> RemoteBinaryPipe:
        """ Create an asynchronous child on the remote end and return a
        file-like object which can communicate with it's standard output. The 
        remote terminal is placed in raw mode with no-echo first, and the
        command is run on a separate background shell w/ no standard input. The
        output of the command can be retrieved through the returned file-like
        object. You **must** either call `close()` of the pipe, or read until
        eof, or the PTY will not be restored to a normal state.

        If `close()` is called prior to EOF, the remote process will be killed,
        and any remaining output will be flushed prior to resetting the terminal.
        """

        if isinstance(cmd, list):
            cmd = shlex.join(cmd)

        for c in mode:
            if c not in "rwb":
                raise ValueError("mode must only contain 'r', 'w' and 'b'")

        sdelim = util.random_string(10)  # "_PWNCAT_STARTDELIM_"
        edelim = util.random_string(10)  # "_PWNCAT_ENDDELIM_"

        # List of ";" separated commands that will be run
        commands: List[str] = []
        # Clear the prompt, or it will get displayed in our output due to the
        # background task
        commands.append(" export PS1=")
        # Needed to disable job control messages in bash
        commands.append("set +m")
        # This is gross, but it allows us to recieve stderr and stdout, while
        # ignoring the job control start message.
        if "w" not in mode and not no_job:
            commands.append(
                f"{{ echo; echo {sdelim}; {cmd} && echo {edelim} || echo {edelim} & }} 2>/dev/null"
            )
        else:
            # This is dangerous. We are in raw mode, and if the process never
            # ends and doesn't provide a way to exit, then we are stuck.
            commands.append(f"echo; echo {sdelim}; {cmd}; echo {edelim}")
        # Re-enable normal job control in bash
        commands.append("set -m")

        # Join them all into one command
        command = ";".join(commands).encode("utf-8")

        # Enter raw mode w/ no echo on the remote terminal
        # DANGER
        if "b" in mode:
            self.raw(echo=False)

        self.client.sendall(command + b"\n")

        while not self.recvuntil(b"\n").startswith(sdelim.encode("utf-8")):
            continue

        # Send the data if requested
        if callable(data):
            data()
        elif data is not None:
            self.client.sendall(data)

        pipe = RemoteBinaryPipe(self, mode, edelim.encode("utf-8"), True, exit_cmd)
        pipe.name = name

        if "w" in mode:
            wrapped = io.BufferedRWPair(pipe, pipe)
            wrapped.name = pipe.name
            pipe = wrapped
        else:
            pipe = io.BufferedReader(pipe)

        return pipe