Exemplo n.º 1
0
def main():
    parser = argparse.ArgumentParser(description="Freedom Fighting Mode.")
    parser.add_argument("--debug-input", action="store_true", help="Toggle debugging of the user input.")
    parser.add_argument("--debug-output", action="store_true", help="Toggle debugging of the terminal output.")
    parser.add_argument("--stdout", help="Redirect stdout to the target file.")
    args = parser.parse_args()
    context.debug_input = args.debug_input
    context.debug_output = args.debug_output
    context.stdout = open(args.stdout, "wb") if args.stdout is not None else sys.stdout

    # Print the banner
    print(random.choice(BANNERS) + "\n")
    print("FFM enabled. Type !list to see available commands and exit to quit.")

    context.terminal_driver = DefaultInputDriver()
    stdin_fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(stdin_fd)
    old_handler = signal.signal(signal.SIGWINCH, update_window_size)
    tty.setraw(context.stdin)

    context.active_session = Session()
    context.sessions.append(context.active_session)

    update_window_size()  # Set the correct window size in the PTY.

    try:
        while context.active_session and context.active_session.bash.poll() is None:
            try:
                r, w, e = select.select([sys.stdin, context.active_session.master], [], [], 1)
                if sys.stdin in r:
                    typed_char = os.read(sys.stdin.fileno(), 1)
                    try:
                        context.active_session.input_driver.handle_input(typed_char)
                    except RuntimeError as e:
                        os.write(context.stdout.fileno(), b"\r\n%s\r\n" % str(e).encode("UTF-8"))
                elif context.active_session.master in r:
                    read = os.read(context.active_session.master, 2048)
                    if context.debug_output:
                        for c in read:
                            os.write(context.stdout.fileno(), ("%02X " % c).encode("UTF-8"))

                    # Store the last line for future use
                    # Only work on the last line
                    last = read.split(b"\n")[-1]
                    if len(last) < 150 and b"\x07" in last:  # TODO: bug when cat-ing a binary file!
                        # This is motivated by my Debian shell's prompt containing weird \x07 bytes separating
                        # two prompt occurrences.
                        context.active_session.input_driver.last_line = last.split(b"\x07")[-1].decode("UTF-8", errors='ignore')
                    elif re.match(PROMPT_REGEXP, last.decode("UTF-8", errors='ignore'), re.UNICODE):
                        context.active_session.input_driver.last_line = last.decode("UTF-8")
                    else:
                        context.active_session.input_driver.last_line = ''

                    # Pass the output to the output driver for display after applying output processors.
                    (proceed, output) = apply_processors(read, OUTPUT_PROCESSOR_LIST)
                    if proceed:
                        context.active_session.output_driver.handle_bytes(output)
            except select.error as e:
                if "[Errno 4]" in str(e):  # Interrupted system call. May be raised if SIGWINCH is received.
                    continue
                else:
                    raise
            # Pretty printing for unimplemented opcodes: no need for a full trace. Probably remove that in the future.
            except RuntimeError as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                filename = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                print("\r\n%s (%s, line %d)\r" % (str(e), filename, exc_tb.tb_lineno))
                return

        # Bash has finished running
        print("FFM disabled.\r")

    finally:
        termios.tcsetattr(stdin_fd, termios.TCSADRAIN, old_settings)
        signal.signal(signal.SIGWINCH, old_handler)
