def test_all_passwords_are_hidden(): """Passwords from Bladerunner.options should be hidden in the output. You could use --debug=<int> from the command line to see the unfiltered output of all commands, but passwords will be hidden in formatted output. """ options = { "password": "******", "second_password": "******", "jump_password": "******", } output = ( "shell_prompt> faked\n" "some text which has hunter7 in it, something secret and even a" "shared_password as well, crazy.\n" "shell_prompt>" ) expected = ( "some text which has ******* in it, **************** and even a" "*************** as well, crazy." ) if sys.version_info > (3,): output = bytes(output, "utf-8") assert formatting.format_output(output, "faked", options) == expected
def _send_cmd(self, command, server): """Internal method to send a single command to the pexpect object. Args:: command: the command to send server: the pexpect object to send to Returns: The formatted output of the command as a string, or -1 on timeout """ try: if self.options["unix_line_endings"]: server.send("{0}{1}".format( command, six.unichr(0x000A), )) elif self.options["windows_line_endings"]: server.send("{0}{1}{2}".format( command, six.unichr(0x000D), six.unichr(0x000A), )) else: server.sendline(command) cmd_response = server.expect( self.options["shell_prompts"] + self.options["extra_prompts"] + self.options["passwd_prompts"], self.options["cmd_timeout"], ) if cmd_response >= ( len(self.options["shell_prompts"]) + len(self.options["extra_prompts"]) ) and len(self.options["second_password"] or "") > 0: server.sendline(self.options["second_password"]) server.expect( self.options["shell_prompts"] + self.options["extra_prompts"], self.options["cmd_timeout"], ) except (pexpect.TIMEOUT, pexpect.EOF): return self._try_for_unmatched_prompt( server, server.before, command, ) return format_output(server.before, command, self.options)
def test_format_output(): """Should remove the first, last, and any line with command in it.""" command = "super duper secret command" fake_output = ( "someshell# {0}\nlots of interesting\noutput n stuff\nsomeshell#" ).format(command) if sys.version_info >= (3, 0): fake_output = bytes(fake_output, "utf-8") output = formatting.format_output(fake_output, command) assert output == "lots of interesting\noutput n stuff"
def test_format_output(self): """Should remove the first, last, and any line with command in it.""" command = "super duper secret command" fake_output = [ "someshell# {0}".format(command), "lots of interesting", "output n stuff", "someshell#", ] self.assertEqual( formatting.format_output("\n".join(fake_output), command), "lots of interesting\noutput n stuff", )
def _send_cmd(self, command, server): """Internal method to send a single command to the pexpect object. Args:: command: the command to send server: the pexpect object to send to Returns: The formatted output of the command as a string, or -1 on timeout """ try: if self.options["unix_line_endings"]: server.send("{0}{1}".format( command, six.unichr(0x000A), )) elif self.options["windows_line_endings"]: server.send("{0}{1}{2}".format( command, six.unichr(0x000D), six.unichr(0x000A), )) else: server.sendline(command) cmd_response = server.expect( self.options["shell_prompts"] + self.options["extra_prompts"] + self.options["passwd_prompts"], self.options["cmd_timeout"], ) if cmd_response >= (len(self.options["shell_prompts"]) + len(self.options["extra_prompts"])) and len( self.options["second_password"] or "") > 0: server.sendline(self.options["second_password"]) server.expect( self.options["shell_prompts"] + self.options["extra_prompts"], self.options["cmd_timeout"], ) except (pexpect.TIMEOUT, pexpect.EOF): return self._try_for_unmatched_prompt( server, server.before, command, ) return format_output(server.before, command, self.options)
def test_command_in_second_line(): """Long commands and small terminals can lead to leakage.""" command = ( "super secret and long rediculous command that receives so many " "arguments it spills over into the next line") fake_output = ("someshell# {0}\n{1}\nlots of interesting\noutput n stuff\n" "someshell#").format(command[:50], command[50:]) if sys.version_info >= (3, 0): fake_output = bytes(fake_output, "utf-8") output = formatting.format_output(fake_output, command) assert output == "lots of interesting\noutput n stuff"
def test_command_in_second_line(self): """Long commands and small terminals can lead to leakage.""" command = ( "super secret and long rediculous command that receives so many " "arguments it spills over into the next line" ) fake_output = [ "someshell# {0}\n{1}".format(command[:50], command[50:]), "lots of interesting", "output n stuff", "someshell#", ] self.assertEqual( formatting.format_output("\n".join(fake_output), command), "lots of interesting\noutput n stuff", )
def test_command_in_second_line(): """Long commands and small terminals can lead to leakage.""" command = ( "super secret and long rediculous command that receives so many " "arguments it spills over into the next line" ) fake_output = ( "someshell# {0}\n{1}\nlots of interesting\noutput n stuff\n" "someshell#" ).format(command[:50], command[50:]) if sys.version_info >= (3, 0): fake_output = bytes(fake_output, "utf-8") output = formatting.format_output(fake_output, command) assert output == "lots of interesting\noutput n stuff"
def test_all_passwords_are_hidden(): """Passwords from Bladerunner.options should be hidden in the output. You could use --debug=<int> from the command line to see the unfiltered output of all commands, but passwords will be hidden in formatted output. """ options = { "password": "******", "second_password": "******", "jump_password": "******", } output = ("shell_prompt> faked\n" "some text which has hunter7 in it, something secret and even a" "shared_password as well, crazy.\n" "shell_prompt>") expected = ( "some text which has ******* in it, **************** and even a" "*************** as well, crazy.") if sys.version_info > (3, ): output = bytes(output, "utf-8") assert formatting.format_output(output, "faked", options) == expected
def _try_for_unmatched_prompt(self, server, output, command, _from_login=False, _attempts_left=3): """On command timeout, send newlines to guess the missing shell prompt. Args: server: the sshc object output: the sshc.before after issuing command before the timeout command: the command issued that caused the initial timeout _from_login: if this is called from the login method, return the (connection, code) tuple, or return formatted_output() _attempts_left: internal integer to iterate over this function with Returns: format_output if it can find a new prompt, or -1 on error """ # prompt is usually in the last 30 chars of the last line of output # do /not/ format_line the prompt, it could contain special characters try: new_prompt = output.splitlines()[-1][-30:] except IndexError: new_prompt = "" if isinstance(new_prompt, bytes): new_prompt = codecs.decode(new_prompt, DEFAULT_ENCODING) # escape regex characters replacements = ["\\", "/", ")", "(", "[", "]", "{", "}", " ", "$", "?", ">", "<", "^", ".", "*"] for char in replacements: new_prompt = new_prompt.replace(char, "\{0}".format(char)) if new_prompt and new_prompt not in self.options["shell_prompts"]: self.options["shell_prompts"].append(new_prompt) try: server.sendline() server.expect( self.options["shell_prompts"] + self.options["extra_prompts"], 2, ) except (pexpect.TIMEOUT, pexpect.EOF): if _attempts_left: return self._try_for_unmatched_prompt( server, server.before, command, _from_login=_from_login, _attempts_left=(_attempts_left - 1), ) else: self._push_expect_forward(server) if _from_login: return (server, 1) else: return format_output(output, command, self.options) self.send_interrupt(server) if _from_login: # if we get here, we tried to guess the prompt by sending enter 3 # times, but still didn't return to that same shell. Something odd # is likely happening on the device that needs manual inspection return (None, -6) else: return -1
def _try_for_unmatched_prompt(self, server, output, command, _from_login=False, _attempts_left=3): """On command timeout, send newlines to guess the missing shell prompt. Args: server: the sshc object output: the sshc.before after issuing command before the timeout command: the command issued that caused the initial timeout _from_login: if this is called from the login method, return the (connection, code) tuple, or return formatted_output() _attempts_left: internal integer to iterate over this function with Returns: format_output if it can find a new prompt, or -1 on error """ # do /not/ format_line the prompt, it could contain special characters try: new_prompt = output.splitlines()[-1] except IndexError: new_prompt = "" if isinstance(new_prompt, bytes): new_prompt = codecs.decode(new_prompt, DEFAULT_ENCODING) # escape regex characters replacements = [ "\\", "/", ")", "(", "[", "]", "{", "}", " ", "$", "?", ">", "<", "^", ".", "*" ] for char in replacements: new_prompt = new_prompt.replace(char, "\{0}".format(char)) if new_prompt and new_prompt not in self.options["shell_prompts"]: self.options["shell_prompts"].append(new_prompt) try: server.sendline() server.expect( self.options["shell_prompts"] + self.options["extra_prompts"], 2, ) except (pexpect.TIMEOUT, pexpect.EOF): if _attempts_left: return self._try_for_unmatched_prompt( server, server.before, command, _from_login=_from_login, _attempts_left=(_attempts_left - 1), ) except OSError: # we've lost the underlying connection return -1 else: self._push_expect_forward(server) if _from_login: return (server, 1) else: return format_output(output, command, self.options) self.send_interrupt(server) if _from_login: # if we get here, we tried to guess the prompt by sending enter 3 # times, but still didn't return to that same shell. Something odd # is likely happening on the device that needs manual inspection return (None, -6) else: return -1