Exemplo n.º 2
0
Arquivo: ffm.py Projeto: xuacker/FFM
def main():
    parser = argparse.ArgumentParser(description="Freedom Fighting Mode.")
    parser.add_argument("--debug-input",
                        action="store_true",
                        help="Toggle debugging of the user input.")
    parser.add_argument("--debug-output",
                        action="store_true",
                        help="Toggle debugging of the terminal output.")
    parser.add_argument("--config",
                        "-c",
                        help="The harness' configuration file.",
                        default=os.path.join(os.path.dirname(__file__),
                                             "ffm.conf"))
    parser.add_argument("--stdout", help="Redirect stdout to the target file.")
    args = parser.parse_args()
    context.debug_input = args.debug_input
    context.debug_output = args.debug_output
    context.stdout = open(args.stdout,
                          "wb") if args.stdout is not None else sys.stdout

    # Print the banner
    print(random.choice(BANNERS) + "\n")
    print(
        "FFM enabled. Type !list to see available commands and exit to quit.")

    # Check that the configuration file exists and is sane.
    if not os.path.exists(args.config):
        print(
            "Could not find %s. Please provide it with the --config option." %
            args.config)
        return
    context.config = configparser.ConfigParser(allow_no_value=True,
                                               inline_comment_prefixes=("#",
                                                                        ";"))
    context.config.read(args.config)

    context.terminal_driver = DefaultInputDriver()
    stdin_fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(stdin_fd)
    old_handler = signal.signal(signal.SIGWINCH, update_window_size)
    tty.setraw(context.stdin)

    context.active_session = Session()
    context.sessions.append(context.active_session)

    update_window_size()  # Set the correct window size in the PTY.

    try:
        while context.active_session and context.active_session.bash.poll(
        ) is None:
            try:
                r, w, e = select.select(
                    [sys.stdin, context.active_session.master], [], [], 1)
                if sys.stdin in r:
                    typed_char = os.read(sys.stdin.fileno(), 1)
                    try:
                        context.active_session.input_driver.handle_input(
                            typed_char)
                    except RuntimeError as e:
                        os.write(context.stdout.fileno(),
                                 b"\r\n%s\r\n" % str(e).encode("UTF-8"))
                elif context.active_session.master in r:
                    read = os.read(context.active_session.master, 2048)
                    if context.debug_output:
                        for c in read:
                            os.write(context.stdout.fileno(),
                                     ("%02X " % c).encode("UTF-8"))

                    # Store the last line for future use
                    last = read.split(b"\n")[-1]
                    # Debian terminals update the window title with this escape sequence. Ignore it.
                    last = re.sub(b"\x1b]0;.*?\x07", b"", last)
                    # Kali terminals add color to the prompt. Strip it.
                    last = re.sub(b"\x1b\[[0-?]*[ -/]*[@-~]", b"", last)
                    if re.match(PROMPT_REGEXP,
                                last.decode("UTF-8", errors='ignore'),
                                re.UNICODE):
                        # TODO: keep the colors in the saved prompt. This will require all
                        # references of len(last_line) to be updated to ignore escape sequences.
                        context.active_session.input_driver.last_line = last.decode(
                            "UTF-8")
                    else:
                        context.active_session.input_driver.last_line = ''

                    # Pass the output to the output driver for display after applying output processors.
                    (proceed,
                     output) = apply_processors(read, OUTPUT_PROCESSOR_LIST)
                    if proceed:
                        context.active_session.output_driver.handle_bytes(
                            output)
            except select.error as e:
                if "[Errno 4]" in str(
                        e
                ):  # Interrupted system call. May be raised if SIGWINCH is received.
                    continue
                else:
                    raise
            # Pretty printing for unimplemented opcodes: no need for a full trace. Probably remove that in the future.
            except RuntimeError as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                filename = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                print("\r\n%s (%s, line %d)\r" %
                      (str(e), filename, exc_tb.tb_lineno))
                return

        # Bash has finished running
        print("FFM disabled.\r")

    finally:
        termios.tcsetattr(stdin_fd, termios.TCSADRAIN, old_settings)
        signal.signal(signal.SIGWINCH, old_handler)
Exemplo n.º 3
0
    def _state_ground(self, c):
        # Printable character: add it to the buffer and display it.
        if 0x20 <= c < 0x7F:
            self.append(chr(c))
            self.print_character(chr(c))
        # ^A: go to the beginning of the line.
        elif c == 0x01:
            if self.cursor_position != len(self.input_buffer):
                self.go_to_sol()
        # ^C or ^D: forward to the underlying TTY, empty the current buffer.
        elif c == 0x03 or c == 0x04:
            # If the user is connected to a shell with no TTY, ask for confirmation to avoid
            # terminating it.
            if c == 0x03 and self.last_line == "":
                write_str(
                    "\r\nWarning: ^C may terminate the current shell! Please confirm by "
                    "sending it again.\r\n", LogLevel.WARNING)
                self.draw_current_line()
                self.state = self._state_confirm_sigint
            else:
                self.input_buffer = ""
                os.write(context.active_session.master, bytes([c]))
        # ^E: go to the end of the line.
        elif c == 0x05:
            if self.cursor_position != 0:
                self.go_to_eol()
        # TAB: line completion
        elif c == 0x09:
            # Tab completion for the current system.
            self.perform_tab_completion()
            self.state = self._state_tab
        # ^K: clear line starting from the cursor.
        elif c == 0x0B:
            if self.cursor_position > 0:
                write(ansi.ED(0))
                self.input_buffer = self.input_buffer[:-self.cursor_position]
                self.cursor_position = 0
        # ^L: clear screen
        elif c == 0x0C:
            write(ansi.CUP() +
                  ansi.ED(2))  # Put the cursor at the top and delete all.
            self.draw_current_line()
        # Carriage return: validate and send to the PTY.
        elif c == 0x0D:
            # Place the cursor at EOL in order to avoid deleting part of the line with the output.
            if self.cursor_position != 0:
                self.go_to_eol()
            write(b"\r\n")

            # Add the command to the history if it's not empty.
            if self.input_buffer.strip():
                self.history.append(self.input_buffer)
                self.history_cursor = 0

            # Update the log file if there is one:
            misc.logging.log(("%s\r\n" % self.input_buffer).encode('UTF-8'))

            if parse_commands(self.input_buffer):
                # A command has been detected and was executed.
                # Write a new prompt.
                self.input_buffer = ""
                self.draw_current_line()
                misc.logging.log(self.last_line.encode(
                    "UTF-8"))  # Manually write the prompt to the log too.
            else:
                # No command detected: forward the input to the TTY.
                (proceed,
                 command_line) = apply_processors(self.input_buffer,
                                                  INPUT_PROCESSOR_LIST)
                if proceed:  # Ignore the command line if one of the processors returned CANCEL.
                    os.write(context.active_session.master,
                             command_line.encode('UTF-8') + b'\r')
                    self.input_buffer = ""
                else:
                    self.draw_current_line()
            self.cursor_position = 0
        # ^U: clear line up to the cursor.
        elif c == 0x15:
            if self.cursor_position == 0:
                self.clear_line()
                self.input_buffer = ""
                write_str_internal(self.last_line)
            elif self.cursor_position != len(self.input_buffer):
                # Delete the whole line and rewrite the updated one, while keeping track
                # of where the cursor should be placed.
                self.clear_line()
                self.input_buffer = self.input_buffer[-self.cursor_position:]
                self.cursor_position = len(self.input_buffer)
                write_str_internal(self.last_line)
                write(ansi.SC)
                write_str_internal(self.input_buffer)
                write(ansi.RC)
        # ^W: delete the current word.
        elif c == 0x17:
            self.delete_word()
        # Backspace (^H)
        elif c == 0x7F:
            self.backspace()
        elif 0 <= c <= 0x17 or c == 0x19 or 0x1C <= c <= 0x1F:
            # Execute
            raise RuntimeError(
                "Not implemented (to handle here)! (Ground, 0x%02X)" % c)
        # Unicode character.
        elif 0xC2 <= c <= 0xF4:
            self.unicode_buffer = bytearray([c])
            self.state = self._state_unicode_char
        else:
            raise RuntimeError("Not implemented! (Ground, 0x%02X)" % c)